Tool Libs
UMIT-TIROL Institute of Automation and Control Engineering library collection
 
Loading...
Searching...
No Matches
min.h
Go to the documentation of this file.
1
5#pragma once
6#include "frameregistry.h"
7
8#include <stdint.h>
9#include <utils/queue.h>
10
12struct CRC32 {
14 uint32_t checksum{0xffffffff};
16 void init() {
17 *this = CRC32{};
18 }
20 void step(uint8_t byte) {
21 checksum ^= byte;
22 for (uint32_t j = 0; j < 8; j++) {
23 uint32_t mask = (uint32_t) -(checksum & 1U);
24 checksum = (checksum >> 1) ^ (0xedb88320U & mask);
25 }
26 }
28 uint32_t finalize() {
29 return ~checksum;
30 }
31};
32
34struct Min {
35 // Special protocol bytes
36 enum {
37 HEADER_BYTE = 0xaaU,
38 STUFF_BYTE = 0x55U,
39 EOF_BYTE = 0x55U,
40 };
63 class In : public Source<Frame> {
64 CRC32 crc{};
65 Frame frame{};
66 Queue<Frame> queue{20};
68 uint8_t header_seen{0}, frame_length{0};
69 uint32_t frame_crc{0};
70 // Receiving state machine
71 enum State {
72 SEARCHING_FOR_SOF,
73 RECEIVING_ID_CONTROL,
74 RECEIVING_SEQ,
75 RECEIVING_LENGTH,
76 RECEIVING_PAYLOAD,
77 RECEIVING_CHECKSUM_3,
78 RECEIVING_CHECKSUM_2,
79 RECEIVING_CHECKSUM_1,
80 RECEIVING_CHECKSUM_0,
81 RECEIVING_EOF,
82 } state {};
83 void byte(uint8_t b) {
84 // three header bytes always mean "start of frame" and will
85 // reset the frame buffer and be ready to receive frame data
86 //
87 // two in a row during the frame means to expect a stuff byte.
88
89 if (header_seen == 2) {
90 header_seen = 0;
91 if (b == HEADER_BYTE) {
92 state = RECEIVING_ID_CONTROL;
93 return;
94 }
95 if (b == STUFF_BYTE) {
96 // discard this byte
97 return;
98 } else {
99 // something has gone wrong, give up
100 state = SEARCHING_FOR_SOF;
101 return;
102 }
103 }
104
105 if (b == HEADER_BYTE) {
106 header_seen++;
107 } else {
108 header_seen = 0;
109 }
110
111 switch (state) {
112 case SEARCHING_FOR_SOF:
113 // handled at the header byte site
114 break;
115 case RECEIVING_ID_CONTROL:
116 frame.id = b & (uint8_t) 0x3fU;
117 frame.b.len = 0;
118 crc.init();
119 crc.step(b);
120 state = RECEIVING_LENGTH;
121 break;
122 case RECEIVING_LENGTH:
123 frame_length = b;
124 crc.step(b);
125 if (frame_length > 0) {
126 state = RECEIVING_PAYLOAD;
127 } else {
128 state = RECEIVING_CHECKSUM_3;
129 }
130 break;
131 case RECEIVING_PAYLOAD:
132 frame.b.append(b);
133 crc.step(b);
134 if (--frame_length == 0) {
135 state = RECEIVING_CHECKSUM_3;
136 }
137 break;
138 case RECEIVING_CHECKSUM_3:
139 frame_crc = ((uint32_t) b) << 24;
140 state = RECEIVING_CHECKSUM_2;
141 break;
142 case RECEIVING_CHECKSUM_2:
143 frame_crc |= ((uint32_t) b) << 16;
144 state = RECEIVING_CHECKSUM_1;
145 break;
146 case RECEIVING_CHECKSUM_1:
147 frame_crc |= ((uint32_t) b) << 8;
148 state = RECEIVING_CHECKSUM_0;
149 break;
150 case RECEIVING_CHECKSUM_0:
151 frame_crc |= b;
152 if (frame_crc == crc.finalize()) {
153 // Frame received OK, pass up data to handler
154 queue.trypush(std::move(frame));
155 frame = {};
156 }
157 // Either the frame failed, or we already handled it
158 // anyway we can start looking for the next frame,
159 // we don't have to explicitly wait for the EOF
160 state = SEARCHING_FOR_SOF;
161 break;
162 case RECEIVING_EOF:
163 // fallthrough
164 default:
165 state = SEARCHING_FOR_SOF;
166 break;
167 }
168 }
169 public:
171 In(Source<Buffer<uint8_t>> &from) : source{from} { }
173 bool empty() override {
174 while (!queue.full() && !source.empty()) {
175 for (auto b: source.pop()) {
176 byte(b);
177 }
178 }
179 return queue.empty();
180 }
181
186 Frame pop() override {
187 return queue.pop();
188 }
189 void *operator new(size_t sz, In *where) {
190 return where;
191 }
192 };
208 class Out : public Sink<Frame> {
209 CRC32 crc{};
210 Buffer<uint8_t> req = 128;
212 uint8_t header_countdown = 2;
213 void stuff(uint8_t b) {
214 req.append(b);
215 crc.step(b);
216
217 // See if an additional stuff byte is needed
218 if (b == HEADER_BYTE) {
219 if (--header_countdown == 0) {
220 req.append(STUFF_BYTE);
221 header_countdown = 2U;
222 }
223 } else {
224 header_countdown = 2U;
225 }
226 }
227 void nostuff(uint8_t b) {
228 req.append(b);
229 }
230 public:
232 Out(Sink<Buffer<uint8_t>> &to) : out{to} { }
233 using Sink<Frame>::push;
234 bool full() override {
235 return out.full();
236 }
238 void push(Frame &&f) override {
239 req = 128;
240 crc.init();
241 nostuff(HEADER_BYTE);
242 nostuff(HEADER_BYTE);
243 nostuff(HEADER_BYTE);
244 stuff(f.id);
245 stuff(f.b.len);
246 for (size_t i = 0; i < f.b.len; ++i) {
247 stuff(f.b.at(i));
248 }
249 uint32_t sum = crc.finalize();
250 stuff((uint8_t) ((sum >> 24) & 0xff));
251 stuff((uint8_t) ((sum >> 16) & 0xff));
252 stuff((uint8_t) ((sum >> 8) & 0xff));
253 stuff((uint8_t) ((sum >> 0) & 0xff));
254 nostuff(EOF_BYTE);
255 out.trypush(std::move(req));
256 }
257 void *operator new(size_t sz, Out *where) {
258 return where;
259 }
260 };
268 void poll(uint32_t, uint32_t) {
269 while (!in.empty()) {
270 reg.handle(in.pop());
271 }
272 };
273};
incoming Min stream
Definition min.h:63
Frame pop() override
get available Frame
Definition min.h:186
In(Source< Buffer< uint8_t > > &from)
unwrap given Buffer stream into Frame
Definition min.h:171
bool empty() override
check if Frame available
Definition min.h:173
outgoing Min stream
Definition min.h:208
bool full() override
check if sink is full
Definition min.h:234
Out(Sink< Buffer< uint8_t > > &to)
create Buffer stream wrapper
Definition min.h:232
void push(Frame &&f) override
push Frame through to underlying Buffer stream
Definition min.h:238
simple Buffer backed queue implementation
Definition queue.h:12
T pop() override
remove front of queue and return it
Definition queue.h:65
bool empty() override
check if queue is empty
Definition queue.h:83
bool full() override
return true if queue is full
Definition queue.h:87
Copyright (c) 2023 IACE.
Copyright (c) 2023 IACE.
dynamically allocated, but fixed-size buffer template
Definition buffer.h:18
Buffer & append(T b)
simple append single item
Definition buffer.h:44
size_t len
number of items stored in buffer
Definition buffer.h:21
simple CRC32 implementation
Definition min.h:12
void init()
reinitialize state
Definition min.h:16
uint32_t finalize()
get final CRC32 value
Definition min.h:28
void step(uint8_t byte)
calculate step with given byte
Definition min.h:20
uint32_t checksum
state
Definition min.h:14
Registry for dispatching frames to their registered destinations.
Definition frameregistry.h:61
void handle(Frame &&f)
handle given Frame and consume it
Definition frameregistry.h:108
pyWisp communication frame
Definition frameregistry.h:10
Buffer< uint8_t > b
buffer containing the Frame payload
Definition frameregistry.h:12
uint8_t id
buffer id: [0..63]
Definition frameregistry.h:14
full min-based connection wrapper
Definition min.h:34
void poll(uint32_t, uint32_t)
dispatch incoming Frames through registry
Definition min.h:268
Out out
outgoing Frame stream
Definition min.h:264
In in
incoming Frame stream
Definition min.h:262
FrameRegistry reg
Frame registry for this connection.
Definition min.h:266
generic object sink, i.e.
Definition streams.h:15
virtual bool full()=0
check if sink is full
void trypush(T &&t)
use this if you don't care if it's going to be successful. data gets discarded if sink is full.
Definition streams.h:28
generic object source, i.e.
Definition streams.h:40
virtual T pop()=0
pull object from source does not check for data. guard by using 'if (!empty) { ......
virtual bool empty()=0
check if source is empty