diff --git a/lib/generator/stubs/t.ml b/lib/generator/stubs/t.ml index 15ad279..4f574a6 100644 --- a/lib/generator/stubs/t.ml +++ b/lib/generator/stubs/t.ml @@ -1,5 +1,7 @@ open Ctypes +(** {1 Types} *) + type error = | Number of int (** A positive number *) | Success (** Success (no error) *) @@ -26,6 +28,7 @@ type version = { describe: string; (** For ABI compatibility only *) } +(** Contains only the fields I needed so far *) type device_descriptor = { id_vendor: int; (** Vendor ID. *) id_product: int; (** Product ID.*) @@ -34,6 +37,8 @@ type device_descriptor = { num_configurations: int; } +(** {1 C types} *) + module Types(T:Cstubs.Types.TYPE) = struct let success = T.constant "LIBUSB_SUCCESS" T.int64_t let error_io = T.constant "LIBUSB_ERROR_IO" T.int64_t diff --git a/lib/libusb.mli b/lib/libusb.mli index 1039643..f86855a 100644 --- a/lib/libusb.mli +++ b/lib/libusb.mli @@ -1,8 +1,19 @@ +(** 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. *) + + open Ctypes include module type of T -(** {1 Errors} *) +(** {1 Getting more of {! error}s} *) val string_of_error: error -> string @@ -10,14 +21,20 @@ 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 @@ -29,30 +46,31 @@ 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. *) +(** Should be called after closing all open devices and before your application + terminates. *) val get_version: unit -> version -(** @return the version of the running libusb library *) +(** @return the version of the used C libusb library *) (** {1 Devices enumeration} *) type device -(** A C pointer to a 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. *) + forget to {!Libusb.unref_device} each of them after use (see below). *) val unref_device: device -> unit -(** Decrement the reference count of a device. +(** [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. *) + device shall be destroyed by libusb C library. *) val unref_devices: device list -> unit -(** [unref_device == List.iter unref_device] *) +(** [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] *) @@ -71,9 +89,7 @@ type device_handle (** A opaque type to manipulate opened devices *) val open_device: ?unref:bool -> device -> (device_handle, error) result -(** Opens the device. - - The C libusb library device opening increments the device reference count. +(** 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 @@ -81,18 +97,71 @@ val open_device: ?unref:bool -> device -> (device_handle, error) result {!Libusb.close_device} will be called. *) val close_device: device_handle -> unit -(** Closes the device. This operation decrements the reference counter. *) +(** 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}. -(** {1 Transfers} *) + 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. *) diff --git a/libusb.opam b/libusb.opam index 7e2de92..7c7affd 100644 --- a/libusb.opam +++ b/libusb.opam @@ -1,5 +1,5 @@ name: "extremes" -version: "2018-06-15-1" +version: "2018-06-24-1" maintainer: "Matthieu Dubuget " authors: "Matthieu Dubuget " homepage: "none" @@ -16,3 +16,8 @@ depends: [ "configurator" {build} "ocamlfind" {build} ] + +depexts: [ + [["debian"] ["libusb-1.0-0-dev"]] + [["ubuntu"] ["libusb-1.0-0-dev"]] +]