JSDRV API

group jsdrv_api

The Joulescope driver host application interface.

This API is based upon a distributed publish-subscribe (PubSub) implementation. The system is arranged as a hierarchical set of topics which have values. Devices expose topics that control and configure operation. Devices also publish the measured data to topics for consumption by the host application.

The host code can set topic values using jsdrv_publish(). Host code can subscribe to topic value changes using jsdrv_subscribe(). This driver will then call the registered subscriber callback for each change on a matching topic. When the host code calls jsdrv_subscribe() with flags (JSDRV_SFLAG_RETAIN | JSDRV_SFLAG_PUB), then the driver immediately provides the retained values to synchronize the host state.

This implementation provides several nice features:

  • Multiple value data types including integers, floats, str, json, binary

  • Retained values

  • Topic metadata for automatically populating user interfaces.

  • Thread-safe, in-order operation. The driver provides thread-safe synchronous publish with timeout. However, subscriber callbacks are always invoked from the internal PubSub thread, and the host code is responsible for resynchronization.

  • Guaranteed in-order topic traversal for retained messages based upon creation order.

  • Device connection options:

    • connect and restore default settings

    • connect and resume using existing device settings.

Topic names use a hierarchical naming convention. Topics associated with a device start with a prefix: {p} = {backend}/{model}/{serial_number}

  • {backend}: 1 character backend identifier 0-9, a-z, A-Z.

  • {model}: The device model number, such as js220.

  • {serial_number}: The device serial number string.

The rest of the topic is also hierarchical, and the following characters are reserved:

/?#$'"`&@%
Topics that start with ‘_’ or ‘@’ are directed only to the central PubSub instance within the driver itself.

Topics are presumed to have retained values unless the subtopic starts with the character ‘!’.

Topics with the following suffix characters have special meanings:

  • ’’: metadata request (value should be NULL)

  • ’$’: metadata response

  • ’?’: query request (value should be NULL)

  • ’&’: query response

  • ’#’: return code. Value is i32 return code. 0=success.

Note that the topic owner will respond to jsdrv_publish operations with a return code to allow for fully synchronous operation.

The metadata values are JSON-formatted strings with the following data structure:

  • dtype: one of [str, json, bin, f32, f64, u8, u16, u32, u64, i8, i16, i32, i64]

  • brief: A brief string description (recommended).

  • detail: A more detailed string description (optional).

  • default: The recommended default value (optional).

  • options: A list of options, where each option is each a flat list of: [value [, alt1 [, …]]] The alternates must be given in preference order. The first value must be the value as dtype. The second value alt1 (when provided) is used to automatically populate user interfaces, and it can be the same as value. Additional values will be interpreted as equivalents.

  • range: The list of [v_min, v_max] or [v_min, v_max, v_step]. Both v_min and v_max are inclusive. v_step defaults to 1 if omitted.

  • format: Formatting hints string:

    • version: The u32 dtype should be interpreted as major8.minor8.patch16.

  • flags: A list of flags for this topic. Options include:

    • ro: This topic cannot be updated.

    • hide: This topic should not appear in the user interface.

    • dev: Developer option that should not be used in production.

Defines

JSDRV_PAYLOAD_LENGTH_MAX

The maximum size for normal PubSub messages.

JSDRV_STREAM_HEADER_SIZE

The header size of jsdrv_stream_signal_s before the data field.

JSDRV_STREAM_DATA_SIZE

The size of data in jsdrv_stream_signal_s.

JSDRV_TIMEOUT_MS_DEFAULT

The recommended default timeout.

JSDRV_TIMEOUT_MS_INIT

The recommended default jsdrv_initialize() timeout.

Typedefs

typedef void (*jsdrv_subscribe_fn)(void *user_data, const char *topic, const struct jsdrv_union_s *value)

Function called on topic updates.

This function will be called from the Joulescope driver frontend thread. The function is responsible for performing any resynchronization to an application target thread, if needed. However, the value only remains valid for the duration of the callback. Any binary or string data must be copied!

Param user_data:

The arbitrary user data.

Param topic:

The topic for this update.

Param value:

The value for this update.

Enums

enum jsdrv_payload_type_e

The payload type for jsdrv_union_s.app.

Values:

enumerator JSDRV_PAYLOAD_TYPE_UNION
enumerator JSDRV_PAYLOAD_TYPE_STREAM
enumerator JSDRV_PAYLOAD_TYPE_STATISTICS
enumerator JSDRV_PAYLOAD_TYPE_BUFFER_INFO
enumerator JSDRV_PAYLOAD_TYPE_BUFFER_REQ
enumerator JSDRV_PAYLOAD_TYPE_BUFFER_RSP
enum jsdrv_element_type_e

The element base type for streaming data.

Values:

enumerator JSDRV_DATA_TYPE_UNDEFINED
enumerator JSDRV_DATA_TYPE_INT
enumerator JSDRV_DATA_TYPE_UINT
enumerator JSDRV_DATA_TYPE_FLOAT
enum jsdrv_field_e

The signal field type for streaming data.

Values:

enumerator JSDRV_FIELD_UNDEFINED
enumerator JSDRV_FIELD_CURRENT
enumerator JSDRV_FIELD_VOLTAGE
enumerator JSDRV_FIELD_POWER
enumerator JSDRV_FIELD_RANGE
enumerator JSDRV_FIELD_GPI
enumerator JSDRV_FIELD_UART
enumerator JSDRV_FIELD_RAW
enum jsdrv_time_type_e

The time specification type.

Values:

enumerator JSDRV_TIME_UTC

Time in i64 34Q30 UTC. See jsdrv/time.h.

enumerator JSDRV_TIME_SAMPLES

Time in sample_ids for the corresponding channel.

enum jsdrv_buffer_response_type_e

The buffer response type.

Values:

enumerator JSDRV_BUFFER_RESPONSE_SAMPLES

Data contains samples.

enumerator JSDRV_BUFFER_RESPONSE_SUMMARY

Data contains summary statistics.

enum jsdrv_subscribe_flag_e

The subscriber flags for jsdrv_subscribe().

Values:

enumerator JSDRV_SFLAG_NONE

No flags (always 0).

enumerator JSDRV_SFLAG_RETAIN

Immediately forward retained PUB and/or METADATA, depending upon JSDRV_PUBSUB_SFLAG_PUB and JSDRV_PUBSUB_SFLAG_METADATA_RSP.

enumerator JSDRV_SFLAG_PUB

Receive normal topic publish.

enumerator JSDRV_SFLAG_METADATA_REQ

Subscribe to receive metadata requests like “$” and “a/b/$”.

enumerator JSDRV_SFLAG_METADATA_RSP

Subscribe to receive metadata responses like “a/b/c$.

enumerator JSDRV_SFLAG_QUERY_REQ

Subscribe to receive query requests like “?” and “a/b/?”.

enumerator JSDRV_SFLAG_QUERY_RSP

Subscribe to receive query responses like “a/b/c?”.

enumerator JSDRV_SFLAG_RETURN_CODE

Subscribe to receive return code messages like “a/b/c#”.

enum jsdrv_device_open_mode_e

The driver mode for device open.

Values:

enumerator JSDRV_DEVICE_OPEN_MODE_DEFAULTS

Restore the device to its default, power-on state.

enumerator JSDRV_DEVICE_OPEN_MODE_RESUME

Update the driver with the device’s existing state.

enumerator JSDRV_DEVICE_OPEN_MODE_RAW

Low-level open only, for use by internal tools.

Functions

int32_t jsdrv_initialize(struct jsdrv_context_s **context, const struct jsdrv_arg_s *args, uint32_t timeout_ms)

Initialize the Joulescope driver (synchronous).

Parameters:
  • context[out] The Joulescope driver context for future API calls.

  • args – The initialization arguments or NULL. The argument list is terminated with an argument with an empty string for topic.

  • timeout_ms – This function is always blocking and waits for up to timeout_ms for the operation to complete. When 0, use the default timeout [recommended]. When nonzero, override the default timeout.

Returns:

0 or error code.

void jsdrv_finalize(struct jsdrv_context_s *context, uint32_t timeout_ms)

Finalize the Joulescope driver (synchronous).

This function releases all Joulescope driver resources including memory and threads.

This function must not be called from the driver frontend thread. Therefore, do not call this function directly from a subscriber callback.

Parameters:
  • context – The context from jsdrv_initialize().

  • timeout_ms – This function is always blocking and waits for up to timeout_ms for the operation to complete. When 0, use the default timeout [recommended]. When nonzero, override the default timeout.

int32_t jsdrv_publish(struct jsdrv_context_s *context, const char *topic, const struct jsdrv_union_s *value, uint32_t timeout_ms)

Publish a new value.

Parameters:
  • context – The Joulescope driver context.

  • topic – The topic to publish.

  • value – The new topic value.

  • timeout_ms – When 0, publish asynchronously without awaiting the result. When nonzero, block awaiting the return code message.

Returns:

0 or error code. All calls may return JSDRV_ERROR_PARAMETER_INVALID. Each topic may return other error codes.

int32_t jsdrv_query(struct jsdrv_context_s *context, const char *topic, struct jsdrv_union_s *value, uint32_t timeout_ms)

Query a retained value.

Parameters:
  • context – The Joulescope driver context.

  • topic – The topic to query.

  • value[inout] The topic value. For string, JSON, and binary values, the provided value must be initialized with an allocated buffer. The value will be copied into this buffer or return JSDRV_ERROR_TOO_SMALL. If provided, this buffer will be ignored for other value types.

  • timeout_ms – This function is always blocking and waits for up to timeout_ms for the operation to complete. When 0, use the default timeout [recommended]. When nonzero, override the default timeout.

Returns:

0 or error code. All calls may return JSDRV_ERROR_PARAMETER_INVALID and JSDRV_ERROR_TIMED_OUT.

int32_t jsdrv_subscribe(struct jsdrv_context_s *context, const char *topic, uint8_t flags, jsdrv_subscribe_fn cbk_fn, void *cbk_user_data, uint32_t timeout_ms)

Subscribe to topic updates.

Synchronous, blocking subscription is most useful when flags contains JSDRV_SFLAG_RETAIN. The operation will not complete until cbk_fn() is called with all retained values.

Parameters:
  • context – The Joulescope driver context.

  • topic – The subscription topic. The cbk_fn will be called whenever this topic or a child is updated.

  • flags – The jsdrv_subscribe_flag_e bitmap. 0 (JSDRV_SFLAG_NONE) for no flags.

  • cbk_fn – The function to call with topic updates. When called, this function will be invoked from the Joulescope driver thread. The function must NOT call jsdrv_finalize() or jsdrv_wait().

  • cbk_user_data – The arbitrary data provided to cbk_fn.

  • timeout_ms – When 0, subscribe asynchronously. When nonzero, block awaiting the subscription operation to complete.

Returns:

0 or error code.

int32_t jsdrv_unsubscribe(struct jsdrv_context_s *context, const char *topic, jsdrv_subscribe_fn cbk_fn, void *cbk_user_data, uint32_t timeout_ms)

Unsubscribe to topic updates.

Most callers will want to use blocking, synchronous unsubscribe. Blocking unsubscribe ensures that cbk_fn() will not be called when this function returns. With asynchronous unsubscribe, cbk_fn() may be called for some indefinite number of times and duration until the unsubscribe request is handled internally.

See also

jsdrv_subscribe

Parameters:
  • context – The Joulescope driver context.

  • topic – The subscription topic for unsubscription.

  • cbk_fn – The previous subscribed function.

  • cbk_user_data – The arbitrary data provided to cbk_fn which must match the value provided to jsdrv_subscribe().

  • timeout_ms – When 0, unsubscribe asynchronously. When nonzero, block awaiting the unsubscribe operation to complete.

Returns:

0 or error code.

int32_t jsdrv_unsubscribe_all(struct jsdrv_context_s *context, jsdrv_subscribe_fn cbk_fn, void *cbk_user_data, uint32_t timeout_ms)

Unsubscribe from all topic updates (asynchronous).

Most callers will want to use blocking, synchronous unsubscribe. See jsdrv_unsubscribe() for details.

Parameters:
  • context – The Joulescope driver context.

  • cbk_fn – The previous subscribed function.

  • cbk_user_data – The arbitrary data provided to cbk_fn which must match the value provided to jsdrv_subscribe().

  • timeout_ms – When 0, unsubscribe asynchronously. When nonzero, block awaiting the unsubscribe operation to complete.

Returns:

0 or error code.

int32_t jsdrv_open(struct jsdrv_context_s *context, const char *device_prefix, int32_t mode)

Open a device.

This is a convenience function that wraps a single call to jsdrv_publish() with an i32 value. Language wrappers should not wrap this function and instead call jsdrv_publish() directly.

Parameters:
  • context – The Joulescope driver context.

  • device_prefix – The device prefix string.

  • mode – The jsdrv_device_open_mode_e.

Returns:

0 or error code.

int32_t jsdrv_close(struct jsdrv_context_s *context, const char *device_prefix)

Close a device.

This is a convenience function that wraps a single call to jsdrv_publish(). Language wrappers should not wrap this function and instead call jsdrv_publish() directly.

Parameters:
  • context – The Joulescope driver context.

  • device_prefix – The device prefix string.

Returns:

0 or error code.

void jsdrv_calibration_hash(const uint32_t *msg, uint32_t length, uint32_t *hash)

Compute the calibration hash.

Parameters:
  • msg[in] – The calibration message.

  • length[in] – The length of message in bytes which must be a multiple of 32 bytes.

  • hash[out] – The u32[16] hash of the message. The total length is u32 x 16 = 64-byte = 512 bit.

struct jsdrv_stream_signal_s
#include <jsdrv.h>

A contiguous, uncompressed sample block for a channel.

Public Members

uint64_t sample_id

the starting sample id, which increments by decimate_factor.

uint8_t field_id

jsdrv_field_e

uint8_t index

The channel index within the field.

uint8_t element_type

jsdrv_element_type_e

uint8_t element_size_bits

The element size in bits.

uint32_t element_count

size of data in elements

uint32_t sample_rate

The frequency for sample_id.

uint32_t decimate_factor

The decimation factor from sample_id to data samples.

struct jsdrv_time_map_s time_map

The time map between sample_id (before decimate_factor) and UTC.

uint8_t data[JSDRV_STREAM_DATA_SIZE]

The channel data.

struct jsdrv_statistics_s
#include <jsdrv.h>

The payload data structure for statistics updates.

Public Members

uint8_t version

The version, only 1 currently supported.

uint8_t rsv1_u8

Reserved = 0.

uint8_t rsv2_u8

Reserved = 0.

uint8_t decimate_factor

The decimate factor from sample_id to calculated samples = 2.

uint32_t block_sample_count

Samples used to compute this block, in decimated samples.

uint32_t sample_freq

The samples per second for *_sample_id (undecimated)

uint32_t rsv3_u8

Reserved = 0.

uint64_t block_sample_id

First sample in this block’s statistics computation.

uint64_t accum_sample_id

First sample in the integration statistics computation.

double i_avg

The average current over the block.

double i_std

The standard deviation of current over the block.

double i_min

The minimum current value in the block.

double i_max

The maximum current value in the block.

double v_avg

The average voltage over the block.

double v_std

The standard deviation of voltage over the block.

double v_min

The minimum voltage value in the block.

double v_max

The maximum voltage value in the block.

double p_avg

The average power over the block.

double p_std

The standard deviation of power over the block.

double p_min

The minimum power value in the block.

double p_max

The maximum power value in the block.

double charge_f64

The charge (integral of current) from accum_sample_id as a 64-bit float.

double energy_f64

The energy (integral of power) from accum_sample_id as a 64-bit float.

uint64_t charge_i128[2]

The charge (integral of current) from accum_sample_id as a 128-bit signed integer with 2**-31 scale.

uint64_t energy_i128[2]

The energy (integral of power) from accum_sample_id as a 128-bit signed integer with 2**-31 scale.

struct jsdrv_time_map_s time_map

The time map between sample_id and UTC.

struct jsdrv_time_range_utc_s
#include <jsdrv.h>

A UTC-defined time range.

Times are int64 34Q30 in UTC from the epoch. See jsdrv/time.h.

Public Members

int64_t start

The time for data[0] (inclusive).

int64_t end

The time for data[-1] (inclusive).

uint64_t length

The number of evenly-spaced entries.

struct jsdrv_time_range_samples_s
#include <jsdrv.h>

A sample_id-defined time range.

Times are in uint64_t sample_ids for the corresponding channel.

Public Members

uint64_t start

The time for data[0] (inclusive).

uint64_t end

The time for data[-1] (inclusive).

uint64_t length

The number of evenly-spaced entries.

struct jsdrv_buffer_info_s
#include <jsdrv.h>

The signal buffer information.

This structure contains both the size and range. The size is populated immediately, even if the buffer is still empty. As the buffer contents grows, the buffer range will approach the buffer size. When the buffer is full, the range will be close to the size. The range when full is not required to be the entire size to allow for buffering optimizations.

Public Members

uint8_t version

The response format version == 1.

uint8_t rsv1_u8

Reserved, set to 0.

uint8_t rsv2_u8

Reserved, set to 0.

uint8_t rsv3_u8

Reserved, set to 0.

uint8_t field_id

jsdrv_field_e

uint8_t index

The channel index within the field.

uint8_t element_type

jsdrv_element_type_e

uint8_t element_size_bits

The element size in bits.

char topic[JSDRV_TOPIC_LENGTH_MAX]

The source topic that provides jsdrv_stream_signal_s.

int64_t size_in_utc

The total buffer size in UTC time.

uint64_t size_in_samples

The total buffer size in samples.

struct jsdrv_time_range_utc_s time_range_utc

In UTC time.

struct jsdrv_time_range_samples_s time_range_samples

In sample time.

struct jsdrv_time_map_s time_map

The map between samples and utc time.

union jsdrv_buffer_request_time_range_u
#include <jsdrv.h>

The time range union for buffer requests.

Public Members

struct jsdrv_time_range_utc_s utc
struct jsdrv_time_range_samples_s samples
struct jsdrv_buffer_request_s
#include <jsdrv.h>

Request data from the streaming sample buffer.

To make a sample request that returns jsdrv_buffer_sample_response_s, only specify end or length. Set the unused value to zero.

If both end and length are specified, then the request may return jsdrv_buffer_summary_response_s. However, if the specified increment is less than or equal to one sample duration, then the request will return jsdrv_buffer_sample_response_s.

For JSDRV_TIME_UTC with end and length > 1, the time increment between samples is: time_incr = (time_end - time_start) / (length - 1)

Using python, the x-axis time is then: x = np.linspace(time_start, time_end, length, dtype=np.int64)

For JSDRV_TIME_SAMPLES with end and length > 1, the sample increment between samples is: sample_id_incr = (sample_id_end - sample_id_start) / (length - 1)

The buffer implementation may deduplicate requests using the combination rsp_topic and rsp_id.

Public Members

uint8_t version

The request format version == 1.

int8_t time_type

jsdrv_time_type_e

uint8_t rsv1_u8

Reserved, set to 0.

uint8_t rsv2_u8

Reserved, set to 0.

uint32_t rsv3_u32

Reserved, set to 0.

char rsp_topic[JSDRV_TOPIC_LENGTH_MAX]

The topic for this response.

int64_t rsp_id

The additional identifier to include in the response.

struct jsdrv_summary_entry_s
#include <jsdrv.h>

A single summary statistics entry.

Public Members

float avg

The average (mean) over the window.

float std

The standard deviation over the window.

float min

The maximum value over the window.

float max

The minimum value over the window.

struct jsdrv_buffer_response_s
#include <jsdrv.h>

The response to jsdrv_buffer_request_s produced by the memory buffer.

The response populates both info.time_range_utc and info.time_range_samples. Both length values are equal, and specify the number of returned data samples. For response_type JSDRV_BUFFER_RESPONSE_SUMMARY, the data is jsdrv_summary_entry_s[info.time_range_utc.length]. info.element_type is JSDRV_DATA_TYPE_UNDEFINED and info.element_size_bits is sizeof(jsdrv_summary_entry_s) * 8.

For response_type JSDRV_BUFFER_RESPONSE_SAMPLES, the data type depends upon info.element_type and info.element_size_bits.

Public Members

uint8_t version

The response format version == 1.

uint8_t response_type

jsdrv_buffer_response_type_e

uint8_t rsv1_u8

Reserved, set to 0.

uint8_t rsv2_u8

Reserved, set to 0.

uint32_t rsv3_u32

Reserved, set to 0.

int64_t rsp_id

The value provided to jsdrv_buffer_request_s.

struct jsdrv_buffer_info_s info

The response information.

uint64_t data[]

The response data.

The data type for the response varies. Unfortunately, C does not support flexible arrays in union types. Your code should cast the data to the appropriate type. Use info.time_range_samples.length for the number of data elements in this response data.

For response_type JSDRV_BUFFER_RESPONSE_SUMMARY, the data is jsdrv_summary_entry_s[info.time_range_samples.length].

For response_type JSDRV_BUFFER_RESPONSE_SAMPLES, the data is defined by info.element_type and info.element_size_bits.

struct jsdrv_arg_s
#include <jsdrv.h>

The initialization argument structure.

Public Members

const char *topic

The argument name.

struct jsdrv_union_s value

The argument value.