(** Binding to a tiny part of {{:http://libusb.info} libusb}. *) (** For a more complete binding, have a look at the more complete and more advanced {{:https://github.com/letoh/ocaml-usb} ocaml-usb}. I wrote this alternate binding: - in order to experiment more in depth with {{:https://github.com/ocamllabs/ocaml-ctypes} Ctypes}; - and because I needed something more portable than {{:https://github.com/letoh/ocaml-usb} ocaml-usb}: this one is working on Windows. *) include module type of T (** {1 Getting more of {! error}s} *) val string_of_error: error -> string val description_of_error: error -> string (** {1 Flags} *) (** {2 Request types} *) val request_type_standard: int val request_type_class: int val request_type_vendor: int val request_type_reserved: int (** {2 Endpoint directions} *) val endpoint_direction_in: int val endpoint_direction_out: int (** {2 Recipients} *) val recipient_device: int val recipient_interface: int val recipient_endpoint: int val recipient_other: int (** {1 Initialisation} *) val init_libusb: unit -> (unit, error) result (** This function must be called before calling any other libusb function. *) val exit_libusb: unit -> unit (** Should be called after closing all open devices and before your application terminates. *) val get_version: unit -> version (** @return the version of the used C libusb library *) (** {1 Devices enumeration} *) type device (** Opaque type representing a C pointer to a device *) val get_device_list: unit -> (device list, error) result (** @return a list of C pointers to libusb devices. Each device returned in the list has it's reference counter set to 1. Do not forget to {!Libusb.unref_device} each of them after use (see below). *) val unref_device: device -> unit (** [unref_device d] decrements the reference count of [d]. If the decrement operation causes the reference count to reach zero, the device shall be destroyed by libusb C library. *) val unref_devices: device list -> unit (** [unref_devices l == List.iter unref_device l] *) val is_vendor: int -> device -> bool (** [is_vendor vend d] checks if device [d] vendor id is [vend] *) val is_product: int -> device -> bool (** [is_product prod d] checks if device [d] product id is [prod] *) val filter_devices: (device -> bool) -> device list -> device list (** [filter_devices f dl] filters [dl] devices list using [f]. The devices of [dl] which are not part of the returned list are unreferenced with {!Libusb.unref_device}. *) (** {1 Device opening} *) type device_handle (** A opaque type to manipulate opened devices *) val open_device: ?unref:bool -> device -> (device_handle, error) result (** The C libusb library device opening increments the device reference count. If the operation is successfull, and if [unref] is true (which is it's default value) {!Libusb.open_device} decrements the device reference counter of the device: this allows the device to be destroyed automatically when {!Libusb.close_device} will be called. *) val close_device: device_handle -> unit (** Closes the device. This operation decrements the reference counter. TODO: make the reference counter decrement optionnal? *) val get_device_descriptor: device -> (device_descriptor, error) result val get_string_descriptor: device_handle -> int -> (string, error) result val claim_interface: device_handle -> int -> (unit, error) result (** Claim an interface on a given {! device_handle}. You must claim the interface you wish to use before you can perform I/O on any of its endpoints. It is legal to attempt to claim an already-claimed interface, in which case libusb just returns without doing anything. Claiming of interfaces is a purely logical operation; it does not cause any requests to be sent over the bus. Interface claiming is used to instruct the underlying operating system that your application wishes to take ownership of the interface. This is a non-blocking function. *) val release_interface: device_handle -> int -> (unit, error) result (** Release an interface previously claimed with {! claim_interface}. You should release all claimed interfaces before closing a {!device_handle}. This is a blocking function. A SET_INTERFACE control request will be sent to the device, resetting interface state to the first alternate setting. *) (** {1 Synchronous device I/O} *) val control_transfer: device_handle:device_handle -> request_type:int -> request:int -> value:int -> index:int -> buffer:(char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t -> timeout:int -> unit -> error (** Perform a USB control transfer. @param request_type is a bitfield used to parameter the transfer. It can be constructed with a logical or between constants. By instance, to make a vendor request output, this parameter can be set to [(]{! endpoint_direction_in} [ lor ] {! request_type_vendor} [ lor ] {! recipient_device} [)]. The [value] and [index] fields values should be given in host-endian byte order. TODO: check if something can be done to have the OCaml binding take care of this. *) val bulk_transfer: device_handle:device_handle -> endpoint:int -> buffer:(char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t -> timeout:int -> unit -> (int, error) result (** Perform a USB bulk transfer. The direction of the transfer is inferred from the direction bits of the [endpoint] address. By instance, to write on the [#1] endpoint, [endpoint] should be passed : [(] {! Libusb.endpoint_direction_out} [ lor 1] [)]. For bulk reads, the length of [buffer] indicates the maximum length of data you are expecting to receive. If less data arrives than expected, this function will return that data, so be sure to check the transferred output parameter. You should also check the transferred parameter for bulk writes. Not all of the data may have been written. Also check transferred when dealing with a timeout error code. libusb may have to split your transfer into a number of chunks to satisfy underlying O/S requirements, meaning that the timeout may expire after the first few chunks have completed. libusb is careful not to lose any data that may have been transferred; do not assume that timeout conditions indicate a complete lack of I/O. *)