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:
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:
QOS_FLAG_RELIABILITY_ACK_DISABLED
- The library notifies the message only once and is not added to the internal pending list.QOS_FLAG_RELIABILITY_ACK_REQUIRED
- The library adds the message to the internal pending list and notifies after every time interval set in theCONFIG_QOS_MESSAGE_NOTIFY_TIMEOUT_SECONDS
Kconfig option with theQOS_EVT_MESSAGE_TIMER_EXPIRED
event. The library notifies the message until the message is removed or the limit set through theCONFIG_QOS_MESSAGE_NOTIFIED_COUNT_MAX
Kconfig option is reached.
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
include/lib/qos.h
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
Enums
-
enum qos_evt_type
Events notified by the library’s callback handler.
Values:
-
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.
-
enumerator QOS_EVT_MESSAGE_TIMER_EXPIRED
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.
-
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.
-
uint32_t flags
-
struct qos_evt
- #include <qos.h>
Library callback event structure.
Public Members
-
enum qos_evt_type type
Event type notified by the library.
-
enum qos_evt_type type
-
X(name)