// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Use the <code>chrome.usb</code> API to interact with connected USB
// devices. This API provides access to USB operations from within the context
// of an app. Using this API, apps can function as drivers for hardware devices.
namespace usb {

  // Direction, Recipient, RequestType, and TransferType all map to their
  // namesakes within the USB specification.
  enum Direction {in, out};
  enum Recipient {device, _interface, endpoint, other};
  enum RequestType {standard, class, vendor, reserved};
  enum TransferType {control, interrupt, isochronous, bulk};

  // For isochronous mode, SynchronizationType and UsageType map to their
  // namesakes within the USB specification.
  enum SynchronizationType {asynchronous, adaptive, synchronous};
  enum UsageType {data, feedback, explicitFeedback};

  // Returned by |getDevices| to identify a connected USB device.
  dictionary Device {
    // The id of the USB device. It remains unchanged until the device is
    // unplugged.
    long device;
    long vendorId;
    long productId;
  };

  // Returned by |openDevice| to be used for USB communication.
  // Every time a device is opened, a new connection handle is created.
  //
  // A connection handle represents the underlying data structure that contains
  // all the data we need to communicate with a USB device, including the status
  // of interfaces, the pending transfers, the descriptors, and etc. A connectin
  // handle id is different from a USB device id.
  //
  // All connection handles can work together if the device allows it.
  // The connection handle will be automatically closed when the app is reloaded
  // or suspended.
  //
  // When a connection handle is closed, all the interfaces it claimed will be
  // released and all the transfers in progress will be canceled immediately.
  dictionary ConnectionHandle {
    // The id of the USB connection handle.
    long handle;
    long vendorId;
    long productId;
  };

  dictionary EndpointDescriptor {
    long address;
    TransferType type;
    Direction direction;
    long maximumPacketSize;

    // Used for isochronous mode.
    SynchronizationType? synchronization;
    UsageType? usage;

    // If this is an interrupt endpoint, this will be 1-255.
    long? pollingInterval;
  };

  dictionary InterfaceDescriptor {
    long interfaceNumber;
    long alternateSetting;
    long interfaceClass;
    long interfaceSubclass;
    long interfaceProtocol;
    DOMString? description;
    EndpointDescriptor[] endpoints;
  };

  // ControlTransferInfo represents that parameters to a single USB control
  // transfer.
  dictionary ControlTransferInfo {
    // The direction of this transfer.
    Direction direction;

    // The intended recipient for this transfer.
    Recipient recipient;

    // The type of this request.
    RequestType requestType;

    long request;
    long value;
    long index;

    // If this transfer is an input transfer, then this field must be set to
    // indicate the expected data length. If this is an output transfer, then
    // this field is ignored.
    long? length;

    // The data payload carried by this transfer. If this is an output transfer
    // then this field must be set.
    ArrayBuffer? data;
  };

  // GenericTransferInfo is used by both bulk and interrupt transfers to
  // specify the parameters of the transfer.
  dictionary GenericTransferInfo {
    // The direction of this transfer.
    Direction direction;

    long endpoint;

    // If this is an input transfer then this field indicates the size of the
    // input buffer. If this is an output transfer then this field is ignored.
    long? length;

    // If this is an output transfer then this field must be populated.
    // Otherwise, it will be ignored.
    ArrayBuffer? data;
  };

  // IsochronousTransferInfo describes a single multi-packet isochronous
  // transfer.
  dictionary IsochronousTransferInfo {
    // All of the normal transfer parameters are encapsulated in the
    // transferInfo parameters. Note that the data specified in this parameter
    // block is split along packetLength boundaries to form the individual
    // packets of the transfer.
    GenericTransferInfo transferInfo;

    // The total number of packets in this transfer.
    long packets;

    // The length of each of the packets in this transfer.
    long packetLength;
  };

  dictionary TransferResultInfo {
    // A value of 0 indicates that the transfer was a success. Other values
    // indicate failure.
    long? resultCode;

    // If the transfer was an input transfer then this field will contain all
    // of the input data requested.
    ArrayBuffer? data;
  };

  // Describes the properties of devices which are found via |getDevices|.
  dictionary EnumerateDevicesOptions {
    long vendorId;
    long productId;
  };
  
  // Describes the properties of devices which are found via |findDevices|.
  dictionary EnumerateDevicesAndRequestAccessOptions {
    long vendorId;
    long productId;
    // The interface id to request access against.
    // Only available on ChromeOS. It has no effect on other platforms.
    long? interfaceId;
  };

  callback VoidCallback = void ();
  callback GetDevicesCallback = void (Device[] devices);
  callback RequestAccessCallback = void (boolean sucess);
  callback OpenDeviceCallback = void (ConnectionHandle handle);
  callback FindDevicesCallback = void (ConnectionHandle[] handles);
  callback ListInterfacesCallback = void (InterfaceDescriptor[] descriptors);
  callback CloseDeviceCallback = void ();
  callback TransferCallback = void (TransferResultInfo info);
  callback ResetDeviceCallback = void(boolean result);

  interface Functions {
    // Lists USB devices specified by vendorId/productId/interfaceId tuple.
    // |options|: The properties to search for on target devices.
    // |callback|: Invoked with a list of |Device|s on complete.
    static void getDevices(EnumerateDevicesOptions options,
                           GetDevicesCallback callback);

    // This method is ChromeOS specific. Calling this method on other platforms
    // will fail.
    // Requests access from the permission broker to an OS claimed device if the
    // given interface on the device is not claimed.
    //
    // |device|: The device to request access to.
    // |interfaceId|: 
    static void requestAccess(Device device,
                              long interfaceId,
                              RequestAccessCallback callback);

    // Opens a USB device returned by |getDevices|.
    // |device|: The device to open.
    // |callback|: Invoked with the created ConnectionHandle on complete.
    static void openDevice(Device device, OpenDeviceCallback callback);

    // Finds USB devices specified by the vendorId/productId/interfaceId tuple
    // and, if permissions allow, opens them for use.
    //
    // On Chrome OS, you can specify the interfaceId. In that case the method
    // will request access from permission broker in the same way as in
    // |requestUsbAcess|.
    //
    // If the access request is rejected, or the device is failed to be opened,
    // its connection handle will not be created or returned.
    //
    // Calling this method is equivalent to calling |getDevices| followed by
    // a series of |requestAccess| (if it is on ChromeOs) and |openDevice|
    // calls, and returning all the successfully opened connection handles.
    //
    // |options|: The properties to search for on target devices.
    // |callback|: Invoked with the opened ConnectionHandle on complete.
    static void findDevices(EnumerateDevicesAndRequestAccessOptions options,
                            FindDevicesCallback callback);

    // Closes a connection handle. Invoking operations on a device after it
    // has been closed is a safe operation, but causes no action to be taken.
    // |handle|: The connection handle to close.
    // |callback|: The callback to invoke once the device is closed.
    static void closeDevice(ConnectionHandle handle,
                            optional CloseDeviceCallback callback);

    // Lists all the interfaces on the USB device.
    // |handle|: The device from which the interfaces should be listed.
    // |callback|: The callback to invoke when the interfaces are enumerated.
    static void listInterfaces(ConnectionHandle handle,
                               ListInterfacesCallback callback);

    // Claims an interface on the specified USB device.
    // Before you can transfer data with endpoints, you must claim their parent
    // interfaces. Only one connection handle on the same host can claim each
    // interface. If the interface is already claimed, this call will fail.
    //
    // You shall call releaseInterface when the interface is not needed anymore.
    //
    // |handle|: The device on which the interface is to be claimed.
    // |interface|: The interface number to be claimed.
    // |callback|: The callback to invoke once the interface is claimed.
    static void claimInterface(ConnectionHandle handle, long interfaceNumber,
                               VoidCallback callback);

    // Releases a claim to an interface on the provided device.
    // |handle|: The device on which the interface is to be released.
    // |interface|: The interface number to be released.
    // |callback|: The callback to invoke once the interface is released.
    static void releaseInterface(ConnectionHandle handle, long interfaceNumber,
                                 VoidCallback callback);

    // Selects an alternate setting on a previously claimed interface on a
    // device.
    // |handle|: The device on which the interface settings are to be set.
    // |interface|: The interface number to be set.
    // |alternateSetting|: The alternate setting to set.
    // |callback|: The callback to invoke once the interface setting is set.
    static void setInterfaceAlternateSetting(ConnectionHandle handle,
                                             long interfaceNumber,
                                             long alternateSetting,
                                             VoidCallback callback);

    // Performs a control transfer on the specified device. See the
    // ControlTransferInfo structure for the parameters required to make a
    // transfer.
    //
    // Conceptually control transfer talks to the device itself. You do not need
    // to claim interface 0 to perform a control transfer.
    //
    // |handle|: A connection handle to make the transfer on.
    // |transferInfo|: The parameters to the transfer. See ControlTransferInfo.
    // |callback|: Invoked once the transfer has completed.
    static void controlTransfer(ConnectionHandle handle,
                                ControlTransferInfo transferInfo,
                                TransferCallback callback);

    // Performs a bulk transfer on the specified device.
    // |handle|: A connection handle to make the transfer on.
    // |transferInfo|: The parameters to the transfer. See GenericTransferInfo.
    // |callback|: Invoked once the transfer has completed.
    static void bulkTransfer(ConnectionHandle handle,
                             GenericTransferInfo transferInfo,
                             TransferCallback callback);

    // Performs an interrupt transfer on the specified device.
    // |handle|: A connection handle to make the transfer on.
    // |transferInfo|: The parameters to the transfer. See GenericTransferInfo.
    // |callback|: Invoked once the transfer has completed.
    static void interruptTransfer(ConnectionHandle handle,
                                  GenericTransferInfo transferInfo,
                                  TransferCallback callback);

    // Performs an isochronous transfer on the specific device.
    // |handle|: A connection handle to make the transfer on.
    // |transferInfo|: The parameters to the transfer. See
    // IsochronousTransferInfo.
    // |callback|: Invoked once the transfer has been completed.
    static void isochronousTransfer(ConnectionHandle handle,
                                    IsochronousTransferInfo transferInfo,
                                    TransferCallback callback);

    // Tries to reset the USB device and restores it to the previous status.
    // If the reset fails, the given connection handle will be closed and the 
    // USB device will appear to be disconnected then reconnected. 
    // In that case you must call |getDevices| or |findDevices| again to acquire
    // the device.
    //
    // |handle|: A connection handle to reset.
    // |callback|: Invoked once the device is reset with a boolean indicating
    // whether the reset is completed successfully.
    static void resetDevice(ConnectionHandle handle,
                            ResetDeviceCallback callback);
  };
};