Skip to content

Commit 8ecee21

Browse files
Arduhdlc first version.
1 parent b6544a7 commit 8ecee21

File tree

4 files changed

+384
-1
lines changed

4 files changed

+384
-1
lines changed

Arduhdlc.cpp

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
Arduhdlc is Arduino HDLC library, which can be used over any interface.
3+
Copyright (C) 2015 Jarkko Hautakorpi et al. see LICENSE.txt
4+
5+
This program is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU General Public License
7+
as published by the Free Software Foundation; either version 2
8+
of the License, or (at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18+
*/
19+
20+
#include "Arduino.h"
21+
#include "Arduhdlc.h"
22+
23+
/* HDLC Asynchronous framing */
24+
/* The frame boundary octet is 01111110, (7E in hexadecimal notation) */
25+
#define FRAME_BOUNDARY_OCTET 0x7E
26+
27+
/* A "control escape octet", has the bit sequence '01111101', (7D hexadecimal) */
28+
#define CONTROL_ESCAPE_OCTET 0x7D
29+
30+
/* If either of these two octets appears in the transmitted data, an escape octet is sent, */
31+
/* followed by the original data octet with bit 5 inverted */
32+
#define INVERT_OCTET 0x20
33+
34+
/* The frame check sequence (FCS) is a 16-bit CRC-CCITT */
35+
/* AVR Libc CRC function is _crc_ccitt_update() */
36+
/* Corresponding CRC function in Qt (www.qt.io) is qChecksum() */
37+
#define CRC16_CCITT_INIT_VAL 0xFFFF
38+
39+
/* 16bit low and high bytes copier */
40+
#define low(x) ((x) & 0xFF)
41+
#define high(x) (((x)>>8) & 0xFF)
42+
43+
Arduhdlc::Arduhdlc (sendchar_type put_char, frame_handler_type hdlc_command_router, uint16_t max_frame_length) : sendchar_function(put_char), frame_handler(hdlc_command_router)
44+
{
45+
this->frame_position = 0;
46+
this->max_frame_length = max_frame_length;
47+
this->receive_frame_buffer = (uint8_t *)malloc(max_frame_length+1); // char *ab = (char*)malloc(12);
48+
this->frame_checksum = CRC16_CCITT_INIT_VAL;
49+
this->escape_character = false;
50+
}
51+
52+
/* Function to send a byte throug USART, I2C, SPI etc.*/
53+
void Arduhdlc::sendchar(uint8_t data)
54+
{
55+
(*this->sendchar_function)(data);
56+
}
57+
58+
/* Function to find valid HDLC frame from incoming data */
59+
void Arduhdlc::charReceiver(uint8_t data)
60+
{
61+
/* FRAME FLAG */
62+
if(data == FRAME_BOUNDARY_OCTET)
63+
{
64+
if(this->escape_character == true)
65+
{
66+
this->escape_character = false;
67+
}
68+
/* If a valid frame is detected */
69+
else if( (this->frame_position >= 2) &&
70+
( this->frame_checksum == ((this->receive_frame_buffer[this->frame_position-1] << 8 ) | (this->receive_frame_buffer[this->frame_position-2] & 0xff)) ) ) // (msb << 8 ) | (lsb & 0xff)
71+
{
72+
/* Call the user defined function and pass frame to it */
73+
(*frame_handler)(receive_frame_buffer,(uint8_t)(this->frame_position-2));
74+
}
75+
this->frame_position = 0;
76+
this->frame_checksum = CRC16_CCITT_INIT_VAL;
77+
return;
78+
}
79+
80+
if(this->escape_character)
81+
{
82+
this->escape_character = false;
83+
data ^= INVERT_OCTET;
84+
}
85+
else if(data == CONTROL_ESCAPE_OCTET)
86+
{
87+
this->escape_character = true;
88+
return;
89+
}
90+
91+
receive_frame_buffer[this->frame_position] = data;
92+
93+
if(this->frame_position-2 >= 0) {
94+
this->frame_checksum = _crc_ccitt_update(this->frame_checksum, receive_frame_buffer[this->frame_position-2]);
95+
}
96+
97+
this->frame_position++;
98+
99+
if(this->frame_position == this->max_frame_length)
100+
{
101+
this->frame_position = 0;
102+
this->frame_checksum = CRC16_CCITT_INIT_VAL;
103+
}
104+
}
105+
106+
/* Wrap given data in HDLC frame and send it out byte at a time*/
107+
void Arduhdlc::frameDecode(const char *framebuffer, uint8_t frame_length)
108+
{
109+
uint8_t data;
110+
uint16_t fcs = CRC16_CCITT_INIT_VAL;
111+
112+
this->sendchar((uint8_t)FRAME_BOUNDARY_OCTET);
113+
114+
while(frame_length)
115+
{
116+
data = *framebuffer++;
117+
fcs = _crc_ccitt_update(fcs, data);
118+
if((data == CONTROL_ESCAPE_OCTET) || (data == FRAME_BOUNDARY_OCTET))
119+
{
120+
this->sendchar((uint8_t)CONTROL_ESCAPE_OCTET);
121+
data ^= INVERT_OCTET;
122+
}
123+
this->sendchar((uint8_t)data);
124+
frame_length--;
125+
}
126+
data = low(fcs);
127+
if((data == CONTROL_ESCAPE_OCTET) || (data == FRAME_BOUNDARY_OCTET))
128+
{
129+
this->sendchar((uint8_t)CONTROL_ESCAPE_OCTET);
130+
data ^= (uint8_t)INVERT_OCTET;
131+
}
132+
this->sendchar((uint8_t)data);
133+
data = high(fcs);
134+
if((data == CONTROL_ESCAPE_OCTET) || (data == FRAME_BOUNDARY_OCTET))
135+
{
136+
this->sendchar(CONTROL_ESCAPE_OCTET);
137+
data ^= INVERT_OCTET;
138+
}
139+
this->sendchar(data);
140+
this->sendchar(FRAME_BOUNDARY_OCTET);
141+
}
142+
143+

Arduhdlc.h

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef arduhdlc_h
2+
#define arduhdlc_h
3+
4+
#include "Arduino.h"
5+
#include <stdint.h>
6+
#include <stdbool.h>
7+
#include <util/crc16.h>
8+
9+
typedef void (* sendchar_type) (uint8_t);
10+
typedef void (* frame_handler_type)(const uint8_t *framebuffer, uint16_t framelength);
11+
12+
class Arduhdlc
13+
{
14+
public:
15+
Arduhdlc (sendchar_type, frame_handler_type, uint16_t max_frame_length);
16+
void charReceiver(uint8_t data);
17+
void frameDecode(const char *framebuffer, uint8_t frame_length);
18+
19+
private:
20+
/* User must define a function, that sends a 8bit char over the chosen interface, usart, spi, i2c etc. */
21+
sendchar_type sendchar_function;
22+
/* User must define a function, that will process the valid received frame */
23+
/* This function can act like a command router/dispatcher */
24+
frame_handler_type frame_handler;
25+
void sendchar(uint8_t data);
26+
27+
bool escape_character;
28+
uint8_t * receive_frame_buffer;
29+
uint8_t frame_position;
30+
// 16bit CRC sum for _crc_ccitt_update
31+
uint16_t frame_checksum;
32+
uint16_t max_frame_length;
33+
};
34+
35+
#endif

LICENSE.txt

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
Arduhdlc is Arduino HDLC library, which can be used over any interface.
2+
Copyright (C) 2015 Jarkko Hautakorpi
3+
4+
This program is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU General Public License
6+
as published by the Free Software Foundation; either version 2
7+
of the License, or (at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
18+
19+
20+
21+
Licese applies to work derived from Dust SmartMeshSDK C Library:
22+
=============================================================================
23+
Copyright (c) 2012, Dust Networks
24+
All rights reserved.
25+
26+
Redistribution and use in source and binary forms, with or without
27+
modification, are permitted provided that the following conditions are met:
28+
* Redistributions of source code must retain the above copyright
29+
notice, this list of conditions and the following disclaimer.
30+
* Redistributions in binary form must reproduce the above copyright
31+
notice, this list of conditions and the following disclaimer in the
32+
documentation and/or other materials provided with the distribution.
33+
* Neither the name of Dust Networks nor the
34+
names of its contributors may be used to endorse or promote products
35+
derived from this software without specific prior written permission.
36+
37+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
38+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40+
DISCLAIMED. IN NO EVENT SHALL DUST NETWORKS BE LIABLE FOR ANY
41+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47+
48+
49+
50+
51+
Licese applies to work derived from Piconomic FW Library:
52+
=============================================================================
53+
Copyright (c) 2006 Pieter Conradie [www.piconomic.co.za]
54+
All rights reserved.
55+
56+
Redistribution and use in source and binary forms, with or without
57+
modification, are permitted provided that the following conditions are met:
58+
59+
* Redistributions of source code must retain the above copyright
60+
notice, this list of conditions and the following disclaimer.
61+
62+
* Redistributions in binary form must reproduce the above copyright
63+
notice, this list of conditions and the following disclaimer in
64+
the documentation and/or other materials provided with the
65+
distribution.
66+
67+
* Neither the name of the copyright holders nor the names of
68+
contributors may be used to endorse or promote products derived
69+
from this software without specific prior written permission.
70+
71+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
72+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
73+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
74+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
75+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
76+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
77+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
78+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
79+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
80+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
81+
POSSIBILITY OF SUCH DAMAGE.
82+
83+
Title: HDLC encapsulation layer
84+
Author(s): Pieter Conradie
85+
Creation Date: 2007-03-31
86+
Revision Info: $Id: hdlc.h 117 2010-06-24 20:21:28Z pieterconradie $
87+
88+
89+
90+
91+
Licese applies to work derived from HDLC byte stuffing package:
92+
=============================================================================
93+
/*****************************************************
94+
* HDLC byte stuffing package *
95+
* *
96+
* Created on: Dec 2013 *
97+
* Author: jdn *
98+
* *
99+
******************************************************
100+
* *
101+
* *
102+
* (C) 2012,2013 *
103+
* *
104+
* Jens Dalsgaard Nielsen <[email protected]> *
105+
* http://www.control.aau.dk/~jdn *
106+
* Studentspace/Satlab *
107+
* Section of Automation & Control *
108+
* Aalborg University, *
109+
* Denmark *
110+
* *
111+
* "THE BEER-WARE LICENSE" (frit efter PHK) *
112+
* <[email protected]> wrote this file. As long as you *
113+
* retain this notice you can do whatever you want *
114+
* with this stuff. If we meet some day, and you think*
115+
* this stuff is worth it ... *
116+
* you can buy me a beer in return :-) *
117+
* or if you are real happy then ... *
118+
* single malt will be well received :-) *
119+
* *
120+
* Use it at your own risk - no warranty *
121+
*****************************************************/

README.md

+85-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,86 @@
11
# Arduhdlc
2-
Simple Arduino HDLC library
2+
3+
ArduHDLC is a *Simple Arduino HDLC library*. It can be used over any interface like USART, SPI, CAN or I2C.
4+
Library only has two functions, validate incoming HDLC frame and wrap data in HDLC packet.
5+
The HDLC frame structure is up to the user to define and decide.
6+
7+
## Minimum requirements
8+
To use the library, user must pass all incoming data to charReceiver() function, and define two functions:
9+
1. Function to send HDLC frame out, one byte at a time.
10+
2. Function to handle/receive a valid HDLC frame
11+
12+
When HDLC frame is being built around user data (say, "ABCD"), user defined function is called for each byte of the frame. For "ABCD" 8 bytes are sent out, frame being "\~ABCD??~" where the two characters before end flag ~ are two non printable bytes/characters from 16bit CRC function. CRC for "ABCD" is 53965, or 0xCD and 0xD2 in Hexadecimal representation.
13+
14+
HDLC frame containing "ABCD":
15+
16+
```cpp
17+
packet "~ABCDÍÒ~" char
18+
[0] 126 '~' char
19+
[1] 65 'A' char
20+
[2] 66 'B' char
21+
[3] 67 'C' char
22+
[4] 68 'D' char
23+
[5] 205 / 205 char
24+
[6] 210 / 210 char
25+
[7] 126 '~' char
26+
```
27+
28+
When valid HDLC frame is found from input stream, received data and length of the data is passed to user defined function. It is up to the user what to do with this data. For receiving "ABCD" user function gets pointer to the data, and integer 4 indicating that data is 4 bytes long.
29+
30+
## Example usage (serial port)
31+
32+
```cpp
33+
34+
#include "Arduhdlc.h"
35+
#define MAX_HDLC_FRAME_LENGTH 32
36+
/* Function to send out byte/char */
37+
void send_character(uint8_t data);
38+
39+
/* Function to handle a valid HDLC frame */
40+
void hdlc_frame_handler(const uint8_t *data, uint16_t length);
41+
42+
/* Initialize Arduhdlc library with three parameters.
43+
1. Character send function, to send out HDLC frame one byte at a time.
44+
2. HDLC frame handler function for received frame.
45+
3. Length of the longest frame used, to allocate buffer in memory */
46+
Arduhdlc hdlc(&send_character, &hdlc_frame_handler, MAX_HDLC_FRAME_LENGTH);
47+
48+
/* Function to send out one 8bit character */
49+
void send_character(uint8_t data) {
50+
Serial.print((char)data);
51+
}
52+
53+
/* Frame handler function. What to do with received data? */
54+
void hdlc_frame_handler(const uint8_t *data, uint16_t length) {
55+
// Do something with data that is in framebuffer
56+
}
57+
58+
void setup() {
59+
pinMode(1,OUTPUT); // Serial port TX to output
60+
// initialize serial port to 9600 baud
61+
Serial.begin(9600);
62+
}
63+
64+
void loop() {
65+
66+
}
67+
68+
/*
69+
SerialEvent occurs whenever a new data comes in the
70+
hardware serial RX. This routine is run between each
71+
time loop() runs, so using delay inside loop can delay
72+
response. Multiple bytes of data may be available.
73+
*/
74+
void serialEvent() {
75+
while (Serial.available()) {
76+
// get the new byte:
77+
char inChar = (char)Serial.read();
78+
// Pass all incoming data to hdlc char receiver
79+
hdlc.charReceiver(inChar);
80+
}
81+
}
82+
```
83+
84+
85+
Complete example project on sending commands and data, through the serial port from Qt GUI program on PC, to Arduino UNO over HDLC protocol, is available on GitHub.
86+
See: [Qt GUI to Arduino HDLC example](https://github.com/jarkko-hautakorpi/arduhdlc-qt-gui-example)

0 commit comments

Comments
 (0)