Skip to content

Device Services C SDK Reference

Introduction

This page provides detail on the API provided by the C SDK. A device service implementation will define a number of callback functions, and a main function which registers these functions with the SDK and uses the SDK lifecycle methods to start the service and shut it down. The implementation may also use some of the helper functions which the SDK provides.

In various places information is passed between the SDK and the DS implementation using the iot_data_t type. This is a holder for data of different types, and its use is described in its own page : Use of iot_data_t

Types

devsdk_service_t

This struct represents a running device service. An instance of it is created by calling devsdk_service_new, and this instance should be passed in subsequent sdk function calls.

devsdk_callbacks

This struct type holds pointers to the various callback functions which the device service implementor needs to define in order to do the device-specific work of the service

devsdk_address_t

This is an alias to void*. Implementations should define their own structure for device addresses and cast devsdk_address_t* to pointers to that structure.

devsdk_resource_attr_t

This is an alias to void*. Implementations should define their own structure for device resource information and cast devsdk_resource_attr_t* to pointers to that structure.

devsdk_protocols

This is an opaque structure which holds protocol properties. The devsdk_protocols_properties function is used to find the properties for a particular protocol.

devsdk_error

This structure is used to pass errors back from the device service startup and shutdown functions

Field Type Content
code uint32_t A numeric code indicating the error. Zero is used for success
reason const char * A string describing the error

An instance of devsdk_error with the code field set to zero should be passed by reference when calling startup and shutdown functions

devsdk_device_t

Specifies a device

Field Type Content
name char* The device's name (for logging purposes)
address devsdk_address_t Address of the device in parsed form

devsdk_resource_t

Specifies a resource on a device

Field Type Content
name char* The resource name (for logging purposes)
attrs devsdk_resource_attr_t Resource attributes in parsed form
type iot_typecode_t* Expected type of values read from or written to the resource

devsdk_commandrequest

Specifies a resource in a get or put request

Field Type Content
resource devsdk_resource_t* The resource definition
mask uint64_t Mask to be applied (put requests only)

devsdk_commandresult

Holds a value which has been read from a resource

Field Type Content
value iot_data_t* The value which has been read
origin uint64_t Timestamp of the value

The timestamp is specified in nanoseconds past the epoch. It should only be set if one is provided by the device itself. Otherwise the timestamp should be left at zero and the SDK will use the current time.

devsdk_device_resources

A list of device resources available on a device

Field Type Content
resname char* Name of the resource
attributes iot_data_t* String-keyed map of the resource attributes
type iot_typecode_t* Type of the data which may be read or written
readable bool Whether this resource is readable
writable bool Whether this resource is writable
next devsdk_device_resources* The next resource in the list, or NULL if this is the last

devsdk_devices

A description of a device or a list of such descriptions

Field Type Content
device devsdk_device_t* The device's name and addressing information
resources devsdk_device_resources* Information on the device's resources
next devsdk_devices* The next device in the list, or NULL if this is the last

Callbacks

Note that each of the callback functions has as its first parameter a void* pointer. This pointer is specified by the implementation when the device service is created, and is passed to all callbacks. It may therefore be used to hold whatever state is required by the implementation.

Required callback functions

devsdk_initialize

This function is called during the service start operation. Its purpose is to supply the implementation with a logger and configuration.

Parameter Type Description
impl void* The context data passed in when the service was created
lc iot_logger_t* A logging client for the device service
config iot_data_t* A string-keyed map containing the configuration specified in the service's "Driver" section

The function should return true to indicate that initialization was successful, or false to abort the service startup - eg if the supplied configuration was invalid or resources were not available

devsdk_create_address

This function should take the protocol properties that were specified for a device, and create an object representing the device's address in a form suitable for subsequent access.

Parameter Type Description
impl void* The context data passed in when the service was created
protocols const devsdk_protocols* The protocol properties for the device
exception iot_data_t** Additional information in the event of an error

If the supplied protocol properties are valid (ie, mandatory elements are supplied and have valid values), the function should return an allocated structure representing the address. Otherwise the function should return NULL, and set *exception to a string (using eg. iot_data_alloc_string) containing an error message.

devsdk_free_address

This function should free a structure that was previously allocated in the devsdk_create_address implementation.

Parameter Type Description
impl void* The context data passed in when the service was created
address devsdk_address_t The object to be freed.

devsdk_create_resource_attr

This function should take the attributes that were specified for a deviceResource, and create an object representing these attributes in a form suitable for subsequent access.

Parameter Type Description
impl void* The context data passed in when the service was created
attributes const iot_data_t* The attributes for the device
exception iot_data_t** Additional information in the event of an error

If the supplied attributes are valid (ie, mandatory elements are supplied and have valid values), the function should return an allocated structure representing the resource within the device. Otherwise the function should return NULL, and set *exception to a string (using eg. iot_data_alloc_string) containing an error message.

devsdk_free_resource_attr

This function should free a structure that was previously allocated in the devsdk_create_resource_attr implementation

Parameter Type Description
impl void* The context data passed in when the service was created
resource devsdk_resource_attr_t The object to be freed

devsdk_handle_get

This function is called when a get (read) request on a deviceResource or deviceCommand is made. In the former case, the request is for a single reading and in the latter, for multiple readings. These readings will be packaged by the SDK into an Event.

Parameter Type Description
impl void* The context data passed in when the service was created
device devsdk_device_t* The name and address of the device to be queried
nreadings uint32_t The number of readings being requested
requests devsdk_commandrequest* Array containing details of the resources to be queried
readings devsdk_commandresult* Array that the function should populate, with results of this request
options iot_data_t* Any options which were specified in this request
exception iot_data_t** Additional information in the event of an error

The readings array will have been allocated in the SDK; the implementation should set the results into readings[0]...readings[nreadings - 1].

Options will be a string-keyed map which contains any options set specifically on this request. In the current implementation these may have been set via query parameters in the URL used to make the request.

The function should return true if all of the requested resources were successfully read. Otherwise, *exception should be allocated with a string value indicating the problem (this will be logged and returned to the caller), and false returned.

devsdk_handle_put

This function is called when a put (write) request on a deviceResource or deviceCommand is made. In the former case, the request is for a single resource and in the latter, for multiple resources.

Parameter Type Description
impl void* The context data passed in when the service was created
device devsdk_device_t* The name and address of the device to be written to
nreadings uint32_t The number of resources to be written
requests devsdk_commandrequest* Array containing details of the resources to be written
values iot_data_t*[] Array of values to be written
options iot_data_t* Any options which were specified in this request
exception iot_data_t** Additional information in the event of an error

If the mask field in an element of the request array is nonzero, the implementation should implement the following:

new-value = (current-value & mask) | request-value

Options will be a string-keyed map which contains any options set specifically on this request. In the current implementation these may have been set via query parameters in the URL used to make the request.

The function should return true if all of the requested resources were successfully written. Otherwise, *exception should be allocated with a string value indicating the problem (this will be logged and returned to the caller), and false returned.

devsdk_stop

The implementation should perform any cleanup necessary before shutdown. At the time that this function is called, the service will be quiescent, ie there will be no new incoming requests.

Parameter Type Description
impl void* The context data passed in when the service was created
force bool An unclean shutdown may be performed if necessary. Long or indefinite timeouts should not occur.

devsdk_callbacks_init

Call this function in order to create a devsdk_callbacks object containing the required callback functions. This may then be passed to the SDK when starting the service

Parameter Type
init devsdk_initialize
gethandler devsdk_handle_get
puthandler devsdk_handle_put
stop devsdk_stop
create_addr devsdk_create_address
free_addr devsdk_free_address
create_res devsdk_create_resource_attr
free_res devsdk_free_resource_attr

Optional callback functions

devsdk_reconfigure

Implement this function in order to allow changes in the device-specific configuration to be made without restarting the service.

Parameter Type Description
impl void* The context data passed in when the service was created
config iot_data_t* The new configuration (contains all elements, not just those which have changed)

devsdk_callbacks_set_reconfiguration

Call this to add your reconfiguration function to the callbacks structure

Parameter Type Description
cb devsdk_callbacks* structure to be modified
reconf devsdk_reconfigure function to add

devsdk_discover

This function is called when a request for discovery is made. This may occur automatically at intervals or due to an external request. The SDK implements locking such that multiple invocations of this function will not be made in parallel.

Implementations should perform a scan for devices, and use the devsdk_add_discovered_devices function to register them.

Parameter Type Description
impl void* The context data passed in when the service was created

devsdk_describe

This is a placeholder function for future use. Its purpose will be to allow automatic generation of device profiles. It is not used in current versions of EdgeX.

Parameter Type Description
impl void* The context data passed in when the service was created
dev devsdk_device_t* The device which is to be described
options iot_data_t* Service specific discovery options map. May be NULL
resources devsdk_device_resources** The operations supported by the device
exception iot_data_t** Additional information in the event of an error

Implementations should populate the resources parameter and return true if it is possible to automatically describe the device. Otherwise return false and set exception.

devsdk_callbacks_set_discovery

Call this to add your discovery functions to the callbacks structure

Parameter Type Description
cb devsdk_callbacks* structure to be modified
discover devsdk_discover device discovery function
describe devsdk_describe device description function, may be NULL (currently unused)

devsdk_add_device_callback

To be notified when a device is added to the system (and assigned to this device service), provide an implementation of this function

Parameter Type Description
impl void* The context data passed in when the service was created
devname char* The name of the new device
protocols devsdk_protocols* The protocol properties that comprise the device's address
resources devsdk_device_resources* The operations supported by the device
adminEnabled bool Whether the device is administratively enabled

devsdk_update_device_callback

To be notified when a device managed by this service is modified, provide an implementation of this function

Parameter Type Description
impl void* The context data passed in when the service was created
devname char* The name of the updated device
protocols devsdk_protocols* The protocol properties that comprise the device's address
state bool Whether the device is administratively enabled

devsdk_remove_device_callback

To be notified when a device managed by this service is removed, provide an implementation of this function

Parameter Type Description
impl void* The context data passed in when the service was created
devname char* The name of the removed device
protocols devsdk_protocols* The protocol properties that comprise the device's address

devsdk_callbacks_set_listeners

Call this to add your add, remove and/or update listener functions to the callbacks structure. Any of the functions may be NULL

Parameter Type Description
cb devsdk_callbacks* structure to be modified
device_added devsdk_add_device_callback device addition listener
device_updated devsdk_update_device_callback device update listener
device_removed devsdk_remove_device_callback device removal listener

devsdk_autoevent_start_handler

Some device types may be configured to generate readings automatically at intervals. Such behavior may be enabled by providing implementations of this function and the stop handler described below. If "AutoEvents" have been defined for a device, this function will be called to request that automatic events should begin. The events when generated should be posted using the devsdk_post_readings function. In the absence of an implementation of this function, the SDK will poll the device via the get handler.

Parameter Type Description
impl void* The context data passed in when the service was created
devname char* The name of the device to be queried
protocols devsdk_protocols* The address of the device to be queried
resource_name char* The resource on which autoevents have been configured
nreadings uint32_t The number of readings requested
requests devsdk_commandrequest* Array containing details of the resources to be queried
interval uint64_t The time between events, in milliseconds
onChange bool If true, events should only be generated if one or more readings have changed

The function should return a pointer to a data structure that will be provided in a subsequent call to the stop handler when this autoevent is t be stopped

devsdk_autoevent_stop_handler

This function is called to request that automatic events should cease

Parameter Type Description
impl void* The context data passed in when the service was created
handle void* The data structure returned by a previous call to the start handler

devsdk_callbacks_set_autoevent_handlers

Call this to add your autoevent management functions to the callbacks structure. Both start and stop handlers are required

Parameter Type Description
cb devsdk_callbacks* structure to be modified
ae_starter devsdk_autoevent_start_handler Autoevent start handler
ae_stopper devsdk_autoevent_stop_handler Autoevent stop handler

Initialisation and Shutdown

These functions manage the lifecycle of the device service and should be called in the order presented here

devsdk_service_new

This function creates a new device service

Parameter Type Description
defaultname char* The device service name, used in logging, metadata lookups and to scope configuration. This may be overridden via the commandline
version char* The version string for this service. This is for information only, and will be logged during startup
impldata void* An object pointer which will be passed back whenever one of the callback functions is invoked
implfns devsdk_callbacks* Structure containing the device implementation functions. The SDK will call these functions in order to carry out its various actions
argc int* A pointer to argc as passed into main(). This will be adjusted to account for arguments consumed by the SDK
argv char** argv as passed into main(). This will be adjusted to account for arguments consumed by the SDK
err devsdk_error* Nonzero reason codes will be set here in the event of errors

The newly created service is represented by an object of type devsdk_service_t, which is returned if the service is created successfully

The SDK modifies the commandline argument parameters argc and argv, removing those arguments which it supports. The implementation may support additional arguments by inspecting these modified values after the create function has been called

devsdk_service_start

Start the device service. Default values for the implementation-specific configuration are passed in here. These must be provided in a string-keyed iot_data_t map. A value named "X" may be over-ridden in the configuration file by an entry for X in the [Driver] section. For dynamically-updatable configuration, set a value for "Writable/X". This will correspond to a configuration file entry in the [Writable.Driver] section and updates may be received by implementing the devsdk_reconfigure function

Parameter Type Description
svc devsdk_service_t* The device service
driverdfls iot_data_t* Default configuration
err devsdk_error* Nonzero reason codes will be set here in the event of errors

devsdk_service_stop

Stop the device service. Any automatic events will be cancelled and the REST API for the device service will be shut down

Parameter Type Description
svc devsdk_service_t* The device service
force bool Force stop. Currently unused but is passed through to the stop handler
err devsdk_error* Nonzero reason codes will be set here in the event of errors

devsdk_service_free

This function disposes of the device service object and all associated resources

Parameter Type Description
svc devsdk_service_t* The device service

Additional functionality

devsdk_usage

This function writes out the commandline options supported by the SDK. It may be useful if a --help option is to be implemented

devsdk_protocols_properties

This function returns a map of properties (keyed on string) for the named protocol.

Parameter Type Description
prots devsdk_protocols* The protocols to search
name char* The name of the protocol to search for

devsdk_protocols_new

This function creates a new protocols object, or adds a property set to an existing one.

Parameter Type Description
name char* The name of the new protocol
properties iot_data_t* The properties of the new protocol
list devsdk_protocols* The protocols object to extend, or NULL to create a new one

devsdk_protocols_dup

This function duplicates a protocols object

Parameter Type Description
e devsdk_protocols* object to duplicate

devsdk_protocols_free

This function disposes of the memory used by a protocols object

Parameter Type Description
e devsdk_protocols* object to free

devsdk_get_secrets

This function returns secrets (credentials) for the service. In insecure mode these will be part of the service configuration, in secure mode they will be retrieved from the secret store (eg, Vault).

The secrets are returned as a string-keyed map. This should be disposed after use using iot_data_free

devsdk_post_readings

This function posts readings to EdgeX. Depending on configuration this may be via REST to core-data or via the Message Bus to various upstream services. The readings are assembled into an Event and then posted

This function may be used in services which implement the autoevent handlers or by any other service where the natural operation is that readings are generated by the device rather than being explicitly requested

Parameter Type Description
svc devsdk_service_t* The device service
device_name char* Name of the device that has generated the readings
resource_name char* Name of the resource (or command) corresponding to this set of readings
values devsdk_commandresult* The readings to be posted

The cardinality of the values array will depend on the resource - if it is a deviceResource there should be a single reading; for a deviceCommand there may be several

devsdk_add_discovered_devices

This function should be called in response to a request for device discovery, but may be called at any time if for a particular device class immediate automatic discovery is appropriate. The function takes an array of devices in order to allow for batching, but it may be called multiple times during the course of a single invocation of discovery if necessary

Parameter Type Description
svc devsdk_service_t* The device service
ndevices uint32_t Number of devices discovered
devices devsdk_discovered_device* Array of discovered devices

devsdk_set_device_opstate

This function can be used to indicate that a device has become non-operational or non-responsive, or that a device has returned from such a state. The SDK will return errors for requests for a device marked non-operational without calling the get or set handler

Parameter Type Description
svc devsdk_service_t* The device service
devname char* The device that has changed state
operational bool The new operational state

devsdk_get_devices

Returns a list of devices registered with this service

Parameter Type Description
svc devsdk_service_t* The device service

The returned list should be disposed after use using devsdk_free_devices

devsdk_get_device

Returns information on a device

Parameter Type Description
svc devsdk_service_t* The device service
name char* The device to query for

The returned device should be disposed after use using devsdk_free_devices

devsdk_free_devices

Frees a devices structure returned by devsdk_get_devices or devsdk_get_device

Parameter Type Description
svc devsdk_service_t* The device service
d devsdk_devices* The device or device list