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.

Parser is 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.

Default packet structure

Default packet structure

  • 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

  • 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

Tip

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.

Warning

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. Currently supported fields are:

Variable data length is a feature that uses minimum number of bytes to transfer 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 - 0x3F require 2 bytes for transfer. To transfer 32-bit variable, minimum 1-byte and maximum 5-bytes are used.

Tip

Data codification is always LSB Byte first.

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

Warning

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"
  3
  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];
  8
  9/* Data to read and write */
 10static const char* data = "Hello World\r\n";
 11
 12/**
 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");
 20
 21            /* Packet is valid */
 22            printf("Packet is valid!\r\n");
 23
 24            /* Print debug messages for packet */
 25#if LWPKT_CFG_USE_ADDR
 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 */
 29#if LWPKT_CFG_USE_CMD
 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));
 33
 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    }
 45}
 46
 47/**
 48 * \brief           LwPKT example code with event feature
 49 */
 50void
 51example_lwpkt_evt(void) {
 52    lwpktr_t res;
 53    uint32_t time;
 54    uint8_t b;
 55
 56    printf("---\r\nLwPKT event type..\r\n\r\n");
 57
 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);
 66
 67#if LWPKT_CFG_USE_ADDR
 68    /* Set device address (if feature enabled) */
 69    lwpkt_set_addr(&pkt, 0x12);
 70#endif /* LWPKT_CFG_USE_ADDR */
 71
 72    /* 
 73     * Write packet to the TX ringbuffer,
 74     * act as device wants to send some data
 75     */
 76    res = lwpkt_write(&pkt,
 77#if LWPKT_CFG_USE_ADDR
 78        0x11,                       /* End address to whom to send */
 79#endif /* LWPKT_CFG_USE_ADDR */
 80#if LWPKT_CFG_USE_CMD
 81        0x85,                       /* Command type */
 82#endif /* LWPKT_CFG_USE_CMD */
 83        data, strlen(data));        /* Length of data and actual data */
 84
 85    /*
 86     * LwPKT wrote data to pkt_tx_rb ringbuffer
 87     * Now actually transmit data over your interface
 88     * (USART for example, ...)
 89     */
 90
 91    /*
 92     * For the purpose of this example, application will
 93     * fake data transmission by doing reading from TX buffer
 94     * and writing it to RX buffer
 95     */
 96    while (lwrb_read(&pkt_tx_rb, &b, 1) == 1) {
 97        lwrb_write(&pkt_rx_rb, &b, 1);
 98    }
 99
100    /*
101     * Here we have our data in RX buffer
102     * means we received data over network interface
103     */
104
105    /* Set callback function */
106    lwpkt_set_evt_fn(&pkt, my_lwpkt_evt_fn);
107
108    /* Now call process function instead */
109    time = 100; /* Get_current_time_in_milliseconds */
110    lwpkt_process(&pkt, time);
111
112    (void)res;
113}