|
@@ -228,37 +228,41 @@ public:
|
228
|
228
|
PACKET_PROCESS, PACKET_RESEND, PACKET_TIMEOUT, PACKET_ERROR };
|
229
|
229
|
|
230
|
230
|
struct Packet { // 10 byte protocol overhead, ascii with checksum and line number has a minimum of 7 increasing with line
|
231
|
|
- struct [[gnu::packed]] Header {
|
232
|
|
- static constexpr uint16_t HEADER_TOKEN = 0xB5AD;
|
233
|
|
- uint16_t token; // packet start token
|
234
|
|
- uint8_t sync; // stream sync, resend id and packet loss detection
|
235
|
|
- uint8_t meta; // 4 bit protocol,
|
236
|
|
- // 4 bit packet type
|
237
|
|
- uint16_t size; // data length
|
238
|
|
- uint16_t checksum; // header checksum
|
239
|
231
|
|
|
232
|
+ union Header {
|
|
233
|
+ static constexpr uint16_t HEADER_TOKEN = 0xB5AD;
|
|
234
|
+ struct [[gnu::packed]] {
|
|
235
|
+ uint16_t token; // packet start token
|
|
236
|
+ uint8_t sync; // stream sync, resend id and packet loss detection
|
|
237
|
+ uint8_t meta; // 4 bit protocol,
|
|
238
|
+ // 4 bit packet type
|
|
239
|
+ uint16_t size; // data length
|
|
240
|
+ uint16_t checksum; // header checksum
|
|
241
|
+ };
|
240
|
242
|
uint8_t protocol() { return (meta >> 4) & 0xF; }
|
241
|
243
|
uint8_t type() { return meta & 0xF; }
|
242
|
244
|
void reset() { token = 0; sync = 0; meta = 0; size = 0; checksum = 0; }
|
|
245
|
+ uint8_t data[1];
|
243
|
246
|
};
|
244
|
247
|
|
245
|
|
- struct [[gnu::packed]] Footer {
|
246
|
|
- uint16_t checksum; // full packet checksum
|
|
248
|
+ union Footer {
|
|
249
|
+ struct [[gnu::packed]] {
|
|
250
|
+ uint16_t checksum; // full packet checksum
|
|
251
|
+ };
|
247
|
252
|
void reset() { checksum = 0; }
|
|
253
|
+ uint8_t data[1];
|
248
|
254
|
};
|
249
|
255
|
|
250
|
|
- uint8_t header_data[sizeof(Header)],
|
251
|
|
- footer_data[sizeof(Footer)];
|
|
256
|
+ Header header;
|
|
257
|
+ Footer footer;
|
252
|
258
|
uint32_t bytes_received;
|
253
|
259
|
uint16_t checksum, header_checksum;
|
254
|
260
|
millis_t timeout;
|
255
|
261
|
char* buffer;
|
256
|
262
|
|
257
|
|
- Header& header() { return *reinterpret_cast<Header*>(header_data); }
|
258
|
|
- Footer& footer() { return *reinterpret_cast<Footer*>(footer_data); }
|
259
|
263
|
void reset() {
|
260
|
|
- header().reset();
|
261
|
|
- footer().reset();
|
|
264
|
+ header.reset();
|
|
265
|
+ footer.reset();
|
262
|
266
|
bytes_received = 0;
|
263
|
267
|
checksum = 0;
|
264
|
268
|
header_checksum = 0;
|
|
@@ -312,46 +316,46 @@ public:
|
312
|
316
|
stream_state = StreamState::PACKET_WAIT;
|
313
|
317
|
case StreamState::PACKET_WAIT:
|
314
|
318
|
if (!stream_read(data)) { idle(); return; } // no active packet so don't wait
|
315
|
|
- packet.header_data[1] = data;
|
316
|
|
- if (packet.header().token == Packet::Header::HEADER_TOKEN) {
|
|
319
|
+ packet.header.data[1] = data;
|
|
320
|
+ if (packet.header.token == packet.header.HEADER_TOKEN) {
|
317
|
321
|
packet.bytes_received = 2;
|
318
|
322
|
stream_state = StreamState::PACKET_HEADER;
|
319
|
323
|
}
|
320
|
324
|
else {
|
321
|
325
|
// stream corruption drop data
|
322
|
|
- packet.header_data[0] = data;
|
|
326
|
+ packet.header.data[0] = data;
|
323
|
327
|
}
|
324
|
328
|
break;
|
325
|
329
|
case StreamState::PACKET_HEADER:
|
326
|
330
|
if (!stream_read(data)) break;
|
327
|
331
|
|
328
|
|
- packet.header_data[packet.bytes_received++] = data;
|
|
332
|
+ packet.header.data[packet.bytes_received++] = data;
|
329
|
333
|
packet.checksum = checksum(packet.checksum, data);
|
330
|
334
|
|
331
|
335
|
// header checksum calculation can't contain the checksum
|
332
|
|
- if (packet.bytes_received == sizeof(Packet::Header) - 2)
|
|
336
|
+ if (packet.bytes_received == sizeof(Packet::header) - 2)
|
333
|
337
|
packet.header_checksum = packet.checksum;
|
334
|
338
|
|
335
|
|
- if (packet.bytes_received == sizeof(Packet::Header)) {
|
336
|
|
- if (packet.header().checksum == packet.header_checksum) {
|
|
339
|
+ if (packet.bytes_received == sizeof(Packet::header)) {
|
|
340
|
+ if (packet.header.checksum == packet.header_checksum) {
|
337
|
341
|
// The SYNC control packet is a special case in that it doesn't require the stream sync to be correct
|
338
|
|
- if (static_cast<Protocol>(packet.header().protocol()) == Protocol::CONTROL && static_cast<ProtocolControl>(packet.header().type()) == ProtocolControl::SYNC) {
|
|
342
|
+ if (static_cast<Protocol>(packet.header.protocol()) == Protocol::CONTROL && static_cast<ProtocolControl>(packet.header.type()) == ProtocolControl::SYNC) {
|
339
|
343
|
SERIAL_ECHOLNPAIR("ss", sync, ",", buffer_size, ",", VERSION_MAJOR, ".", VERSION_MINOR, ".", VERSION_PATCH);
|
340
|
344
|
stream_state = StreamState::PACKET_RESET;
|
341
|
345
|
break;
|
342
|
346
|
}
|
343
|
|
- if (packet.header().sync == sync) {
|
|
347
|
+ if (packet.header.sync == sync) {
|
344
|
348
|
buffer_next_index = 0;
|
345
|
349
|
packet.bytes_received = 0;
|
346
|
|
- if (packet.header().size) {
|
|
350
|
+ if (packet.header.size) {
|
347
|
351
|
stream_state = StreamState::PACKET_DATA;
|
348
|
352
|
packet.buffer = static_cast<char *>(&buffer[0]); // multipacket buffering not implemented, always allocate whole buffer to packet
|
349
|
353
|
}
|
350
|
354
|
else
|
351
|
355
|
stream_state = StreamState::PACKET_PROCESS;
|
352
|
356
|
}
|
353
|
|
- else if (packet.header().sync == sync - 1) { // ok response must have been lost
|
354
|
|
- SERIAL_ECHOLNPAIR("ok", packet.header().sync); // transmit valid packet received and drop the payload
|
|
357
|
+ else if (packet.header.sync == sync - 1) { // ok response must have been lost
|
|
358
|
+ SERIAL_ECHOLNPAIR("ok", packet.header.sync); // transmit valid packet received and drop the payload
|
355
|
359
|
stream_state = StreamState::PACKET_RESET;
|
356
|
360
|
}
|
357
|
361
|
else if (packet_retries) {
|
|
@@ -364,7 +368,7 @@ public:
|
364
|
368
|
}
|
365
|
369
|
else {
|
366
|
370
|
SERIAL_ECHO_START();
|
367
|
|
- SERIAL_ECHOLNPAIR("Packet Header(", packet.header().sync, "?) Corrupt");
|
|
371
|
+ SERIAL_ECHOLNPAIR("Packet header(", packet.header.sync, "?) corrupt");
|
368
|
372
|
stream_state = StreamState::PACKET_RESEND;
|
369
|
373
|
}
|
370
|
374
|
}
|
|
@@ -384,7 +388,7 @@ public:
|
384
|
388
|
packet.bytes_received++;
|
385
|
389
|
buffer_next_index++;
|
386
|
390
|
|
387
|
|
- if (packet.bytes_received == packet.header().size) {
|
|
391
|
+ if (packet.bytes_received == packet.header.size) {
|
388
|
392
|
stream_state = StreamState::PACKET_FOOTER;
|
389
|
393
|
packet.bytes_received = 0;
|
390
|
394
|
}
|
|
@@ -392,14 +396,14 @@ public:
|
392
|
396
|
case StreamState::PACKET_FOOTER:
|
393
|
397
|
if (!stream_read(data)) break;
|
394
|
398
|
|
395
|
|
- packet.footer_data[packet.bytes_received++] = data;
|
396
|
|
- if (packet.bytes_received == sizeof(Packet::Footer)) {
|
397
|
|
- if (packet.footer().checksum == packet.checksum) {
|
|
399
|
+ packet.footer.data[packet.bytes_received++] = data;
|
|
400
|
+ if (packet.bytes_received == sizeof(Packet::footer)) {
|
|
401
|
+ if (packet.footer.checksum == packet.checksum) {
|
398
|
402
|
stream_state = StreamState::PACKET_PROCESS;
|
399
|
403
|
}
|
400
|
404
|
else {
|
401
|
405
|
SERIAL_ECHO_START();
|
402
|
|
- SERIAL_ECHOLNPAIR("Packet(", packet.header().sync, ") Payload Corrupt");
|
|
406
|
+ SERIAL_ECHOLNPAIR("Packet(", packet.header.sync, ") payload corrupt");
|
403
|
407
|
stream_state = StreamState::PACKET_RESEND;
|
404
|
408
|
}
|
405
|
409
|
}
|
|
@@ -407,9 +411,9 @@ public:
|
407
|
411
|
case StreamState::PACKET_PROCESS:
|
408
|
412
|
sync++;
|
409
|
413
|
packet_retries = 0;
|
410
|
|
- bytes_received += packet.header().size;
|
|
414
|
+ bytes_received += packet.header.size;
|
411
|
415
|
|
412
|
|
- SERIAL_ECHOLNPAIR("ok", packet.header().sync); // transmit valid packet received
|
|
416
|
+ SERIAL_ECHOLNPAIR("ok", packet.header.sync); // transmit valid packet received
|
413
|
417
|
dispatch();
|
414
|
418
|
stream_state = StreamState::PACKET_RESET;
|
415
|
419
|
break;
|
|
@@ -429,7 +433,7 @@ public:
|
429
|
433
|
stream_state = StreamState::PACKET_RESEND;
|
430
|
434
|
break;
|
431
|
435
|
case StreamState::PACKET_ERROR:
|
432
|
|
- SERIAL_ECHOLNPAIR("fe", packet.header().sync);
|
|
436
|
+ SERIAL_ECHOLNPAIR("fe", packet.header.sync);
|
433
|
437
|
reset(); // reset everything, resync required
|
434
|
438
|
stream_state = StreamState::PACKET_RESET;
|
435
|
439
|
break;
|
|
@@ -438,9 +442,9 @@ public:
|
438
|
442
|
}
|
439
|
443
|
|
440
|
444
|
void dispatch() {
|
441
|
|
- switch(static_cast<Protocol>(packet.header().protocol())) {
|
|
445
|
+ switch(static_cast<Protocol>(packet.header.protocol())) {
|
442
|
446
|
case Protocol::CONTROL:
|
443
|
|
- switch(static_cast<ProtocolControl>(packet.header().type())) {
|
|
447
|
+ switch(static_cast<ProtocolControl>(packet.header.type())) {
|
444
|
448
|
case ProtocolControl::CLOSE: // revert back to ASCII mode
|
445
|
449
|
card.flag.binary_mode = false;
|
446
|
450
|
break;
|
|
@@ -449,7 +453,7 @@ public:
|
449
|
453
|
}
|
450
|
454
|
break;
|
451
|
455
|
case Protocol::FILE_TRANSFER:
|
452
|
|
- SDFileTransferProtocol::process(packet.header().type(), packet.buffer, packet.header().size); // send user data to be processed
|
|
456
|
+ SDFileTransferProtocol::process(packet.header.type(), packet.buffer, packet.header.size); // send user data to be processed
|
453
|
457
|
break;
|
454
|
458
|
default:
|
455
|
459
|
SERIAL_ECHO_MSG("Unsupported Binary Protocol");
|