User manual

LwPKT protocol library is a simple state-machine parser and raw data generator to allow 2 or more devices in a network to communicate in a structure way.

It is perfectly suitable for communication in embedded systems, suchs as RS-485, where multiple devices could be easily connected to one big network.

LwPKT library uses well known and easy implementation of LwRB library for data read and data write. It expects 2 different buffer instances, one for TX events, second for RX events.

Parser is a simple state machine that reads and processes every received character from read buffer. When application wants to transmit data, LwPKT library generates raw data and writes them to TX buffer.

Combination of both gives embedded applications freedom to implement communication protocols for TX and RX.

Packet structure

Packet structure consists of several fields, where some are optional and some are mandatory.

Full features structure format

Full features structure format

  • START: Byte with fixed value to represent start of packet

  • FROM: Byte(s) from where this packet is coming from. Optional field, can be disabled with LWPKT_CFG_USE_ADDR

  • TO: Byte(s) to where this packet is targeting. Optional field, can be disabled with LWPKT_CFG_USE_ADDR

  • FLAGS: Variable length (unsigned 32-bit max) field for optional user flags. Optional field, can be disabled with LWPKT_CFG_USE_FLAGS

  • CMD: Byte with optional command field to better align with multiple packets. Optional field, can be disabled with LWPKT_CFG_USE_CMD

  • LEN: Length of data part field. This is variable multi-byte length to support data length >= 256 bytes. Always present

  • DATA: Optional data field. Number of bytes is as in LEN field

  • CRC: 8-bit CRC of all enabled fields except START and STOP bytes. Optional field, can be disabled with LWPKT_CFG_USE_CRC

  • STOP: Byte with fixed value to represent stop of packet


If only 2 devices are communicating and are in the network, considering disabling LWPKT_CFG_USE_ADDR to improve data bandwidth and remove unnecessary packet overhead

Data input output

LwPKT library only reads and writes to 2 ringbuffers used for read and write operations. It is up to application to implement how buffers are actually later written for read operation and sent out on the network for write operation.


LwPKT is platform independant and requires final application to actually take care of data being read/written from/to ringbuffers and transferred further over the network

Variable data length

Some fields implement variable data length feature, to optimize data transfer length. Fields with variable length implementation are:

Variable data length is a feature that uses minimum number of bytes to transfer the data. It uses 7 LSB bits per byte for actual data, and MSB bit to indicate if there are more bytes coming after.

For example, values between 0x00 - 0x7F are codified within single byte, while values between 0x80 - 0xFF require 2 bytes for transfer.


To transfer 32-bit variable, minimum 1-byte and maximum 5-bytes are used.


Data codification is always LSB Byte first.

Static & dynamic feature

LwPKT supports multiple instance in the same build, but there might be cases where each instance needs different protocol configuration, such as enabled/disabled from/to fields or enabled/disabled command feature.

Some configuration features (See configuration chapter for full list of options) support static or dynamic configuration:

  • static configuration is one configuration for all instances. Globally enabled or disabled feature

  • dynamic configuration allows that each instance keeps its own protocol configuration.

Event management

LwPKT may operate in event mode, meaning that application receives notifications on different events:

  • New packet has been received

  • Timeout during packet receive

Timeout function is used when network doesn’t transmit all bytes or if data got lost in the middle of transmission. This is to make sure that packet protocol library easily recovers to be able to receive more packets in the future


To use this feature, application must provide accurate timing in units of milliseconds to be able to properly handle timeout function.

LwPKT example with events
  1#include <stdio.h>
  2#include "lwpkt/lwpkt.h"
  4/* LwPKT data */
  5static lwpkt_t pkt;
  6static lwrb_t pkt_tx_rb, pkt_rx_rb;
  7static uint8_t pkt_tx_rb_data[64], pkt_rx_rb_data[64];
  9/* Data to read and write */
 10static const char* data = "Hello World\r\n";
 13 * \brief           LwPKT application callback
 14 */
 15static void
 16my_lwpkt_evt_fn(lwpkt_t* pkt, lwpkt_evt_type_t type) {
 17    switch (type) {
 18        case LWPKT_EVT_PKT: {
 19            printf("Valid packet received..\r\n");
 21            /* Packet is valid */
 22            printf("Packet is valid!\r\n");
 24            /* Print debug messages for packet */
 26            printf("Packet from: 0x%08X\r\n", (unsigned)lwpkt_get_from_addr(pkt));
 27            printf("Packet to: 0x%08X\r\n", (unsigned)lwpkt_get_to_addr(pkt));
 28#endif /* LWPKT_CFG_USE_ADDR */
 30            printf("Packet cmd: 0x%08X\r\n", (unsigned)lwpkt_get_cmd(pkt));
 31#endif /* LWPKT_CFG_USE_CMD */
 32            printf("Packet data length: 0x%08X\r\n", (unsigned)lwpkt_get_data_len(pkt));
 34            /* Do other thins... */
 35            break;
 36        }
 37        case LWPKT_EVT_TIMEOUT: {
 38            printf("Timeout detected during read operation..\r\n");
 39            break;
 40        }
 41        default: {
 42            break;
 43        }
 44    }
 48 * \brief           LwPKT example code with event feature
 49 */
 51example_lwpkt_evt(void) {
 52    lwpktr_t res;
 53    uint32_t time;
 54    uint8_t b;
 56    printf("---\r\nLwPKT event type..\r\n\r\n");
 58    /* 
 59     * Initialize both ring buffers, for TX and RX operations
 60     *
 61     * Initialize LwPKT and link buffers together
 62     */
 63    lwrb_init(&pkt_tx_rb, pkt_tx_rb_data, sizeof(pkt_tx_rb_data));
 64    lwrb_init(&pkt_rx_rb, pkt_rx_rb_data, sizeof(pkt_rx_rb_data));
 65    lwpkt_init(&pkt, &pkt_tx_rb, &pkt_rx_rb);
 68    /* Set device address (if feature enabled) */
 69    lwpkt_set_addr(&pkt, 0x12);
 70#endif /* LWPKT_CFG_USE_ADDR */
 72    /* 
 73     * Write packet to the TX ringbuffer,
 74     * act as device wants to send some data
 75     */
 76    res = lwpkt_write(&pkt,
 78                      0x11, /* End address to whom to send */
 79#endif                      /* LWPKT_CFG_USE_ADDR */
 81                      0x12345678, /* Custom flags added to the packet */
 82#endif                            /* LWPKT_CFG_USE_FLAGS */
 84                      0x85,                /* Command type */
 85#endif                                     /* LWPKT_CFG_USE_CMD */
 86                      data, strlen(data)); /* Length of data and actual data */
 88    /*
 89     * LwPKT wrote data to pkt_tx_rb ringbuffer
 90     * Now actually transmit data over your interface
 91     * (USART for example, ...)
 92     */
 94    /*
 95     * For the purpose of this example, application will
 96     * fake data transmission by doing reading from TX buffer
 97     * and writing it to RX buffer
 98     */
 99    while (lwrb_read(&pkt_tx_rb, &b, 1) == 1) {
100        lwrb_write(&pkt_rx_rb, &b, 1);
101    }
103    /*
104     * Here we have our data in RX buffer
105     * means we received data over network interface
106     */
108    /* Set callback function */
109    lwpkt_set_evt_fn(&pkt, my_lwpkt_evt_fn);
111    /* Now call process function instead */
112    time = 100; /* Get_current_time_in_milliseconds */
113    lwpkt_process(&pkt, time);
115    (void)res;