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
START
: Byte with fixed value to represent start of packetFROM
: Byte(s) from where this packet is coming from. Optional field, can be disabled withLWPKT_CFG_USE_ADDR
TO
: Byte(s) to where this packet is targeting. Optional field, can be disabled withLWPKT_CFG_USE_ADDR
CMD
: Byte with optional command field to better align with multiple packets. Optional field, can be disabled withLWPKT_CFG_USE_CMD
LEN
: Length of data part field. This is variable multi-byte length to support data length>= 256
bytes. Always presentDATA
: Optional data field. Number of bytes is as inLEN
fieldCRC
: 8-bit CRC of all enabled fields except START and STOP bytes. Optional field, can be disabled withLWPKT_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:
DATA
field is always enabledFROM
andTO
fields whenLWPKT_CFG_ADDR_EXTENDED
feature is enabled
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.
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}