Difference between revisions of "Hardware driver API"

From sigrok
Jump to navigation Jump to search
m (Fixed typo)
 
(17 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Every plugin is built as a shared library, dynamically loaded by the backend at startup. The plugin must define a structure as follows:
Every driver must define a '''struct sr_dev_driver''' to register it with libsigrok. It is defined as follows:


  #include "sigrok.h"
  struct sr_dev_driver {
    /* Driver-specific */
    char *name;
    char *longname;
    int api_version;
    int (*init) (void);
    int (*cleanup) (void);
    GSList *(*scan) (GSList *options);
    GSList *(*dev_list) (void);
    int (*dev_clear) (void);
   
   
struct device_plugin {
    /* Device-specific */
/* plugin-specific */
    int (*dev_open) (struct sr_dev_inst *sdi);
char *name;
    int (*dev_close) (struct sr_dev_inst *sdi);
int api_version;
    int (*config_get) (int info_id, const void **data,
int (*init) (char *deviceinfo);
            const struct sr_dev_inst *sdi);
void (*cleanup) (void);
    int (*config_set) (const struct sr_dev_inst *sdi, int hwcap,
            const void *value);
    int (*dev_acquisition_start) (const struct sr_dev_inst *sdi,
            void *cb_data);
    int (*dev_acquisition_stop) (struct sr_dev_inst *sdi,
            void *cb_data);
   
   
/* device-specific */
    /* Dynamic */
int (*open) (int device_index);
    void *priv;
void (*close) (int device_index);
char *(*get_device_info) (int device_index, int device_info_id);
int (*get_status) (int device_index);
int *(*get_capabilities) (void);
int (*set_configuration) (int device_index, int capability, char *value);
int (*start_acquisition) (int device_index, gpointer session_device_id);
void (*stop_acquisition) (int device_index, gpointer session_device_id);
  };
  };
#define SIGROK_HARDWARE_PLUGIN  struct device_plugin plugin_info


This structure should be the only symbol imported into the libsigrok namespace. The driver's variables thus cannot conflict with the global libsigrok namespace.


This structure is the only symbol imported into the backend namespace. The plugin's variables thus cannot conflict with the global sigrok namespace.
* '''name'''
<blockquote>
A short string describing this driver. It should contain only lowercase a-z, 0-9 and dashes (-). It will be referenced in saved session files.
</blockquote>


* '''name'''
* '''longname'''
<blockquote>
<blockquote>
A freeform string describing the device handled by this plugin.
A longer freeform string describing this driver. It will be shown to the user.
</blockquote>
</blockquote>


Line 36: Line 45:
</blockquote>
</blockquote>


The other members of the structure are pointers to plugin callbacks:
Most of the other members of the structure are pointers to driver callbacks:


* '''init(char *device)'''
* '''init()'''
<blockquote>
<blockquote>
Called when the plugin is initially loading into sigrok, typically at program start. The parameter refers to a device name or special file, whichever is applicable for the plugin. Devices which don't need a supplied device, such as USB devices, can simply ignore this parameter.
Called when the driver is initially loading into libsigrok, typically at program start.
 
<p>Returns SR_OK if successful, SR_ERR otherwise.</p>
The function returns the number of devices found, and 0 if no suitable device was found. If a device was found, any initialization it needs must be performed here; for example, uploading firmware should be done here.
</blockquote>
</blockquote>


* '''cleanup()'''
* '''cleanup()'''
<blockquote>
<blockquote>
Called before the plugin is unloaded. Release any resources the plugin might be holding.
Called before the driver is unloaded. Any resources the driver holds must be released here, such as memory or connectivity library handles.
<p>Returns SR_OK if successful, SR_ERR otherwise.</p>
</blockquote>
</blockquote>


* '''open(int device_index)
* '''scan(GSList *options)'''
<blockquote>
<blockquote>
Open the specified device. The device index starts at 0.
When a frontend wants a driver to scan for devices on the system that it knows about, this function is called. If a device was found, any initialization it needs must be performed here; for example, uploading firmware should be done here.
</blockquote>
 
A driver for USB-connected devices typically doesn't need any help with this: it will find devices known to it by their VendorID and ProductID (VID:PID).
 
However other drivers &mdash; notably those which use a serial port  &mdash; need to be pointed at the device. The GSList <code>options</code> contains instances of this struct:
 
<pre>
struct sr_hwopt {
    int hwopt;
    const void *value;
};
</pre>
 
There are currently two valid <code>hwopt</code> values: '''SR_HWOPT_CONN''', where the associated value contains a string pointing the driver at the resource it needs to connect to. Right now that means a serial port of the form <code>/dev/ttyUSB0</code> or <code>/dev/ttyACM0</code>. The second <code>hwopt</code> is '''SR_HWOPT_SERIALCOMM''', which defines the serial communication parameters for the given port in the form ''&lt;baudrate&gt;/&lt;data bits&gt;&lt;parity&gt;&lt;stop bits&gt;'', for example "9600/8n1" or "600/7o2".
 
For serial port-based drivers, '''SR_HWOPT_CONN''' is always required, and '''SR_HWOPT_SERIALCOMM''' always optional: the driver should know at which bitrate its device(s) can communicate, or probe for it.


* '''close(int device_index)
Any devices found must have a <code>struct sr_dev_inst</code> created, which is added to the driver's known instances -- a GSList stored in the driver context's <code>instances</code> field.
<blockquote>
Close the specified device.
</blockquote>


* '''get_device_info(int device_index, int device_info_id)'''
A copy of the <code>struct sr_dev_inst</code> for every device found in the current invocation of <code>scan()</code> must also be returned in a GSList from the function itself; the frontend is responsible for freeing the list (but will not touch the instances it contains).
<blockquote>
Returns information about the given device. The type of information is given as device_info_id, one of a set of defined constants. The return value must be cast according to the type of information returned:


* DI_IDENTIFIER: string identifying this specific device in the system, in case more than one is connected.
The instances thus returned to the frontend are central to the communication between the driver and the libsigrok frontend: every other callback function has an instance struct as a parameter.
* DI_NUM_PROBES: the number of probes connected to this device (integer).
* DI_SAMPLE_RATES: the samples rates this device supports, as a 0-terminated array of float.
</blockquote>
</blockquote>


* '''get_status(int device_index)'''
* '''dev_list()'''
<blockquote>
<blockquote>
Returns an integer describing the status of the plugin's connection to a device. This may be one of the following:
Called whenever the frontend needs a list of device instances the driver knows about. This should just return the <code>instances</code> field in the driver's context struct.
 
* ST_NOT_FOUND:    The device was not found.
* ST_INITIALIZING:  The device was found, but is still initializing.
* ST_INACTIVE:      The device is live, but not in use.
* ST_ACTIVE:        The device is currently in use.
</blockquote>
</blockquote>


* '''get_capabilities()'''
* '''dev_clear()'''<br />
<blockquote>
<blockquote>
This function returns zero-terminated integer array with the plugin's capabilities, in the form of a set of defined constants. Some of these are informative, and some can be used to configure the plugin (or its connected device). The capabilities tables below have an overview of all possible capabilities.
Clear the list of device instances the driver knows about. A frontend may call the <code>scan()</code> function multiple times to add to the driver's list of known devices, for example with a different serial port each time. If the frontend then wants to start over, it needs this function to clear the list.
<p>Returns SR_OK if successful, SR_ERR otherwise.</p>
</blockquote>
</blockquote>


* '''set_configuration(int device_index, int capability, char *value)'''
* '''dev_open(struct sr_dev_inst *sdi)'''<br />
<blockquote>
<blockquote>
This is used to configure the plugin and/or connected device. The capability is one of the constants returned from the get_capabilities() call. The value depends on the parameter that is to be configured.
Open the specified device.
<p>Returns SR_OK if successful, SR_ERR otherwise.</p>
</blockquote>
</blockquote>


* '''start_acquisition(int device_index, gpointer session_device_id)'''
* '''dev_close(struct sr_dev_inst *sdi)'''<br />
<blockquote>
<blockquote>
Start acquisition on the specified device. The session_device_id will be passed along with the data feed of this session, as the first parameter to session bus callbacks.
Close the specified device.
<p>Returns SR_OK if successful, SR_ERR otherwise.</p>
</blockquote>
</blockquote>


* '''stop_acquisition(int device_index, gpointer session_device_id)'''
* '''config_get(int info_id, const void **data, struct sr_dev_inst *sdi)'''
<blockquote>
<blockquote>
Stop acquisition on the specified device. This causes a DF_END packet to be sent to the sesion bus.
Returns information about the driver, or, if '''sdi''' is provided, that device instance. The type of information is given as info_id, one of a set of defined constants. The return value is always a pointer which refers to information specific to the id. Check <code>libsigrok.h</code> for the definitions ('''SR_DI_*''').
</blockquote>
</blockquote>


 
* '''config_set(const struct sr_dev_inst *sdi, int hwcap, const void *value)'''
 
 
== Informative capabilities ==
 
* HWCAP_LOGIC_ANALYZER
<blockquote>
<blockquote>
This plugin supplies a logic analyzer.
This is used to configure the driver and/or connected device. The hwcap parameter is one of the constants returned from calling <code>info_get()</code> with either SR_DI_HWOPTS (driver options) or SR_DI_HWCAPS (device instance options) as the <code>info_id</code>. The value depends on the parameter to be configured.
</blockquote>
</blockquote>


== Configurable capabilities ==
* '''dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)'''
 
* HWCAP_SAMPLERATE
<blockquote>
<blockquote>
The sample rate in Mhz.
Start acquisition on the specified device. The cb_data parameter will be passed along with the data feed of this session, as the first parameter to session bus callbacks.
</blockquote>
</blockquote>
* HWCAP_LIMIT_SECONDS
 
* '''dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data)'''
<blockquote>
<blockquote>
How long the acquisition should last.
Stop acquisition on the specified device. This causes a DF_END packet to be sent to the session bus.
</blockquote>
</blockquote>
* HWCAP_LIMIT_SAMPLES
 
* '''priv'''
<blockquote>
<blockquote>
How many samples to acquire in the session.
This should contain a pointer to a <code>struct drv_context</code>, which is initialized by the <code>init()</code> function.
</blockquote>
</blockquote>
[[Category:APIs]]

Latest revision as of 11:13, 5 August 2014

Every driver must define a struct sr_dev_driver to register it with libsigrok. It is defined as follows:

struct sr_dev_driver {
   /* Driver-specific */
   char *name;
   char *longname;
   int api_version;
   int (*init) (void);
   int (*cleanup) (void);
   GSList *(*scan) (GSList *options);
   GSList *(*dev_list) (void);
   int (*dev_clear) (void);

   /* Device-specific */
   int (*dev_open) (struct sr_dev_inst *sdi);
   int (*dev_close) (struct sr_dev_inst *sdi);
   int (*config_get) (int info_id, const void **data,
           const struct sr_dev_inst *sdi);
   int (*config_set) (const struct sr_dev_inst *sdi, int hwcap,
           const void *value);
   int (*dev_acquisition_start) (const struct sr_dev_inst *sdi,
           void *cb_data);
   int (*dev_acquisition_stop) (struct sr_dev_inst *sdi,
           void *cb_data);

   /* Dynamic */
   void *priv;
};

This structure should be the only symbol imported into the libsigrok namespace. The driver's variables thus cannot conflict with the global libsigrok namespace.

  • name

A short string describing this driver. It should contain only lowercase a-z, 0-9 and dashes (-). It will be referenced in saved session files.

  • longname

A longer freeform string describing this driver. It will be shown to the user.

  • api_version

Currently defined as 1.

Most of the other members of the structure are pointers to driver callbacks:

  • init()

Called when the driver is initially loading into libsigrok, typically at program start.

Returns SR_OK if successful, SR_ERR otherwise.

  • cleanup()

Called before the driver is unloaded. Any resources the driver holds must be released here, such as memory or connectivity library handles.

Returns SR_OK if successful, SR_ERR otherwise.

  • scan(GSList *options)

When a frontend wants a driver to scan for devices on the system that it knows about, this function is called. If a device was found, any initialization it needs must be performed here; for example, uploading firmware should be done here.

A driver for USB-connected devices typically doesn't need any help with this: it will find devices known to it by their VendorID and ProductID (VID:PID).

However other drivers — notably those which use a serial port — need to be pointed at the device. The GSList options contains instances of this struct:

 struct sr_hwopt {
    int hwopt;
    const void *value;
 };

There are currently two valid hwopt values: SR_HWOPT_CONN, where the associated value contains a string pointing the driver at the resource it needs to connect to. Right now that means a serial port of the form /dev/ttyUSB0 or /dev/ttyACM0. The second hwopt is SR_HWOPT_SERIALCOMM, which defines the serial communication parameters for the given port in the form <baudrate>/<data bits><parity><stop bits>, for example "9600/8n1" or "600/7o2".

For serial port-based drivers, SR_HWOPT_CONN is always required, and SR_HWOPT_SERIALCOMM always optional: the driver should know at which bitrate its device(s) can communicate, or probe for it.

Any devices found must have a struct sr_dev_inst created, which is added to the driver's known instances -- a GSList stored in the driver context's instances field.

A copy of the struct sr_dev_inst for every device found in the current invocation of scan() must also be returned in a GSList from the function itself; the frontend is responsible for freeing the list (but will not touch the instances it contains).

The instances thus returned to the frontend are central to the communication between the driver and the libsigrok frontend: every other callback function has an instance struct as a parameter.

  • dev_list()

Called whenever the frontend needs a list of device instances the driver knows about. This should just return the instances field in the driver's context struct.

  • dev_clear()

Clear the list of device instances the driver knows about. A frontend may call the scan() function multiple times to add to the driver's list of known devices, for example with a different serial port each time. If the frontend then wants to start over, it needs this function to clear the list.

Returns SR_OK if successful, SR_ERR otherwise.

  • dev_open(struct sr_dev_inst *sdi)

Open the specified device.

Returns SR_OK if successful, SR_ERR otherwise.

  • dev_close(struct sr_dev_inst *sdi)

Close the specified device.

Returns SR_OK if successful, SR_ERR otherwise.

  • config_get(int info_id, const void **data, struct sr_dev_inst *sdi)

Returns information about the driver, or, if sdi is provided, that device instance. The type of information is given as info_id, one of a set of defined constants. The return value is always a pointer which refers to information specific to the id. Check libsigrok.h for the definitions (SR_DI_*).

  • config_set(const struct sr_dev_inst *sdi, int hwcap, const void *value)

This is used to configure the driver and/or connected device. The hwcap parameter is one of the constants returned from calling info_get() with either SR_DI_HWOPTS (driver options) or SR_DI_HWCAPS (device instance options) as the info_id. The value depends on the parameter to be configured.

  • dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)

Start acquisition on the specified device. The cb_data parameter will be passed along with the data feed of this session, as the first parameter to session bus callbacks.

  • dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data)

Stop acquisition on the specified device. This causes a DF_END packet to be sent to the session bus.

  • priv

This should contain a pointer to a struct drv_context, which is initialized by the init() function.