Quality of Service

The Quality of Service (QoS) library provides APIs to store and handle acknowledgment of multiple in-flight messages. The library is transport agnostic, which means that it does not enforce any transport-related functionality to the caller.

Implementation

The following sequence diagram shows a typical usage of the library:

Sequence diagram general

QoS library implementation sequence diagram

Configuration

To use this library, set the CONFIG_QOS Kconfig option and include the include/lib/qos.h file to your project.

Additionally, Configure the following options when using this library:

Usage

The qos_message_add() and qos_message_remove() functions add and remove the messages respectively from the library. Before adding a message, it must be associated with a message flag. This flag determines whether or not the message needs to be stored in the pending list that is internal to the library and how the message must be notified. Following are the available flags:

Note

All messages that are added to the library using the qos_message_add() function is notified with the QOS_EVT_MESSAGE_TIMER_EXPIRED event.

The following code block displays how the library can be initialized and a single message is added:

/* Register message types that can be used to route data. */
QOS_MESSAGE_TYPES_REGISTER(SENSOR_DATA, DIAGNOSTIC_DATA);

/* Event handler used to receive notifications from the library. */
static void qos_event_handler(const struct qos_evt *evt)
{
   switch (evt->type) {
   case QOS_EVT_MESSAGE_NEW:
   case QOS_EVT_MESSAGE_TIMER_EXPIRED:
      /* Check evt->message.type and route message based on type. */
      break;
   case QOS_EVT_MESSAGE_REMOVED_FROM_LIST:
      /* Free payload if (evt->message.heap_allocated == true) */
      break;
   default:
      break;
   }
}

/* QoS library message data structure. */
struct qos_data message = {
             .heap_allocated = true,
             .data.buf = pointer_to_payload,
             .data.len = size_of_payload,
             .id = qos_message_id_get_next(),
             .type = SENSOR_DATA,
             .flags = QOS_FLAG_RELIABILITY_ACK_REQUIRED
};

/* Initialize the QoS library and set the library event handler. */
err = qos_init(qos_event_handler);
if (err) {
   LOG_ERR("qos_init, err", err);
   return err;
}

/* Add a single message. */
err = qos_message_add(&message);
if (err) {
   LOG_ERR("qos_message_add, error: %d", err);
   return err;
}

To remove a message from the pending list, call qos_message_remove() with the message ID of the corresponding message:

err = qos_message_remove(message_id);
if (err) {
   LOG_ERR("qos_message_remove, error: %d", err);
   return err;
}

Messages added to the library can be associated with specific message types. These message types can be used to route messages after they have been notified in the library callback handler. Message types can be generated using the QOS_MESSAGE_TYPES_REGISTER macro. For messages that require acknowledgment, message transport libraries often need a message ID. The application can use the qos_message_id_get_next() function to generate the Message IDs.

Note

Some transport libraries reserve specific message IDs for internal use, typically lower integer ranges. Hence, the qos_message_id_get_next() function generates IDs based on an ID base, QOS_MESSAGE_ID_BASE of 15000.

Samples using the library

The nRF9160:Asset Tracker v2 application uses this library.

API documentation

Header file: include/lib/qos.h
Source files: lib/qos.c
group qos

QoS library that provides functionality to store and handle acknowledgment of multiple in-flight messages.

Defines

X(name)

Macro used to register message types that are supported by the application.

QOS_MESSAGE_TYPES_REGISTER(...)
QOS_MESSAGE_ID_BASE

ID base used for message IDs retrieved using qos_message_id_get_next() API.

Typedefs

typedef void (*qos_evt_handler_t)(const struct qos_evt *evt)

QoS library event handler.

Param evt

[in] The event and the associated parameters.

Enums

enum qos_evt_type

Events notified by the library’s callback handler.

Values:

enumerator QOS_EVT_MESSAGE_NEW

A new message is ready. Payload is of type qos_data. (message)

enumerator QOS_EVT_MESSAGE_TIMER_EXPIRED

The internal backoff timer has expired. This callback contains one or more messages that should be sent. Payload is of type qos_data. (message)

Callbacks of this event type are notified in system workqueue context.

enumerator QOS_EVT_MESSAGE_REMOVED_FROM_LIST

Event received when the internal list of pending messages is full or a message has been removed from the list using the qos_message_remove() API call.

If the heap_allocated flag is set in the qos_data message structure the corresponding buffer (message.data.buf) must be freed by the caller. Payload is of type qos_data.

Functions

int qos_init(qos_evt_handler_t evt_handler)

Function that initializes the QoS library.

Parameters
  • evt_handler – Pointer to the event callback handler.

int qos_message_add(struct qos_data *message)

Add a message to the library. If the message fails to be added to the internal list because the list is full, the message will be notified with the QOS_EVT_MESSAGE_REMOVED_FROM_LIST event, so that it can be freed if heap allocated. When this API is called, the event QOS_EVT_MESSAGE_NEW is always notified with the corresponding message.

Parameters
  • message – Pointer to the corresponding message

Return values
  • 0 – on success.

  • -EINVAL – If the message pointer is NULL.

  • -ENOMEM – If the internal list is full.

int qos_message_remove(uint32_t id)

Remove message from internal list. An event QOS_EVT_MESSAGE_REMOVED_FROM_LIST will be notified in the library callback.

Parameters
  • id – Message ID of message to be removed.

Return values
  • 0 – on success.

  • -ENODATA – If the passed in message ID is not found in the internal list.

bool qos_message_has_flag(const struct qos_data *message, uint32_t flag)

Function that checks if a flag is part of the bitmask associated with a message.

Parameters
  • message – Pointer to message.

  • flag – Flag to check for.

Return values
  • true – if the flag checked for is a part of the message flag bitmask.

  • false – if flag checked for is not a part of the message flag bitmask.

void qos_message_print(const struct qos_data *message)

Function that prints the contents of a qos message structure. This requires that the library log level is set to debug level. CONFIG_QOS_LOG_LEVEL_DBG=y.

uint16_t qos_message_id_get_next(void)

Generate message ID that counts from QOS_MESSAGE_ID_BASE message ID base. Count is reset if UINT16_MAX is reached.

Return values

Message – ID.

void qos_message_notify_all(void)

Notify all pending messages. All messages that are currently stored in the internal list will be notified via the QOS_EVT_MESSAGE_TIMER_EXPIRED event. This API does not clear the internal pending list.

void qos_message_remove_all(void)

Remove all pending messages. All messages that are currently stored in the internal list will removed. Each message will be notified in the QOS_EVT_MESSAGE_REMOVED_FROM_LIST callback event. This API clears the internal pending list.

void qos_timer_reset(void)

Reset and stop an ongoing timer backoff.

struct qos_payload
#include <qos.h>

Structure used to keep track of unACKed messages.

Public Members

uint8_t *buf

Pointer to data.

size_t len

Length of data.

struct qos_data
#include <qos.h>

Structure that contains the message payload and corresponding metadata.

Public Members

uint32_t flags

Flags associated with the message. See QoS library flag bitmask values. for documentation on the various flags that can be set.

uint16_t id

Message ID

uint16_t notified_count

Number of times that the message has been notified by the library. This count is not incremented for messages flagged with QOS_FLAG_RELIABILITY_ACK_DISABLED.

uint8_t type

Type of the message.

When adding a message to the library using qos_message_add(), the message types defined with the QOS_MESSAGE_TYPES_REGISTER macro can be used to assign a type to the message.

The message type can be used to route data after a new or timed out message is received with the QOS_MESSAGE_NEW or QOS_EVT_MESSAGE_TIMER_EXPIRED events.

struct qos_payload data

Variable to keep track of user-allocated payload.

bool heap_allocated

Flag signifying if the payload is heap allocated. When a message has been removed from the library using qos_message_remove() the payload buffer must be freed if this flag has been set.

struct qos_evt
#include <qos.h>

Library callback event structure.

Public Members

enum qos_evt_type type

Event type notified by the library.

struct qos_data message

Payload and corresponding metadata.