aboutsummaryrefslogtreecommitdiff
path: root/quantum/serial_link/protocol/byte_stuffer.c
diff options
context:
space:
mode:
authorFred Sundvik <fsundvik@gmail.com>2016-07-06 13:26:20 +0300
committerFred Sundvik <fsundvik@gmail.com>2016-07-06 13:26:20 +0300
commitd5e7603d551a31836bf0c59db259ddc3593a1aa7 (patch)
treecf2ae7163eb7431e24e8a93752ef4fd18d292cd0 /quantum/serial_link/protocol/byte_stuffer.c
parentc5bf090d16cf1fc4d8186f1e8fbbd62457e72da6 (diff)
downloadqmk_firmware-d5e7603d551a31836bf0c59db259ddc3593a1aa7.tar.gz
qmk_firmware-d5e7603d551a31836bf0c59db259ddc3593a1aa7.zip
Remove extra serial_link subdirectory
Diffstat (limited to 'quantum/serial_link/protocol/byte_stuffer.c')
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/quantum/serial_link/protocol/byte_stuffer.c b/quantum/serial_link/protocol/byte_stuffer.c
new file mode 100644
index 000000000..fb4c45a8d
--- /dev/null
+++ b/quantum/serial_link/protocol/byte_stuffer.c
@@ -0,0 +1,145 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/byte_stuffer.h"
26#include "serial_link/protocol/frame_validator.h"
27#include "serial_link/protocol/physical.h"
28#include <stdbool.h>
29
30// This implements the "Consistent overhead byte stuffing protocol"
31// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
32// http://www.stuartcheshire.org/papers/COBSforToN.pdf
33
34#define MAX_FRAME_SIZE 1024
35#define NUM_LINKS 2
36
37typedef struct byte_stuffer_state {
38 uint16_t next_zero;
39 uint16_t data_pos;
40 bool long_frame;
41 uint8_t data[MAX_FRAME_SIZE];
42}byte_stuffer_state_t;
43
44static byte_stuffer_state_t states[NUM_LINKS];
45
46void init_byte_stuffer_state(byte_stuffer_state_t* state) {
47 state->next_zero = 0;
48 state->data_pos = 0;
49 state->long_frame = false;
50}
51
52void init_byte_stuffer(void) {
53 int i;
54 for (i=0;i<NUM_LINKS;i++) {
55 init_byte_stuffer_state(&states[i]);
56 }
57}
58
59void byte_stuffer_recv_byte(uint8_t link, uint8_t data) {
60 byte_stuffer_state_t* state = &states[link];
61 // Start of a new frame
62 if (state->next_zero == 0) {
63 state->next_zero = data;
64 state->long_frame = data == 0xFF;
65 state->data_pos = 0;
66 return;
67 }
68
69 state->next_zero--;
70 if (data == 0) {
71 if (state->next_zero == 0) {
72 // The frame is completed
73 if (state->data_pos > 0) {
74 validator_recv_frame(link, state->data, state->data_pos);
75 }
76 }
77 else {
78 // The frame is invalid, so reset
79 init_byte_stuffer_state(state);
80 }
81 }
82 else {
83 if (state->data_pos == MAX_FRAME_SIZE) {
84 // We exceeded our maximum frame size
85 // therefore there's nothing else to do than reset to a new frame
86 state->next_zero = data;
87 state->long_frame = data == 0xFF;
88 state->data_pos = 0;
89 }
90 else if (state->next_zero == 0) {
91 if (state->long_frame) {
92 // This is part of a long frame, so continue
93 state->next_zero = data;
94 state->long_frame = data == 0xFF;
95 }
96 else {
97 // Special case for zeroes
98 state->next_zero = data;
99 state->data[state->data_pos++] = 0;
100 }
101 }
102 else {
103 state->data[state->data_pos++] = data;
104 }
105 }
106}
107
108static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) {
109 send_data(link, &num_non_zero, 1);
110 if (end > start) {
111 send_data(link, start, end-start);
112 }
113}
114
115void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
116 const uint8_t zero = 0;
117 if (size > 0) {
118 uint16_t num_non_zero = 1;
119 uint8_t* end = data + size;
120 uint8_t* start = data;
121 while (data < end) {
122 if (num_non_zero == 0xFF) {
123 // There's more data after big non-zero block
124 // So send it, and start a new block
125 send_block(link, start, data, num_non_zero);
126 start = data;
127 num_non_zero = 1;
128 }
129 else {
130 if (*data == 0) {
131 // A zero encountered, so send the block
132 send_block(link, start, data, num_non_zero);
133 start = data + 1;
134 num_non_zero = 1;
135 }
136 else {
137 num_non_zero++;
138 }
139 ++data;
140 }
141 }
142 send_block(link, start, data, num_non_zero);
143 send_data(link, &zero, 1);
144 }
145}