LwPKT 1.0.1 documentation¶
Welcome to the documentation for version 1.0.1.
LwPKT is a generic packet protocol library optimized for embedded systems.
Download library Getting started Open Github
Features¶
Written in ANSI C99, compatible with
size_t
for size data typesPlatform independent, no architecture specific code
Uses LwRB library for data read/write operations
Optimized for embedded systems, allows high optimization for data transfer
Configurable settings for packet structure and variable data length
Allows multiple notes in network with from and to addresses
Separate optional field for command data type
Variable data length to support theoretically unlimited packet length
CRC check to handle data transmission errors
User friendly MIT license
Requirements¶
C compiler
Few
kB
of non-volatile memory
Contribute¶
Fresh contributions are always welcome. Simple instructions to proceed:
Fork Github repository
Respect C style & coding rules used by the library
Create a pull request to
develop
branch with new features or bug fixes
Alternatively you may:
Report a bug
Ask for a feature request
License¶
MIT License
Copyright (c) 2020 Tilen MAJERLE
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Table of contents¶
Getting started¶
Download library¶
Library is primarly hosted on Github.
Download latest release from releases area on Github
Clone develop branch for latest development
Download from releases¶
All releases are available on Github releases area.
Clone from Github¶
First-time clone¶
Download and install
git
if not alreadyOpen console and navigate to path in the system to clone repository to. Use command
cd your_path
Clone repository with one of available
3
optionsRun
git clone --recurse-submodules https://github.com/MaJerle/lwpkt
command to clone entire repository, including submodulesRun
git clone --recurse-submodules --branch develop https://github.com/MaJerle/lwpkt
to clone development branch, including submodulesRun
git clone --recurse-submodules --branch master https://github.com/MaJerle/lwpkt
to clone latest stable branch, including submodules
Navigate to
examples
directory and run favourite example
Update cloned to latest version¶
Open console and navigate to path in the system where your resources repository is. Use command
cd your_path
Run
git pull origin master --recurse-submodules
command to pull latest changes and to fetch latest changes from submodulesRun
git submodule foreach git pull origin master
to update & merge all submodules
Note
This is preferred option to use when you want to evaluate library and run prepared examples. Repository consists of multiple submodules which can be automatically downloaded when cloning and pulling changes from root repository.
Add library to project¶
At this point it is assumed that you have successfully download library, either cloned it or from releases page.
Copy
lwpkt
folder to your projectAdd
lwpkt/src/include
folder to include path of your toolchainAdd
libs/lwrb/src/include
folder to include path of your toolchainAdd source files from
lwpkt/src/
folder to toolchain buildAdd source files from
libs/lwrb/src/
folder to toolchain buildBuild the project
Configuration file¶
Library comes with template config file, which can be modified according to needs.
This file shall be named lwpkt_opts.h
and its default template looks like the one below.
Note
Default configuration template file location: lwpkt/src/include/lwpkt/lwpkt_opts_template.h
.
File must be renamed to lwpkt_opts.h
first and then copied to the project directory (or simply renamed in-place) where compiler
include paths have access to it by using #include "lwpkt_opts.h"
.
Tip
Check Configuration section for possible configuration settings
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 | /**
* \file lwpkt_opts_template.h
* \brief LwPKT configuration file
*/
/*
* Copyright (c) 2020 Tilen MAJERLE
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* This file is part of LwPKT - Lightweight packet protocol library.
*
* Author: Tilen MAJERLE <tilen@majerle.eu>
* Version: v1.0.1
*/
#ifndef LWPKT_HDR_OPTS_H
#define LWPKT_HDR_OPTS_H
/* Rename this file to "lwpkt_opts.h" for your application */
/*
* Open "include/lwpkt/lwpkt_opt.h" and
* copy & replace here settings you want to change values
*/
#endif /* LWPKT_HDR_OPTS_H */
|
Minimal example code¶
Run below example to test and verify library
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 108 109 110 111 | #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 example code
*/
void
example_lwpkt(void) {
lwpktr_t res;
uint8_t b;
printf("---\r\nLwPKT default example..\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 read and process packet */
res = lwpkt_read(&pkt);
if (res == lwpktVALID) {
size_t len;
/* 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));
if ((len = lwpkt_get_data_len(&pkt)) > 0) {
uint8_t* d = lwpkt_get_data(&pkt);
printf("Packet data: ");
for (size_t i = 0; i < len; ++i) {
printf("0x%02X ", (unsigned)d[i]);
}
printf("\r\n");
}
/* Check who should be dedicated receiver */
#if LWPKT_CFG_USE_ADDR
if (lwpkt_is_for_me(&pkt)) {
printf("Packet is for me\r\n");
} else if (lwpkt_is_broadcast(&pkt)) {
printf("Packet is broadcast to all devices\r\n");
} else {
printf("Packet is for device ID: 0x%02X\r\n", (unsigned)lwpkt_get_to_addr(&pkt));
}
#endif /* LWPKT_CFG_USE_ADDR */
} else if (res == lwpktINPROG) {
printf("Packet is still in progress, did not receive yet all bytes..\r\n");
} else {
printf("Packet is not valid!\r\n");
}
}
|
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 from where this packet is coming from. Optional field, can be disabled withLWPKT_CFG_USE_ADDR
TO
: Byte 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
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 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);
}
|
API reference¶
List of all the modules:
LwPKT¶
-
group
LWPKT
Lightweight packet protocol.
Defines
-
lwpkt_get_from_addr
(pkt)¶ Get address from where packet was sent.
- Return
Address
- Parameters
[in] pkt
: LwPKT instance
-
lwpkt_get_to_addr
(pkt)¶ Get address to where packet was sent.
- Return
Address
- Parameters
[in] pkt
: LwPKT instance
-
lwpkt_get_data_len
(pkt)¶ Get length of packet.
- Return
Number of data bytes in packet
- Parameters
[in] pkt
: LwPKT instance
-
lwpkt_get_data
(pkt)¶ Get pointer to packet data.
- Return
Pointer to data
- Parameters
[in] pkt
: LwPKT instance
-
lwpkt_get_cmd
(pkt)¶ Get packet command data field.
- Return
Command data field
- Parameters
[in] pkt
: LwPKT instance
-
lwpkt_is_for_me
(pkt)¶ Check if packet
to
field address matches device address.- Return
1
on success,0
otherwise- Parameters
[in] pkt
: LwPKT instance
-
lwpkt_is_broadcast
(pkt)¶ Check if packet was sent to all devices on network.
- Return
1
if broadcast,0
otherwise- Parameters
[in] pkt
: LwPKT instance
Typedefs
-
typedef void (*
lwpkt_evt_fn
)(lwpkt_t *pkt, lwpkt_evt_type_t type)¶ LwPKT event function.
- Parameters
[in] pkt
: LwPKT instance with valid packet[in] type
: Event type
Enums
-
enum
lwpkt_state_t
¶ Packet state enumeration.
Values:
-
enumerator
LWPKT_STATE_START
¶ Packet waits for start byte
-
enumerator
LWPKT_STATE_FROM
¶ Packet waits for “packet from” byte
-
enumerator
LWPKT_STATE_TO
¶ Packet waits for “packet to” byte
-
enumerator
LWPKT_STATE_CMD
¶ Packet waits for “packet cmd” byte
-
enumerator
LWPKT_STATE_LEN
¶ Packet waits for (multiple) data length bytes
-
enumerator
LWPKT_STATE_DATA
¶ Packet waits for actual data bytes
-
enumerator
LWPKT_STATE_CRC
¶ Packet waits for CRC data
-
enumerator
LWPKT_STATE_STOP
¶ Packet waits for stop byte
-
enumerator
-
enum
lwpktr_t
¶ Packet result enumeration.
Values:
-
enumerator
lwpktOK
¶ Function returns successfully
-
enumerator
lwpktERR
¶ General error for function status
-
enumerator
lwpktINPROG
¶ Receive is in progress
-
enumerator
lwpktVALID
¶ packet valid and ready to be read as CRC is valid and STOP received
-
enumerator
lwpktERRCRC
¶ CRC integrity error for the packet. Will not wait STOP byte if received
-
enumerator
lwpktERRSTOP
¶ Packet error with STOP byte, wrong character received for STOP
-
enumerator
lwpktWAITDATA
¶ Packet state is in start mode, waiting start byte to start receiving
-
enumerator
Functions
-
lwpktr_t lwpkt_init (lwpkt_t *pkt, LWRB_VOLATILE lwrb_t *tx_rb, LWRB_VOLATILE lwrb_t *rx_rb)
Initialize packet instance and set device address.
-
lwpktr_t
lwpkt_read
(lwpkt_t *pkt)¶ Read raw data from RX buffer and prepare packet.
- Return
lwpktVALID when packet valid, member of lwpktr_t otherwise
- Parameters
[in] pkt
: Packet instance
-
lwpktr_t
lwpkt_write
(lwpkt_t *pkt, uint8_t to, uint8_t cmd, const void *data, size_t len)¶ Write packet data to TX ringbuffer.
-
lwpktr_t
lwpkt_process
(lwpkt_t *pkt, uint32_t time, lwpkt_evt_fn evt_fn)¶ Process packet instance and read new data.
-
struct
lwpkt_crc_t
¶ - #include <lwpkt.h>
CRC structure for packet.
Public Members
-
uint8_t
crc
¶ Current CRC value
-
uint8_t
-
struct
lwpkt_t
¶ - #include <lwpkt.h>
Packet structure.
Public Members
-
uint8_t
addr
¶ Current device address
-
uint8_t
data
[LWPKT_CFG_MAX_DATA_LEN
]¶ Memory to write received data
-
LWRB_VOLATILE lwrb_t * tx_rb
TX ringbuffer
-
LWRB_VOLATILE lwrb_t * rx_rb
RX ringbuffer
-
uint32_t
last_rx_time
¶ Last RX time in units of milliseconds
-
lwpkt_state_t
state
¶ Actual packet state machine
-
lwpkt_crc_t
crc
¶ Packet CRC byte
-
uint8_t
from
¶ Device address packet is coming from
-
uint8_t
to
¶ Device address packet is intended for
-
uint8_t
cmd
¶ Command packet
-
size_t
len
¶ Number of bytes to receive
-
size_t
index
¶ General index variable for multi-byte parts of packet
-
uint8_t
-
Configuration¶
This is the default configuration of the middleware.
When any of the settings shall be modified, it shall be done in dedicated application config lwpkt_opts.h
file.
Note
Check Getting started for guidelines on how to create and use configuration file.
-
group
LWPKT_OPT
Default configuration setup.
Defines
-
LWPKT_CFG_MAX_DATA_LEN
¶ Maximum length of
data
part of the packet in units of bytes.
-
LWPKT_CFG_ADDR_BROADCAST
¶ Address identifying broadcast message to all devices.
-
LWPKT_CFG_USE_ADDR
¶ Enables
1
or disables0
from
andto
fields in the protocol.This features is useful if communication is between 2 devices exclusively, without addressing requirements
-
LWPKT_CFG_USE_CMD
¶ Enables
1
or disables0
cmd
field in the protocol.When disabled, command part is not used
-
LWPKT_CFG_USE_CRC
¶ Enables
1
or disables0
CRC check in the protocol.
-
LWPKT_CFG_PROCESS_INPROG_TIMEOUT
¶ Defines timeout time before packet is considered as not valid when too long time in data-read mode.
Used with lwpkt_process function
-