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 from where this packet is coming from. Optional field, can be disabled with LWPKT_CFG_USE_ADDR

  • TO: Byte 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

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
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
#include <stdio.h>
#include "lwpkt/lwpkt.h"

/* LwPKT data */
static lwpkt_t pkt;
static lwrb_t pkt_tx_rb, pkt_rx_rb;
static uint8_t pkt_tx_rb_data[64], pkt_rx_rb_data[64];

/* Data to read and write */
static const char* data = "Hello World\r\n";

/**
 * \brief           LwPKT application callback
 */
static void
my_lwpkt_evt_fn(lwpkt_t* pkt, lwpkt_evt_type_t type) {
    switch (type) {
        case LWPKT_EVT_PKT: {
            size_t len;

            printf("Valid packet received..\r\n");

            /* Packet is valid */
            printf("Packet is valid!\r\n");

            /* Print debug messages for packet */
#if LWPKT_CFG_USE_ADDR
            printf("Packet from: 0x%02X\r\n", (unsigned)lwpkt_get_from_addr(pkt));
            printf("Packet to: 0x%02X\r\n", (unsigned)lwpkt_get_to_addr(pkt));
#endif /* LWPKT_CFG_USE_ADDR */
#if LWPKT_CFG_USE_CMD
            printf("Packet cmd: 0x%02X\r\n", (unsigned)lwpkt_get_cmd(pkt));
#endif /* LWPKT_CFG_USE_CMD */
            printf("Packet data length: 0x%02X\r\n", (unsigned)lwpkt_get_data_len(pkt));

            /* Do other thins... */
            break;
        }
        case LWPKT_EVT_TIMEOUT: {
            printf("Timeout detected during read operation..\r\n");
            break;
        }
    }
}

/**
 * \brief           LwPKT example code with event feature
 */
void
example_lwpkt_evt(void) {
    lwpktr_t res;
    uint32_t time;
    uint8_t b;

    printf("---\r\nLwPKT event type..\r\n\r\n");

    /* 
     * Initialize both ring buffers, for TX and RX operations
     *
     * Initialize LwPKT and link buffers together
     */
    lwrb_init(&pkt_tx_rb, pkt_tx_rb_data, sizeof(pkt_tx_rb_data));
    lwrb_init(&pkt_rx_rb, pkt_rx_rb_data, sizeof(pkt_rx_rb_data));
    lwpkt_init(&pkt, &pkt_tx_rb, &pkt_rx_rb);

#if LWPKT_CFG_USE_ADDR
    /* Set device address (if feature enabled) */
    lwpkt_set_addr(&pkt, 0x12);
#endif /* LWPKT_CFG_USE_ADDR */

    /* 
     * Write packet to the TX ringbuffer,
     * act as device wants to send some data
     */
    res = lwpkt_write(&pkt,
#if LWPKT_CFG_USE_ADDR
        0x11,                       /* End address to whom to send */
#endif /* LWPKT_CFG_USE_ADDR */
#if LWPKT_CFG_USE_CMD
        0x85,                       /* Command type */
#endif /* LWPKT_CFG_USE_CMD */
        data, strlen(data));        /* Length of data and actual data */

    /*
     * LwPKT wrote data to pkt_tx_rb ringbuffer
     * Now actually transmit data over your interface
     * (USART for example, ...)
     */

    /*
     * For the purpose of this example, application will
     * fake data transmission by doing reading from TX buffer
     * and writing it to RX buffer
     */
    while (lwrb_read(&pkt_tx_rb, &b, 1) == 1) {
        lwrb_write(&pkt_rx_rb, &b, 1);
    }

    /*
     * Here we have our data in RX buffer
     * means we received data over network interface
     */

    /* Now call process function instead */
    time = 100; /* Get_current_time_in_milliseconds */
    lwpkt_process(&pkt, time, my_lwpkt_evt_fn);
}