TinyPPP
PPP networking over any Arduino Stream
Loading...
Searching...
No Matches
HDLC.h
Go to the documentation of this file.
1#pragma once
6#include <stddef.h>
7#include <stdint.h>
8
9#include <Arduino.h>
10
11namespace tinyppp {
12
13static constexpr uint8_t HDLC_FLAG = 0x7E;
14static constexpr uint8_t HDLC_ESCAPE = 0x7D;
15static constexpr uint8_t HDLC_XOR = 0x20;
16static constexpr uint8_t HDLC_ALL_STATIONS = 0xFF;
17static constexpr uint8_t HDLC_UI = 0x03;
18static constexpr uint16_t FCS16_INIT = 0xFFFF;
19static constexpr uint16_t FCS16_GOOD = 0xF0B8;
20
22inline uint16_t fcs16Update(uint16_t fcs, uint8_t b) {
23 static const uint16_t table[16] = {
24 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387,
25 0x8408, 0x9489, 0xA50A, 0xB58B, 0xC60C, 0xD68D, 0xE70E, 0xF78F};
26 fcs = (fcs >> 4) ^ table[(fcs ^ b) & 0x0F];
27 fcs = (fcs >> 4) ^ table[(fcs ^ (b >> 4)) & 0x0F];
28 return fcs;
29}
30
32inline uint16_t fcs16(const uint8_t *data, size_t len,
33 uint16_t fcs = FCS16_INIT) {
34 for (size_t i = 0; i < len; i++) fcs = fcs16Update(fcs, data[i]);
35 return fcs;
36}
37
45 public:
47 void setOutput(Print *out) { _out = out; }
48
50 void setACCM(uint32_t accm) { _accm = accm; }
51
53 void begin(uint16_t protocol, bool escapeAllControl = false) {
54 _escapeAll = escapeAllControl;
55 _fcs = FCS16_INIT;
56 _len = 0;
57 _ok = _out != nullptr;
58 put(HDLC_FLAG);
61 data(protocol >> 8);
62 data(protocol & 0xFF);
63 }
64
66 void data(uint8_t b) {
67 _fcs = fcs16Update(_fcs, b);
68 stuffed(b);
69 }
70
72 void data(const uint8_t *buf, size_t len) {
73 for (size_t i = 0; i < len; i++) data(buf[i]);
74 }
75
77 bool end() {
78 uint16_t fcs = ~_fcs;
79 stuffed(fcs & 0xFF);
80 stuffed(fcs >> 8);
81 put(HDLC_FLAG);
82 flush();
83 return _ok;
84 }
85
86 private:
87 Print *_out = nullptr;
88 uint32_t _accm = 0xFFFFFFFF;
89 bool _escapeAll = true;
90 bool _ok = false;
91 uint16_t _fcs = FCS16_INIT;
92 uint8_t _buf[256];
93 size_t _len = 0;
94
95 void stuffed(uint8_t b) {
96 bool esc = b == HDLC_FLAG || b == HDLC_ESCAPE ||
97 (b < 0x20 && (_escapeAll || (_accm & (1UL << b))));
98 if (esc) {
99 put(HDLC_ESCAPE);
100 put(b ^ HDLC_XOR);
101 } else {
102 put(b);
103 }
104 }
105
106 void put(uint8_t b) {
107 if (_len == sizeof(_buf)) flush();
108 _buf[_len++] = b;
109 }
110
111 void flush() {
112 if (_len == 0) return;
113 if (_out == nullptr) {
114 // no output: drop the data (the buffer must be emptied in any case)
115 _ok = false;
116 _len = 0;
117 return;
118 }
119 size_t written = 0;
120 // some cores return partial writes: retry a few times
121 for (int retry = 0; retry < 50 && written < _len; retry++) {
122 written += _out->write(_buf + written, _len - written);
123 }
124 if (written < _len) _ok = false;
125 _len = 0;
126 }
127};
128
136template <size_t MAX_FRAME>
138 public:
140 bool add(uint8_t b) {
141 if (b == HDLC_FLAG) {
142 bool result = false;
143 if (_len >= 4 && !_overflow) {
144 if (fcs16(_buf, _len) == FCS16_GOOD) {
145 result = true;
146 _frameLen = _len - 2;
147 } else {
148 _fcsErrors++;
149 }
150 }
151 _len = 0;
152 _escape = false;
153 _overflow = false;
154 return result;
155 }
156 if (b == HDLC_ESCAPE) {
157 _escape = true;
158 return false;
159 }
160 if (_escape) {
161 b ^= HDLC_XOR;
162 _escape = false;
163 }
164 if (_len < sizeof(_buf)) {
165 _buf[_len++] = b;
166 } else {
167 _overflow = true;
168 }
169 return false;
170 }
171
173 uint8_t *frame() { return _buf; }
175 size_t frameLen() const { return _frameLen; }
177 uint32_t fcsErrors() const { return _fcsErrors; }
178
179 private:
180 uint8_t _buf[MAX_FRAME + 2];
181 size_t _len = 0;
182 size_t _frameLen = 0;
183 uint32_t _fcsErrors = 0;
184 bool _escape = false;
185 bool _overflow = false;
186};
187
188} // namespace tinyppp
HDLC frame decoder (RFC 1662).
Definition HDLC.h:137
uint32_t fcsErrors() const
Number of frames dropped because of a wrong FCS.
Definition HDLC.h:177
uint8_t * frame()
Frame content without FCS (address/control included if sent)
Definition HDLC.h:173
bool add(uint8_t b)
Feed one byte: returns true when a valid frame is available.
Definition HDLC.h:140
size_t frameLen() const
Length of the frame returned by frame()
Definition HDLC.h:175
HDLC frame encoder (RFC 1662).
Definition HDLC.h:44
void data(const uint8_t *buf, size_t len)
Adds payload bytes.
Definition HDLC.h:72
void data(uint8_t b)
Adds one payload byte.
Definition HDLC.h:66
void begin(uint16_t protocol, bool escapeAllControl=false)
Starts a frame with address/control header and the protocol number.
Definition HDLC.h:53
void setOutput(Print *out)
Defines the output (e.g. the serial port)
Definition HDLC.h:47
void setACCM(uint32_t accm)
Async-Control-Character-Map of the peer: control chars to escape.
Definition HDLC.h:50
bool end()
Appends FCS and closing flag; returns false if the output dropped bytes.
Definition HDLC.h:77
TinyPPP internals: PPP engine, HDLC framing and the IP stack.
Definition HDLC.h:11
static constexpr uint8_t HDLC_ESCAPE
Definition HDLC.h:14
static constexpr uint16_t FCS16_GOOD
Definition HDLC.h:19
static constexpr uint16_t FCS16_INIT
Definition HDLC.h:18
uint16_t fcs16(const uint8_t *data, size_t len, uint16_t fcs=FCS16_INIT)
FCS-16 over a buffer (continues from fcs)
Definition HDLC.h:32
static constexpr uint8_t HDLC_XOR
Definition HDLC.h:15
uint16_t fcs16Update(uint16_t fcs, uint8_t b)
Incremental FCS-16 (RFC 1662, reflected CRC-CCITT) using a nibble table.
Definition HDLC.h:22
static constexpr uint8_t HDLC_FLAG
Definition HDLC.h:13
static constexpr uint8_t HDLC_ALL_STATIONS
Definition HDLC.h:16
static constexpr uint8_t HDLC_UI
Definition HDLC.h:17