aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Humbert <jack.humb@gmail.com>2016-07-06 08:56:57 -0400
committerGitHub <noreply@github.com>2016-07-06 08:56:57 -0400
commitc6d671e54c249497b5c01ad9badaa50425f394f9 (patch)
tree69685292a135d5d342f34955dae348c405871f4e
parent3577e26fd9916ceab58779ec6323d43da54eb3b5 (diff)
parentd5e7603d551a31836bf0c59db259ddc3593a1aa7 (diff)
downloadqmk_firmware-c6d671e54c249497b5c01ad9badaa50425f394f9.tar.gz
qmk_firmware-c6d671e54c249497b5c01ad9badaa50425f394f9.zip
Merge pull request #482 from fredizzimo/serial_link
Add serial link library
-rw-r--r--quantum/serial_link/LICENSE21
-rw-r--r--quantum/serial_link/README.md1
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.c145
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.h34
-rw-r--r--quantum/serial_link/protocol/frame_router.c69
-rw-r--r--quantum/serial_link/protocol/frame_router.h38
-rw-r--r--quantum/serial_link/protocol/frame_validator.c121
-rw-r--r--quantum/serial_link/protocol/frame_validator.h34
-rw-r--r--quantum/serial_link/protocol/physical.h30
-rw-r--r--quantum/serial_link/protocol/transport.c124
-rw-r--r--quantum/serial_link/protocol/transport.h151
-rw-r--r--quantum/serial_link/protocol/triple_buffered_object.c78
-rw-r--r--quantum/serial_link/protocol/triple_buffered_object.h51
-rw-r--r--quantum/serial_link/system/serial_link.c265
-rw-r--r--quantum/serial_link/system/serial_link.h63
-rw-r--r--quantum/serial_link/tests/Makefile61
-rw-r--r--quantum/serial_link/tests/byte_stuffer_tests.c506
-rw-r--r--quantum/serial_link/tests/frame_router_tests.c231
-rw-r--r--quantum/serial_link/tests/frame_validator_tests.c101
-rw-r--r--quantum/serial_link/tests/transport_tests.c168
-rw-r--r--quantum/serial_link/tests/triple_buffered_object_tests.c82
21 files changed, 2374 insertions, 0 deletions
diff --git a/quantum/serial_link/LICENSE b/quantum/serial_link/LICENSE
new file mode 100644
index 000000000..d7cc3198c
--- /dev/null
+++ b/quantum/serial_link/LICENSE
@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2016 Fred Sundvik
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
diff --git a/quantum/serial_link/README.md b/quantum/serial_link/README.md
new file mode 100644
index 000000000..e8490e290
--- /dev/null
+++ b/quantum/serial_link/README.md
@@ -0,0 +1 @@
# qmk_serial_link \ No newline at end of file
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}
diff --git a/quantum/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/protocol/byte_stuffer.h
new file mode 100644
index 000000000..2cc88beb4
--- /dev/null
+++ b/quantum/serial_link/protocol/byte_stuffer.h
@@ -0,0 +1,34 @@
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#ifndef SERIAL_LINK_BYTE_STUFFER_H
26#define SERIAL_LINK_BYTE_STUFFER_H
27
28#include <stdint.h>
29
30void init_byte_stuffer(void);
31void byte_stuffer_recv_byte(uint8_t link, uint8_t data);
32void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size);
33
34#endif
diff --git a/quantum/serial_link/protocol/frame_router.c b/quantum/serial_link/protocol/frame_router.c
new file mode 100644
index 000000000..04b8c2e75
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_router.c
@@ -0,0 +1,69 @@
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/frame_router.h"
26#include "serial_link/protocol/transport.h"
27#include "serial_link/protocol/frame_validator.h"
28
29static bool is_master;
30
31void router_set_master(bool master) {
32 is_master = master;
33}
34
35void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size){
36 if (is_master) {
37 if (link == DOWN_LINK) {
38 transport_recv_frame(data[size-1], data, size - 1);
39 }
40 }
41 else {
42 if (link == UP_LINK) {
43 if (data[size-1] & 1) {
44 transport_recv_frame(0, data, size - 1);
45 }
46 data[size-1] >>= 1;
47 validator_send_frame(DOWN_LINK, data, size);
48 }
49 else {
50 data[size-1]++;
51 validator_send_frame(UP_LINK, data, size);
52 }
53 }
54}
55
56void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
57 if (destination == 0) {
58 if (!is_master) {
59 data[size] = 1;
60 validator_send_frame(UP_LINK, data, size + 1);
61 }
62 }
63 else {
64 if (is_master) {
65 data[size] = destination;
66 validator_send_frame(DOWN_LINK, data, size + 1);
67 }
68 }
69}
diff --git a/quantum/serial_link/protocol/frame_router.h b/quantum/serial_link/protocol/frame_router.h
new file mode 100644
index 000000000..712250ff3
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_router.h
@@ -0,0 +1,38 @@
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#ifndef SERIAL_LINK_FRAME_ROUTER_H
26#define SERIAL_LINK_FRAME_ROUTER_H
27
28#include <stdint.h>
29#include <stdbool.h>
30
31#define UP_LINK 0
32#define DOWN_LINK 1
33
34void router_set_master(bool master);
35void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size);
36void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size);
37
38#endif
diff --git a/quantum/serial_link/protocol/frame_validator.c b/quantum/serial_link/protocol/frame_validator.c
new file mode 100644
index 000000000..474f80ee8
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_validator.c
@@ -0,0 +1,121 @@
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/frame_validator.h"
26#include "serial_link/protocol/frame_router.h"
27#include "serial_link/protocol/byte_stuffer.h"
28#include <string.h>
29
30const uint32_t poly8_lookup[256] =
31{
32 0, 0x77073096, 0xEE0E612C, 0x990951BA,
33 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
34 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
35 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
36 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
37 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
38 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
39 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
40 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
41 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
42 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
43 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
44 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
45 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
46 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
47 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
48 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
49 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
50 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
51 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
52 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
53 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
54 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
55 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
56 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
57 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
58 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
59 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
60 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
61 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
62 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
63 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
64 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
65 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
66 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
67 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
68 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
69 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
70 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
71 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
72 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
73 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
74 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
75 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
76 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
77 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
78 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
79 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
80 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
81 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
82 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
83 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
84 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
85 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
86 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
87 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
88 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
89 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
90 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
91 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
92 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
93 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
94 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
95 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
96};
97
98static uint32_t crc32_byte(uint8_t *p, uint32_t bytelength)
99{
100 uint32_t crc = 0xffffffff;
101 while (bytelength-- !=0) crc = poly8_lookup[((uint8_t) crc ^ *(p++))] ^ (crc >> 8);
102 // return (~crc); also works
103 return (crc ^ 0xffffffff);
104}
105
106void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
107 if (size > 4) {
108 uint32_t frame_crc;
109 memcpy(&frame_crc, data + size -4, 4);
110 uint32_t expected_crc = crc32_byte(data, size - 4);
111 if (frame_crc == expected_crc) {
112 route_incoming_frame(link, data, size-4);
113 }
114 }
115}
116
117void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
118 uint32_t crc = crc32_byte(data, size);
119 memcpy(data + size, &crc, 4);
120 byte_stuffer_send_frame(link, data, size + 4);
121}
diff --git a/quantum/serial_link/protocol/frame_validator.h b/quantum/serial_link/protocol/frame_validator.h
new file mode 100644
index 000000000..4a910d510
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_validator.h
@@ -0,0 +1,34 @@
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#ifndef SERIAL_LINK_FRAME_VALIDATOR_H
26#define SERIAL_LINK_FRAME_VALIDATOR_H
27
28#include <stdint.h>
29
30void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size);
31// The buffer pointed to by the data needs 4 additional bytes
32void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size);
33
34#endif
diff --git a/quantum/serial_link/protocol/physical.h b/quantum/serial_link/protocol/physical.h
new file mode 100644
index 000000000..425e06cdd
--- /dev/null
+++ b/quantum/serial_link/protocol/physical.h
@@ -0,0 +1,30 @@
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#ifndef SERIAL_LINK_PHYSICAL_H
26#define SERIAL_LINK_PHYSICAL_H
27
28void send_data(uint8_t link, const uint8_t* data, uint16_t size);
29
30#endif
diff --git a/quantum/serial_link/protocol/transport.c b/quantum/serial_link/protocol/transport.c
new file mode 100644
index 000000000..f418d11ce
--- /dev/null
+++ b/quantum/serial_link/protocol/transport.c
@@ -0,0 +1,124 @@
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/transport.h"
26#include "serial_link/protocol/frame_router.h"
27#include "serial_link/protocol/triple_buffered_object.h"
28#include <string.h>
29
30#define MAX_REMOTE_OBJECTS 16
31static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS];
32static uint32_t num_remote_objects = 0;
33
34void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) {
35 unsigned int i;
36 for(i=0;i<_num_remote_objects;i++) {
37 remote_object_t* obj = _remote_objects[i];
38 remote_objects[num_remote_objects++] = obj;
39 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
40 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
41 triple_buffer_init(tb);
42 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
43 tb = (triple_buffer_object_t*)start;
44 triple_buffer_init(tb);
45 }
46 else if(obj->object_type == MASTER_TO_SINGLE_SLAVE) {
47 uint8_t* start = obj->buffer;
48 unsigned int j;
49 for (j=0;j<NUM_SLAVES;j++) {
50 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
51 triple_buffer_init(tb);
52 start += LOCAL_OBJECT_SIZE(obj->object_size);
53 }
54 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
55 triple_buffer_init(tb);
56 }
57 else {
58 uint8_t* start = obj->buffer;
59 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
60 triple_buffer_init(tb);
61 start += LOCAL_OBJECT_SIZE(obj->object_size);
62 unsigned int j;
63 for (j=0;j<NUM_SLAVES;j++) {
64 tb = (triple_buffer_object_t*)start;
65 triple_buffer_init(tb);
66 start += REMOTE_OBJECT_SIZE(obj->object_size);
67 }
68 }
69 }
70}
71
72void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
73 uint8_t id = data[size-1];
74 if (id < num_remote_objects) {
75 remote_object_t* obj = remote_objects[id];
76 if (obj->object_size == size - 1) {
77 uint8_t* start;
78 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
79 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
80 }
81 else if(obj->object_type == SLAVE_TO_MASTER) {
82 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
83 start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size);
84 }
85 else {
86 start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);
87 }
88 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
89 void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb);
90 memcpy(ptr, data, size - 1);
91 triple_buffer_end_write_internal(tb);
92 }
93 }
94}
95
96void update_transport(void) {
97 unsigned int i;
98 for(i=0;i<num_remote_objects;i++) {
99 remote_object_t* obj = remote_objects[i];
100 if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) {
101 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
102 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
103 if (ptr) {
104 ptr[obj->object_size] = i;
105 uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0;
106 router_send_frame(dest, ptr, obj->object_size + 1);
107 }
108 }
109 else {
110 uint8_t* start = obj->buffer;
111 unsigned int j;
112 for (j=0;j<NUM_SLAVES;j++) {
113 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
114 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
115 if (ptr) {
116 ptr[obj->object_size] = i;
117 uint8_t dest = j + 1;
118 router_send_frame(dest, ptr, obj->object_size + 1);
119 }
120 start += LOCAL_OBJECT_SIZE(obj->object_size);
121 }
122 }
123 }
124}
diff --git a/quantum/serial_link/protocol/transport.h b/quantum/serial_link/protocol/transport.h
new file mode 100644
index 000000000..9a052d880
--- /dev/null
+++ b/quantum/serial_link/protocol/transport.h
@@ -0,0 +1,151 @@
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#ifndef SERIAL_LINK_TRANSPORT_H
26#define SERIAL_LINK_TRANSPORT_H
27
28#include "serial_link/protocol/triple_buffered_object.h"
29#include "serial_link/system/serial_link.h"
30
31#define NUM_SLAVES 8
32#define LOCAL_OBJECT_EXTRA 16
33
34// master -> slave = 1 local(target all), 1 remote object
35// slave -> master = 1 local(target 0), multiple remote objects
36// master -> single slave (multiple local, target id), 1 remote object
37typedef enum {
38 MASTER_TO_ALL_SLAVES,
39 MASTER_TO_SINGLE_SLAVE,
40 SLAVE_TO_MASTER,
41} remote_object_type;
42
43typedef struct {
44 remote_object_type object_type;
45 uint16_t object_size;
46 uint8_t buffer[] __attribute__((aligned(4)));
47} remote_object_t;
48
49#define REMOTE_OBJECT_SIZE(objectsize) \
50 (sizeof(triple_buffer_object_t) + objectsize * 3)
51#define LOCAL_OBJECT_SIZE(objectsize) \
52 (sizeof(triple_buffer_object_t) + (objectsize + LOCAL_OBJECT_EXTRA) * 3)
53
54#define REMOTE_OBJECT_HELPER(name, type, num_local, num_remote) \
55typedef struct { \
56 remote_object_t object; \
57 uint8_t buffer[ \
58 num_remote * REMOTE_OBJECT_SIZE(sizeof(type)) + \
59 num_local * LOCAL_OBJECT_SIZE(sizeof(type))]; \
60} remote_object_##name##_t;
61
62#define MASTER_TO_ALL_SLAVES_OBJECT(name, type) \
63 REMOTE_OBJECT_HELPER(name, type, 1, 1) \
64 remote_object_##name##_t remote_object_##name = { \
65 .object = { \
66 .object_type = MASTER_TO_ALL_SLAVES, \
67 .object_size = sizeof(type), \
68 } \
69 }; \
70 type* begin_write_##name(void) { \
71 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
72 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
73 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
74 }\
75 void end_write_##name(void) { \
76 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
77 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
78 triple_buffer_end_write_internal(tb); \
79 signal_data_written(); \
80 }\
81 type* read_##name(void) { \
82 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
83 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
84 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
85 return triple_buffer_read_internal(obj->object_size, tb); \
86 }
87
88#define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \
89 REMOTE_OBJECT_HELPER(name, type, NUM_SLAVES, 1) \
90 remote_object_##name##_t remote_object_##name = { \
91 .object = { \
92 .object_type = MASTER_TO_SINGLE_SLAVE, \
93 .object_size = sizeof(type), \
94 } \
95 }; \
96 type* begin_write_##name(uint8_t slave) { \
97 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
98 uint8_t* start = obj->buffer;\
99 start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \
100 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
101 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
102 }\
103 void end_write_##name(uint8_t slave) { \
104 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
105 uint8_t* start = obj->buffer;\
106 start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \
107 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
108 triple_buffer_end_write_internal(tb); \
109 signal_data_written(); \
110 }\
111 type* read_##name() { \
112 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
113 uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\
114 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
115 return triple_buffer_read_internal(obj->object_size, tb); \
116 }
117
118#define SLAVE_TO_MASTER_OBJECT(name, type) \
119 REMOTE_OBJECT_HELPER(name, type, 1, NUM_SLAVES) \
120 remote_object_##name##_t remote_object_##name = { \
121 .object = { \
122 .object_type = SLAVE_TO_MASTER, \
123 .object_size = sizeof(type), \
124 } \
125 }; \
126 type* begin_write_##name(void) { \
127 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
128 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
129 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
130 }\
131 void end_write_##name(void) { \
132 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
133 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
134 triple_buffer_end_write_internal(tb); \
135 signal_data_written(); \
136 }\
137 type* read_##name(uint8_t slave) { \
138 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
139 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
140 start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \
141 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
142 return triple_buffer_read_internal(obj->object_size, tb); \
143 }
144
145#define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name
146
147void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects);
148void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size);
149void update_transport(void);
150
151#endif
diff --git a/quantum/serial_link/protocol/triple_buffered_object.c b/quantum/serial_link/protocol/triple_buffered_object.c
new file mode 100644
index 000000000..e3e8989d3
--- /dev/null
+++ b/quantum/serial_link/protocol/triple_buffered_object.c
@@ -0,0 +1,78 @@
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/triple_buffered_object.h"
26#include "serial_link/system/serial_link.h"
27#include <stdbool.h>
28#include <stddef.h>
29
30#define GET_READ_INDEX() object->state & 3
31#define GET_WRITE_INDEX() (object->state >> 2) & 3
32#define GET_SHARED_INDEX() (object->state >> 4) & 3
33#define GET_DATA_AVAILABLE() (object->state >> 6) & 1
34
35#define SET_READ_INDEX(i) object->state = ((object->state & ~3) | i)
36#define SET_WRITE_INDEX(i) object->state = ((object->state & ~(3 << 2)) | (i << 2))
37#define SET_SHARED_INDEX(i) object->state = ((object->state & ~(3 << 4)) | (i << 4))
38#define SET_DATA_AVAILABLE(i) object->state = ((object->state & ~(1 << 6)) | (i << 6))
39
40void triple_buffer_init(triple_buffer_object_t* object) {
41 object->state = 0;
42 SET_WRITE_INDEX(0);
43 SET_READ_INDEX(1);
44 SET_SHARED_INDEX(2);
45 SET_DATA_AVAILABLE(0);
46}
47
48void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object) {
49 serial_link_lock();
50 if (GET_DATA_AVAILABLE()) {
51 uint8_t shared_index = GET_SHARED_INDEX();
52 uint8_t read_index = GET_READ_INDEX();
53 SET_READ_INDEX(shared_index);
54 SET_SHARED_INDEX(read_index);
55 SET_DATA_AVAILABLE(false);
56 serial_link_unlock();
57 return object->buffer + object_size * shared_index;
58 }
59 else {
60 serial_link_unlock();
61 return NULL;
62 }
63}
64
65void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object) {
66 uint8_t write_index = GET_WRITE_INDEX();
67 return object->buffer + object_size * write_index;
68}
69
70void triple_buffer_end_write_internal(triple_buffer_object_t* object) {
71 serial_link_lock();
72 uint8_t shared_index = GET_SHARED_INDEX();
73 uint8_t write_index = GET_WRITE_INDEX();
74 SET_SHARED_INDEX(write_index);
75 SET_WRITE_INDEX(shared_index);
76 SET_DATA_AVAILABLE(true);
77 serial_link_unlock();
78}
diff --git a/quantum/serial_link/protocol/triple_buffered_object.h b/quantum/serial_link/protocol/triple_buffered_object.h
new file mode 100644
index 000000000..2e57db3f5
--- /dev/null
+++ b/quantum/serial_link/protocol/triple_buffered_object.h
@@ -0,0 +1,51 @@
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#ifndef SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H
26#define SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H
27
28#include <stdint.h>
29
30typedef struct {
31 uint8_t state;
32 uint8_t buffer[] __attribute__((aligned(4)));
33}triple_buffer_object_t;
34
35void triple_buffer_init(triple_buffer_object_t* object);
36
37#define triple_buffer_begin_write(object) \
38 (typeof(*object.buffer[0])*)triple_buffer_begin_write_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object)
39
40#define triple_buffer_end_write(object) \
41 triple_buffer_end_write_internal((triple_buffer_object_t*)object)
42
43#define triple_buffer_read(object) \
44 (typeof(*object.buffer[0])*)triple_buffer_read_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object)
45
46void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object);
47void triple_buffer_end_write_internal(triple_buffer_object_t* object);
48void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object);
49
50
51#endif
diff --git a/quantum/serial_link/system/serial_link.c b/quantum/serial_link/system/serial_link.c
new file mode 100644
index 000000000..75c7e77a7
--- /dev/null
+++ b/quantum/serial_link/system/serial_link.c
@@ -0,0 +1,265 @@
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#include "report.h"
25#include "host_driver.h"
26#include "serial_link/system/serial_link.h"
27#include "hal.h"
28#include "serial_link/protocol/byte_stuffer.h"
29#include "serial_link/protocol/transport.h"
30#include "serial_link/protocol/frame_router.h"
31#include "matrix.h"
32#include <stdbool.h>
33#include "print.h"
34#include "config.h"
35
36static event_source_t new_data_event;
37static bool serial_link_connected;
38static bool is_master = false;
39
40static uint8_t keyboard_leds(void);
41static void send_keyboard(report_keyboard_t *report);
42static void send_mouse(report_mouse_t *report);
43static void send_system(uint16_t data);
44static void send_consumer(uint16_t data);
45
46host_driver_t serial_driver = {
47 keyboard_leds,
48 send_keyboard,
49 send_mouse,
50 send_system,
51 send_consumer
52};
53
54// Define these in your Config.h file
55#ifndef SERIAL_LINK_BAUD
56#error "Serial link baud is not set"
57#endif
58
59#ifndef SERIAL_LINK_THREAD_PRIORITY
60#error "Serial link thread priority not set"
61#endif
62
63static SerialConfig config = {
64 .sc_speed = SERIAL_LINK_BAUD
65};
66
67//#define DEBUG_LINK_ERRORS
68
69static uint32_t read_from_serial(SerialDriver* driver, uint8_t link) {
70 const uint32_t buffer_size = 16;
71 uint8_t buffer[buffer_size];
72 uint32_t bytes_read = sdAsynchronousRead(driver, buffer, buffer_size);
73 uint8_t* current = buffer;
74 uint8_t* end = current + bytes_read;
75 while(current < end) {
76 byte_stuffer_recv_byte(link, *current);
77 current++;
78 }
79 return bytes_read;
80}
81
82static void print_error(char* str, eventflags_t flags, SerialDriver* driver) {
83#ifdef DEBUG_LINK_ERRORS
84 if (flags & SD_PARITY_ERROR) {
85 print(str);
86 print(" Parity error\n");
87 }
88 if (flags & SD_FRAMING_ERROR) {
89 print(str);
90 print(" Framing error\n");
91 }
92 if (flags & SD_OVERRUN_ERROR) {
93 print(str);
94 uint32_t size = qSpaceI(&(driver->iqueue));
95 xprintf(" Overrun error, queue size %d\n", size);
96
97 }
98 if (flags & SD_NOISE_ERROR) {
99 print(str);
100 print(" Noise error\n");
101 }
102 if (flags & SD_BREAK_DETECTED) {
103 print(str);
104 print(" Break detected\n");
105 }
106#else
107 (void)str;
108 (void)flags;
109 (void)driver;
110#endif
111}
112
113bool is_serial_link_master(void) {
114 return is_master;
115}
116
117// TODO: Optimize the stack size, this is probably way too big
118static THD_WORKING_AREA(serialThreadStack, 1024);
119static THD_FUNCTION(serialThread, arg) {
120 (void)arg;
121 event_listener_t new_data_listener;
122 event_listener_t sd1_listener;
123 event_listener_t sd2_listener;
124 chEvtRegister(&new_data_event, &new_data_listener, 0);
125 eventflags_t events = CHN_INPUT_AVAILABLE
126 | SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR | SD_NOISE_ERROR | SD_BREAK_DETECTED;
127 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD1),
128 &sd1_listener,
129 EVENT_MASK(1),
130 events);
131 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD2),
132 &sd2_listener,
133 EVENT_MASK(2),
134 events);
135 bool need_wait = false;
136 while(true) {
137 eventflags_t flags1 = 0;
138 eventflags_t flags2 = 0;
139 if (need_wait) {
140 eventmask_t mask = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
141 if (mask & EVENT_MASK(1)) {
142 flags1 = chEvtGetAndClearFlags(&sd1_listener);
143 print_error("DOWNLINK", flags1, &SD1);
144 }
145 if (mask & EVENT_MASK(2)) {
146 flags2 = chEvtGetAndClearFlags(&sd2_listener);
147 print_error("UPLINK", flags2, &SD2);
148 }
149 }
150
151 // Always stay as master, even if the USB goes into sleep mode
152 is_master |= usbGetDriverStateI(&USBD1) == USB_ACTIVE;
153 router_set_master(is_master);
154
155 need_wait = true;
156 need_wait &= read_from_serial(&SD2, UP_LINK) == 0;
157 need_wait &= read_from_serial(&SD1, DOWN_LINK) == 0;
158 update_transport();
159 }
160}
161
162void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
163 if (link == DOWN_LINK) {
164 sdWrite(&SD1, data, size);
165 }
166 else {
167 sdWrite(&SD2, data, size);
168 }
169}
170
171static systime_t last_update = 0;
172
173typedef struct {
174 matrix_row_t rows[MATRIX_ROWS];
175} matrix_object_t;
176
177static matrix_object_t last_matrix = {};
178
179SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t);
180MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool);
181
182static remote_object_t* remote_objects[] = {
183 REMOTE_OBJECT(serial_link_connected),
184 REMOTE_OBJECT(keyboard_matrix),
185};
186
187void init_serial_link(void) {
188 serial_link_connected = false;
189 init_serial_link_hal();
190 add_remote_objects(remote_objects, sizeof(remote_objects)/sizeof(remote_object_t*));
191 init_byte_stuffer();
192 sdStart(&SD1, &config);
193 sdStart(&SD2, &config);
194 chEvtObjectInit(&new_data_event);
195 (void)chThdCreateStatic(serialThreadStack, sizeof(serialThreadStack),
196 SERIAL_LINK_THREAD_PRIORITY, serialThread, NULL);
197}
198
199void matrix_set_remote(matrix_row_t* rows, uint8_t index);
200
201void serial_link_update(void) {
202 if (read_serial_link_connected()) {
203 serial_link_connected = true;
204 }
205
206 matrix_object_t matrix;
207 bool changed = false;
208 for(uint8_t i=0;i<MATRIX_ROWS;i++) {
209 matrix.rows[i] = matrix_get_row(i);
210 changed |= matrix.rows[i] != last_matrix.rows[i];
211 }
212
213 systime_t current_time = chVTGetSystemTimeX();
214 systime_t delta = current_time - last_update;
215 if (changed || delta > US2ST(1000)) {
216 last_update = current_time;
217 last_matrix = matrix;
218 matrix_object_t* m = begin_write_keyboard_matrix();
219 for(uint8_t i=0;i<MATRIX_ROWS;i++) {
220 m->rows[i] = matrix.rows[i];
221 }
222 end_write_keyboard_matrix();
223 *begin_write_serial_link_connected() = true;
224 end_write_serial_link_connected();
225 }
226
227 matrix_object_t* m = read_keyboard_matrix(0);
228 if (m) {
229 matrix_set_remote(m->rows, 0);
230 }
231}
232
233void signal_data_written(void) {
234 chEvtBroadcast(&new_data_event);
235}
236
237bool is_serial_link_connected(void) {
238 return serial_link_connected;
239}
240
241host_driver_t* get_serial_link_driver(void) {
242 return &serial_driver;
243}
244
245// NOTE: The driver does nothing, because the master handles everything
246uint8_t keyboard_leds(void) {
247 return 0;
248}
249
250void send_keyboard(report_keyboard_t *report) {
251 (void)report;
252}
253
254void send_mouse(report_mouse_t *report) {
255 (void)report;
256}
257
258void send_system(uint16_t data) {
259 (void)data;
260}
261
262void send_consumer(uint16_t data) {
263 (void)data;
264}
265
diff --git a/quantum/serial_link/system/serial_link.h b/quantum/serial_link/system/serial_link.h
new file mode 100644
index 000000000..351e03877
--- /dev/null
+++ b/quantum/serial_link/system/serial_link.h
@@ -0,0 +1,63 @@
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#ifndef SERIAL_LINK_H
26#define SERIAL_LINK_H
27
28#include "host_driver.h"
29#include <stdbool.h>
30
31void init_serial_link(void);
32void init_serial_link_hal(void);
33bool is_serial_link_connected(void);
34bool is_serial_link_master(void);
35host_driver_t* get_serial_link_driver(void);
36void serial_link_update(void);
37
38#if defined(PROTOCOL_CHIBIOS)
39#include "ch.h"
40
41static inline void serial_link_lock(void) {
42 chSysLock();
43}
44
45static inline void serial_link_unlock(void) {
46 chSysUnlock();
47}
48
49void signal_data_written(void);
50
51#else
52
53inline void serial_link_lock(void) {
54}
55
56inline void serial_link_unlock(void) {
57}
58
59void signal_data_written(void);
60
61#endif
62
63#endif
diff --git a/quantum/serial_link/tests/Makefile b/quantum/serial_link/tests/Makefile
new file mode 100644
index 000000000..1b072c6f1
--- /dev/null
+++ b/quantum/serial_link/tests/Makefile
@@ -0,0 +1,61 @@
1# The MIT License (MIT)
2#
3# Copyright (c) 2016 Fred Sundvik
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23CC = gcc
24CFLAGS =
25INCLUDES = -I. -I../../
26LDFLAGS = -L$(BUILDDIR)/cgreen/build-c/src -shared
27LDLIBS = -lcgreen
28UNITOBJ = $(BUILDDIR)/serialtest/unitobj
29DEPDIR = $(BUILDDIR)/serialtest/unit.d
30UNITTESTS = $(BUILDDIR)/serialtest/unittests
31DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td
32EXT = .so
33UNAME := $(shell uname)
34ifneq (, $(findstring MINGW, $(UNAME)))
35 EXT = .dll
36endif
37ifneq (, $(findstring CYGWIN, $(UNAME)))
38 EXT = .dll
39endif
40
41SRC = $(wildcard *.c)
42TESTFILES = $(patsubst %.c, $(UNITTESTS)/%$(EXT), $(SRC))
43$(shell mkdir -p $(DEPDIR) >/dev/null)
44
45test: $(TESTFILES)
46 @$(BUILDDIR)/cgreen/build-c/tools/cgreen-runner --color $(TESTFILES)
47
48$(UNITTESTS)/%$(EXT): $(UNITOBJ)/%.o
49 @mkdir -p $(UNITTESTS)
50 $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
51
52$(UNITOBJ)/%.o : %.c
53$(UNITOBJ)/%.o: %.c $(DEPDIR)/%.d
54 @mkdir -p $(UNITOBJ)
55 $(CC) $(CFLAGS) $(DEPFLAGS) $(INCLUDES) -c $< -o $@
56 @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
57
58$(DEPDIR)/%.d: ;
59.PRECIOUS: $(DEPDIR)/%.d
60
61-include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))) \ No newline at end of file
diff --git a/quantum/serial_link/tests/byte_stuffer_tests.c b/quantum/serial_link/tests/byte_stuffer_tests.c
new file mode 100644
index 000000000..64b170e8c
--- /dev/null
+++ b/quantum/serial_link/tests/byte_stuffer_tests.c
@@ -0,0 +1,506 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/byte_stuffer.h"
28#include "serial_link/protocol/byte_stuffer.c"
29#include "serial_link/protocol/frame_validator.h"
30#include "serial_link/protocol/physical.h"
31
32static uint8_t sent_data[MAX_FRAME_SIZE*2];
33static uint16_t sent_data_size;
34
35Describe(ByteStuffer);
36BeforeEach(ByteStuffer) {
37 init_byte_stuffer();
38 sent_data_size = 0;
39}
40AfterEach(ByteStuffer) {}
41
42void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
43 mock(data, size);
44}
45
46void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
47 memcpy(sent_data + sent_data_size, data, size);
48 sent_data_size += size;
49}
50
51Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
52 never_expect(validator_recv_frame);
53 byte_stuffer_recv_byte(0, 0);
54}
55
56Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
57 never_expect(validator_recv_frame);
58 byte_stuffer_recv_byte(0, 0xFF);
59}
60
61Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
62 never_expect(validator_recv_frame);
63 byte_stuffer_recv_byte(0, 0x4A);
64}
65
66Ensure(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
67 never_expect(validator_recv_frame);
68 byte_stuffer_recv_byte(0, 1);
69 byte_stuffer_recv_byte(0, 0);
70}
71
72Ensure(ByteStuffer, receives_single_byte_valid_frame) {
73 uint8_t expected[] = {0x37};
74 expect(validator_recv_frame,
75 when(size, is_equal_to(1)),
76 when(data, is_equal_to_contents_of(expected, 1))
77 );
78 byte_stuffer_recv_byte(0, 2);
79 byte_stuffer_recv_byte(0, 0x37);
80 byte_stuffer_recv_byte(0, 0);
81}
82
83Ensure(ByteStuffer, receives_three_bytes_valid_frame) {
84 uint8_t expected[] = {0x37, 0x99, 0xFF};
85 expect(validator_recv_frame,
86 when(size, is_equal_to(3)),
87 when(data, is_equal_to_contents_of(expected, 3))
88 );
89 byte_stuffer_recv_byte(0, 4);
90 byte_stuffer_recv_byte(0, 0x37);
91 byte_stuffer_recv_byte(0, 0x99);
92 byte_stuffer_recv_byte(0, 0xFF);
93 byte_stuffer_recv_byte(0, 0);
94}
95
96Ensure(ByteStuffer, receives_single_zero_valid_frame) {
97 uint8_t expected[] = {0};
98 expect(validator_recv_frame,
99 when(size, is_equal_to(1)),
100 when(data, is_equal_to_contents_of(expected, 1))
101 );
102 byte_stuffer_recv_byte(0, 1);
103 byte_stuffer_recv_byte(0, 1);
104 byte_stuffer_recv_byte(0, 0);
105}
106
107Ensure(ByteStuffer, receives_valid_frame_with_zeroes) {
108 uint8_t expected[] = {5, 0, 3, 0};
109 expect(validator_recv_frame,
110 when(size, is_equal_to(4)),
111 when(data, is_equal_to_contents_of(expected, 4))
112 );
113 byte_stuffer_recv_byte(0, 2);
114 byte_stuffer_recv_byte(0, 5);
115 byte_stuffer_recv_byte(0, 2);
116 byte_stuffer_recv_byte(0, 3);
117 byte_stuffer_recv_byte(0, 1);
118 byte_stuffer_recv_byte(0, 0);
119}
120
121Ensure(ByteStuffer, receives_two_valid_frames) {
122 uint8_t expected1[] = {5, 0};
123 uint8_t expected2[] = {3};
124 expect(validator_recv_frame,
125 when(size, is_equal_to(2)),
126 when(data, is_equal_to_contents_of(expected1, 2))
127 );
128 expect(validator_recv_frame,
129 when(size, is_equal_to(1)),
130 when(data, is_equal_to_contents_of(expected2, 1))
131 );
132 byte_stuffer_recv_byte(1, 2);
133 byte_stuffer_recv_byte(1, 5);
134 byte_stuffer_recv_byte(1, 1);
135 byte_stuffer_recv_byte(1, 0);
136 byte_stuffer_recv_byte(1, 2);
137 byte_stuffer_recv_byte(1, 3);
138 byte_stuffer_recv_byte(1, 0);
139}
140
141Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
142 uint8_t expected[] = {5, 7};
143 expect(validator_recv_frame,
144 when(size, is_equal_to(2)),
145 when(data, is_equal_to_contents_of(expected, 2))
146 );
147 byte_stuffer_recv_byte(1, 3);
148 byte_stuffer_recv_byte(1, 1);
149 byte_stuffer_recv_byte(1, 0);
150 byte_stuffer_recv_byte(1, 3);
151 byte_stuffer_recv_byte(1, 5);
152 byte_stuffer_recv_byte(1, 7);
153 byte_stuffer_recv_byte(1, 0);
154}
155
156Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
157 uint8_t expected[] = {5, 7};
158 expect(validator_recv_frame,
159 when(size, is_equal_to(2)),
160 when(data, is_equal_to_contents_of(expected, 2))
161 );
162 byte_stuffer_recv_byte(0, 2);
163 byte_stuffer_recv_byte(0, 9);
164 byte_stuffer_recv_byte(0, 4); // This should have been zero
165 byte_stuffer_recv_byte(0, 0);
166 byte_stuffer_recv_byte(0, 3);
167 byte_stuffer_recv_byte(0, 5);
168 byte_stuffer_recv_byte(0, 7);
169 byte_stuffer_recv_byte(0, 0);
170}
171
172Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
173 uint8_t expected[254];
174 int i;
175 for (i=0;i<254;i++) {
176 expected[i] = i + 1;
177 }
178 expect(validator_recv_frame,
179 when(size, is_equal_to(254)),
180 when(data, is_equal_to_contents_of(expected, 254))
181 );
182 byte_stuffer_recv_byte(0, 0xFF);
183 for (i=0;i<254;i++) {
184 byte_stuffer_recv_byte(0, i+1);
185 }
186 byte_stuffer_recv_byte(0, 0);
187}
188
189Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
190 uint8_t expected[255];
191 int i;
192 for (i=0;i<254;i++) {
193 expected[i] = i + 1;
194 }
195 expected[254] = 7;
196 expect(validator_recv_frame,
197 when(size, is_equal_to(255)),
198 when(data, is_equal_to_contents_of(expected, 255))
199 );
200 byte_stuffer_recv_byte(0, 0xFF);
201 for (i=0;i<254;i++) {
202 byte_stuffer_recv_byte(0, i+1);
203 }
204 byte_stuffer_recv_byte(0, 2);
205 byte_stuffer_recv_byte(0, 7);
206 byte_stuffer_recv_byte(0, 0);
207}
208
209Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
210 uint8_t expected[255];
211 int i;
212 for (i=0;i<254;i++) {
213 expected[i] = i + 1;
214 }
215 expected[254] = 0;
216 expect(validator_recv_frame,
217 when(size, is_equal_to(255)),
218 when(data, is_equal_to_contents_of(expected, 255))
219 );
220 byte_stuffer_recv_byte(0, 0xFF);
221 for (i=0;i<254;i++) {
222 byte_stuffer_recv_byte(0, i+1);
223 }
224 byte_stuffer_recv_byte(0, 1);
225 byte_stuffer_recv_byte(0, 1);
226 byte_stuffer_recv_byte(0, 0);
227}
228
229Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
230 uint8_t expected[515];
231 int i;
232 int j;
233 for (j=0;j<2;j++) {
234 for (i=0;i<254;i++) {
235 expected[i+254*j] = i + 1;
236 }
237 }
238 for (i=0;i<7;i++) {
239 expected[254*2+i] = i + 1;
240 }
241 expect(validator_recv_frame,
242 when(size, is_equal_to(515)),
243 when(data, is_equal_to_contents_of(expected, 510))
244 );
245 byte_stuffer_recv_byte(0, 0xFF);
246 for (i=0;i<254;i++) {
247 byte_stuffer_recv_byte(0, i+1);
248 }
249 byte_stuffer_recv_byte(0, 0xFF);
250 for (i=0;i<254;i++) {
251 byte_stuffer_recv_byte(0, i+1);
252 }
253 byte_stuffer_recv_byte(0, 8);
254 byte_stuffer_recv_byte(0, 1);
255 byte_stuffer_recv_byte(0, 2);
256 byte_stuffer_recv_byte(0, 3);
257 byte_stuffer_recv_byte(0, 4);
258 byte_stuffer_recv_byte(0, 5);
259 byte_stuffer_recv_byte(0, 6);
260 byte_stuffer_recv_byte(0, 7);
261 byte_stuffer_recv_byte(0, 0);
262}
263
264Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
265 uint8_t expected[MAX_FRAME_SIZE] = {};
266 expect(validator_recv_frame,
267 when(size, is_equal_to(MAX_FRAME_SIZE)),
268 when(data, is_equal_to_contents_of(expected, MAX_FRAME_SIZE))
269 );
270 int i;
271 byte_stuffer_recv_byte(0, 1);
272 for(i=0;i<MAX_FRAME_SIZE;i++) {
273 byte_stuffer_recv_byte(0, 1);
274 }
275 byte_stuffer_recv_byte(0, 0);
276}
277
278Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
279 uint8_t expected[1] = {0};
280 never_expect(validator_recv_frame);
281 int i;
282 byte_stuffer_recv_byte(0, 1);
283 for(i=0;i<MAX_FRAME_SIZE;i++) {
284 byte_stuffer_recv_byte(0, 1);
285 }
286 byte_stuffer_recv_byte(0, 1);
287 byte_stuffer_recv_byte(0, 0);
288}
289
290Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
291 uint8_t expected[1] = {1};
292 expect(validator_recv_frame,
293 when(size, is_equal_to(1)),
294 when(data, is_equal_to_contents_of(expected, 1))
295 );
296 int i;
297 byte_stuffer_recv_byte(0, 1);
298 for(i=0;i<MAX_FRAME_SIZE;i++) {
299 byte_stuffer_recv_byte(0, 1);
300 }
301 byte_stuffer_recv_byte(0, 2);
302 byte_stuffer_recv_byte(0, 1);
303 byte_stuffer_recv_byte(0, 0);
304}
305
306Ensure(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
307 assert_that(sent_data_size, is_equal_to(0));
308 byte_stuffer_send_frame(0, NULL, 0);
309}
310
311Ensure(ByteStuffer, send_one_byte_frame) {
312 uint8_t data[] = {5};
313 byte_stuffer_send_frame(1, data, 1);
314 uint8_t expected[] = {2, 5, 0};
315 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
316 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
317}
318
319Ensure(ByteStuffer, sends_two_byte_frame) {
320 uint8_t data[] = {5, 0x77};
321 byte_stuffer_send_frame(0, data, 2);
322 uint8_t expected[] = {3, 5, 0x77, 0};
323 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
324 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
325}
326
327Ensure(ByteStuffer, sends_one_byte_frame_with_zero) {
328 uint8_t data[] = {0};
329 byte_stuffer_send_frame(0, data, 1);
330 uint8_t expected[] = {1, 1, 0};
331 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
332 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
333}
334
335Ensure(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
336 uint8_t data[] = {0, 9};
337 byte_stuffer_send_frame(1, data, 2);
338 uint8_t expected[] = {1, 2, 9, 0};
339 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
340 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
341}
342
343Ensure(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
344 uint8_t data[] = {9, 0};
345 byte_stuffer_send_frame(1, data, 2);
346 uint8_t expected[] = {2, 9, 1, 0};
347 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
348 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
349}
350
351Ensure(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
352 uint8_t data[] = {9, 0, 0x68};
353 byte_stuffer_send_frame(0, data, 3);
354 uint8_t expected[] = {2, 9, 2, 0x68, 0};
355 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
356 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
357}
358
359Ensure(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
360 uint8_t data[] = {0, 0x55, 0};
361 byte_stuffer_send_frame(0, data, 3);
362 uint8_t expected[] = {1, 2, 0x55, 1, 0};
363 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
364 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
365}
366
367Ensure(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
368 uint8_t data[] = {0, 0, 0};
369 byte_stuffer_send_frame(0, data, 3);
370 uint8_t expected[] = {1, 1, 1, 1, 0};
371 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
372 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
373}
374
375Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) {
376 uint8_t data[254];
377 int i;
378 for(i=0;i<254;i++) {
379 data[i] = i + 1;
380 }
381 byte_stuffer_send_frame(0, data, 254);
382 uint8_t expected[256];
383 expected[0] = 0xFF;
384 for(i=1;i<255;i++) {
385 expected[i] = i;
386 }
387 expected[255] = 0;
388 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
389 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
390}
391
392Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) {
393 uint8_t data[255];
394 int i;
395 for(i=0;i<255;i++) {
396 data[i] = i + 1;
397 }
398 byte_stuffer_send_frame(0, data, 255);
399 uint8_t expected[258];
400 expected[0] = 0xFF;
401 for(i=1;i<255;i++) {
402 expected[i] = i;
403 }
404 expected[255] = 2;
405 expected[256] = 255;
406 expected[257] = 0;
407 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
408 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
409}
410
411Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
412 uint8_t data[255];
413 int i;
414 for(i=0;i<254;i++) {
415 data[i] = i + 1;
416 }
417 data[255] = 0;
418 byte_stuffer_send_frame(0, data, 255);
419 uint8_t expected[258];
420 expected[0] = 0xFF;
421 for(i=1;i<255;i++) {
422 expected[i] = i;
423 }
424 expected[255] = 1;
425 expected[256] = 1;
426 expected[257] = 0;
427 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
428 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
429}
430
431Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
432 uint8_t original_data[] = { 1, 2, 3};
433 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
434 expect(validator_recv_frame,
435 when(size, is_equal_to(sizeof(original_data))),
436 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
437 );
438 int i;
439 for(i=0;i<sent_data_size;i++) {
440 byte_stuffer_recv_byte(1, sent_data[i]);
441 }
442}
443
444Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
445 uint8_t original_data[] = { 1, 0, 3, 0, 0, 9};
446 byte_stuffer_send_frame(1, original_data, sizeof(original_data));
447 expect(validator_recv_frame,
448 when(size, is_equal_to(sizeof(original_data))),
449 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
450 );
451 int i;
452 for(i=0;i<sent_data_size;i++) {
453 byte_stuffer_recv_byte(0, sent_data[i]);
454 }
455}
456
457Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
458 uint8_t original_data[254];
459 int i;
460 for(i=0;i<254;i++) {
461 original_data[i] = i + 1;
462 }
463 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
464 expect(validator_recv_frame,
465 when(size, is_equal_to(sizeof(original_data))),
466 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
467 );
468 for(i=0;i<sent_data_size;i++) {
469 byte_stuffer_recv_byte(1, sent_data[i]);
470 }
471}
472
473Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
474 uint8_t original_data[256];
475 int i;
476 for(i=0;i<254;i++) {
477 original_data[i] = i + 1;
478 }
479 original_data[254] = 22;
480 original_data[255] = 23;
481 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
482 expect(validator_recv_frame,
483 when(size, is_equal_to(sizeof(original_data))),
484 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
485 );
486 for(i=0;i<sent_data_size;i++) {
487 byte_stuffer_recv_byte(1, sent_data[i]);
488 }
489}
490
491Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
492 uint8_t original_data[255];
493 int i;
494 for(i=0;i<254;i++) {
495 original_data[i] = i + 1;
496 }
497 original_data[254] = 0;
498 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
499 expect(validator_recv_frame,
500 when(size, is_equal_to(sizeof(original_data))),
501 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
502 );
503 for(i=0;i<sent_data_size;i++) {
504 byte_stuffer_recv_byte(1, sent_data[i]);
505 }
506}
diff --git a/quantum/serial_link/tests/frame_router_tests.c b/quantum/serial_link/tests/frame_router_tests.c
new file mode 100644
index 000000000..6c806fa93
--- /dev/null
+++ b/quantum/serial_link/tests/frame_router_tests.c
@@ -0,0 +1,231 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/byte_stuffer.c"
28#include "serial_link/protocol/frame_validator.c"
29#include "serial_link/protocol/frame_router.c"
30#include "serial_link/protocol/transport.h"
31
32static uint8_t received_data[256];
33static uint16_t received_data_size;
34
35typedef struct {
36 uint8_t sent_data[256];
37 uint16_t sent_data_size;
38} receive_buffer_t;
39
40typedef struct {
41 receive_buffer_t send_buffers[2];
42} router_buffer_t;
43
44router_buffer_t router_buffers[8];
45
46router_buffer_t* current_router_buffer;
47
48
49Describe(FrameRouter);
50BeforeEach(FrameRouter) {
51 init_byte_stuffer();
52 memset(router_buffers, 0, sizeof(router_buffers));
53 current_router_buffer = 0;
54}
55AfterEach(FrameRouter) {}
56
57typedef struct {
58 uint32_t data;
59 uint8_t extra[16];
60} frame_buffer_t;
61
62
63void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
64 receive_buffer_t* buffer = &current_router_buffer->send_buffers[link];
65 memcpy(buffer->sent_data + buffer->sent_data_size, data, size);
66 buffer->sent_data_size += size;
67}
68
69static void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
70 int i;
71 for(i=0;i<size;i++) {
72 byte_stuffer_recv_byte(link, data[i]);
73 }
74}
75
76static void activate_router(uint8_t num) {
77 current_router_buffer = router_buffers + num;
78 router_set_master(num==0);
79}
80
81static void simulate_transport(uint8_t from, uint8_t to) {
82 activate_router(to);
83 if (from > to) {
84 receive_data(DOWN_LINK,
85 router_buffers[from].send_buffers[UP_LINK].sent_data,
86 router_buffers[from].send_buffers[UP_LINK].sent_data_size);
87 }
88 else if(to > from) {
89 receive_data(UP_LINK,
90 router_buffers[from].send_buffers[DOWN_LINK].sent_data,
91 router_buffers[from].send_buffers[DOWN_LINK].sent_data_size);
92 }
93}
94
95void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
96 mock(from, data, size);
97}
98
99
100Ensure(FrameRouter, master_broadcast_is_received_by_everyone) {
101 frame_buffer_t data;
102 data.data = 0xAB7055BB;
103 activate_router(0);
104 router_send_frame(0xFF, (uint8_t*)&data, 4);
105 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
106 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
107
108 expect(transport_recv_frame,
109 when(from, is_equal_to(0)),
110 when(size, is_equal_to(4)),
111 when(data, is_equal_to_contents_of(&data.data, 4))
112 );
113 simulate_transport(0, 1);
114 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
115 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
116
117 expect(transport_recv_frame,
118 when(from, is_equal_to(0)),
119 when(size, is_equal_to(4)),
120 when(data, is_equal_to_contents_of(&data.data, 4))
121 );
122 simulate_transport(1, 2);
123 assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
124 assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
125}
126
127Ensure(FrameRouter, master_send_is_received_by_targets) {
128 frame_buffer_t data;
129 data.data = 0xAB7055BB;
130 activate_router(0);
131 router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
132 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
133 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
134
135 simulate_transport(0, 1);
136 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
137 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
138
139 expect(transport_recv_frame,
140 when(from, is_equal_to(0)),
141 when(size, is_equal_to(4)),
142 when(data, is_equal_to_contents_of(&data.data, 4))
143 );
144 simulate_transport(1, 2);
145 assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
146 assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
147
148 expect(transport_recv_frame,
149 when(from, is_equal_to(0)),
150 when(size, is_equal_to(4)),
151 when(data, is_equal_to_contents_of(&data.data, 4))
152 );
153 simulate_transport(2, 3);
154 assert_that(router_buffers[3].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
155 assert_that(router_buffers[3].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
156}
157
158Ensure(FrameRouter, first_link_sends_to_master) {
159 frame_buffer_t data;
160 data.data = 0xAB7055BB;
161 activate_router(1);
162 router_send_frame(0, (uint8_t*)&data, 4);
163 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
164 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
165
166 expect(transport_recv_frame,
167 when(from, is_equal_to(1)),
168 when(size, is_equal_to(4)),
169 when(data, is_equal_to_contents_of(&data.data, 4))
170 );
171 simulate_transport(1, 0);
172 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
173 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
174}
175
176Ensure(FrameRouter, second_link_sends_to_master) {
177 frame_buffer_t data;
178 data.data = 0xAB7055BB;
179 activate_router(2);
180 router_send_frame(0, (uint8_t*)&data, 4);
181 assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
182 assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
183
184 simulate_transport(2, 1);
185 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
186 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
187
188 expect(transport_recv_frame,
189 when(from, is_equal_to(2)),
190 when(size, is_equal_to(4)),
191 when(data, is_equal_to_contents_of(&data.data, 4))
192 );
193 simulate_transport(1, 0);
194 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
195 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
196}
197
198Ensure(FrameRouter, master_sends_to_master_does_nothing) {
199 frame_buffer_t data;
200 data.data = 0xAB7055BB;
201 activate_router(0);
202 router_send_frame(0, (uint8_t*)&data, 4);
203 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
204 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
205}
206
207Ensure(FrameRouter, link_sends_to_other_link_does_nothing) {
208 frame_buffer_t data;
209 data.data = 0xAB7055BB;
210 activate_router(1);
211 router_send_frame(2, (uint8_t*)&data, 4);
212 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
213 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
214}
215
216Ensure(FrameRouter, master_receives_on_uplink_does_nothing) {
217 frame_buffer_t data;
218 data.data = 0xAB7055BB;
219 activate_router(1);
220 router_send_frame(0, (uint8_t*)&data, 4);
221 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
222 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
223
224 never_expect(transport_recv_frame);
225 activate_router(0);
226 receive_data(UP_LINK,
227 router_buffers[1].send_buffers[UP_LINK].sent_data,
228 router_buffers[1].send_buffers[UP_LINK].sent_data_size);
229 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
230 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
231}
diff --git a/quantum/serial_link/tests/frame_validator_tests.c b/quantum/serial_link/tests/frame_validator_tests.c
new file mode 100644
index 000000000..d20947e2c
--- /dev/null
+++ b/quantum/serial_link/tests/frame_validator_tests.c
@@ -0,0 +1,101 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/frame_validator.c"
28
29void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) {
30 mock(data, size);
31}
32
33void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
34 mock(data, size);
35}
36
37Describe(FrameValidator);
38BeforeEach(FrameValidator) {}
39AfterEach(FrameValidator) {}
40
41Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) {
42 never_expect(route_incoming_frame);
43 uint8_t data[] = {1, 2};
44 validator_recv_frame(0, 0, 1);
45 validator_recv_frame(0, data, 2);
46 validator_recv_frame(0, data, 3);
47 validator_recv_frame(0, data, 4);
48}
49
50Ensure(FrameValidator, validates_one_byte_frame_with_correct_crc) {
51 uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
52 expect(route_incoming_frame,
53 when(size, is_equal_to(1)),
54 when(data, is_equal_to_contents_of(data, 1))
55 );
56 validator_recv_frame(0, data, 5);
57}
58
59Ensure(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
60 uint8_t data[] = {0x44, 0, 0, 0, 0};
61 never_expect(route_incoming_frame);
62 validator_recv_frame(1, data, 5);
63}
64
65Ensure(FrameValidator, validates_four_byte_frame_with_correct_crc) {
66 uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA};
67 expect(route_incoming_frame,
68 when(size, is_equal_to(4)),
69 when(data, is_equal_to_contents_of(data, 4))
70 );
71 validator_recv_frame(1, data, 8);
72}
73
74Ensure(FrameValidator, validates_five_byte_frame_with_correct_crc) {
75 uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
76 expect(route_incoming_frame,
77 when(size, is_equal_to(5)),
78 when(data, is_equal_to_contents_of(data, 5))
79 );
80 validator_recv_frame(0, data, 9);
81}
82
83Ensure(FrameValidator, sends_one_byte_with_correct_crc) {
84 uint8_t original[] = {0x44, 0, 0, 0, 0};
85 uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
86 expect(byte_stuffer_send_frame,
87 when(size, is_equal_to(sizeof(expected))),
88 when(data, is_equal_to_contents_of(expected, sizeof(expected)))
89 );
90 validator_send_frame(0, original, 1);
91}
92
93Ensure(FrameValidator, sends_five_bytes_with_correct_crc) {
94 uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0};
95 uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
96 expect(byte_stuffer_send_frame,
97 when(size, is_equal_to(sizeof(expected))),
98 when(data, is_equal_to_contents_of(expected, sizeof(expected)))
99 );
100 validator_send_frame(0, original, 5);
101}
diff --git a/quantum/serial_link/tests/transport_tests.c b/quantum/serial_link/tests/transport_tests.c
new file mode 100644
index 000000000..358e1b9fd
--- /dev/null
+++ b/quantum/serial_link/tests/transport_tests.c
@@ -0,0 +1,168 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/transport.c"
28#include "serial_link/protocol/triple_buffered_object.c"
29
30void signal_data_written(void) {
31 mock();
32}
33
34static uint8_t sent_data[2048];
35static uint16_t sent_data_size;
36
37void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
38 mock(destination);
39 memcpy(sent_data + sent_data_size, data, size);
40 sent_data_size += size;
41}
42
43typedef struct {
44 uint32_t test;
45} test_object1_t;
46
47typedef struct {
48 uint32_t test1;
49 uint32_t test2;
50} test_object2_t;
51
52MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t);
53MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t);
54SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t);
55
56static remote_object_t* test_remote_objects[] = {
57 REMOTE_OBJECT(master_to_slave),
58 REMOTE_OBJECT(master_to_single_slave),
59 REMOTE_OBJECT(slave_to_master),
60};
61
62Describe(Transport);
63BeforeEach(Transport) {
64 add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
65 sent_data_size = 0;
66}
67AfterEach(Transport) {}
68
69Ensure(Transport, write_to_local_signals_an_event) {
70 begin_write_master_to_slave();
71 expect(signal_data_written);
72 end_write_master_to_slave();
73 begin_write_slave_to_master();
74 expect(signal_data_written);
75 end_write_slave_to_master();
76 begin_write_master_to_single_slave(1);
77 expect(signal_data_written);
78 end_write_master_to_single_slave(1);
79}
80
81Ensure(Transport, writes_from_master_to_all_slaves) {
82 update_transport();
83 test_object1_t* obj = begin_write_master_to_slave();
84 obj->test = 5;
85 expect(signal_data_written);
86 end_write_master_to_slave();
87 expect(router_send_frame,
88 when(destination, is_equal_to(0xFF)));
89 update_transport();
90 transport_recv_frame(0, sent_data, sent_data_size);
91 test_object1_t* obj2 = read_master_to_slave();
92 assert_that(obj2, is_not_equal_to(NULL));
93 assert_that(obj2->test, is_equal_to(5));
94}
95
96Ensure(Transport, writes_from_slave_to_master) {
97 update_transport();
98 test_object1_t* obj = begin_write_slave_to_master();
99 obj->test = 7;
100 expect(signal_data_written);
101 end_write_slave_to_master();
102 expect(router_send_frame,
103 when(destination, is_equal_to(0)));
104 update_transport();
105 transport_recv_frame(3, sent_data, sent_data_size);
106 test_object1_t* obj2 = read_slave_to_master(2);
107 assert_that(read_slave_to_master(0), is_equal_to(NULL));
108 assert_that(obj2, is_not_equal_to(NULL));
109 assert_that(obj2->test, is_equal_to(7));
110}
111
112Ensure(Transport, writes_from_master_to_single_slave) {
113 update_transport();
114 test_object1_t* obj = begin_write_master_to_single_slave(3);
115 obj->test = 7;
116 expect(signal_data_written);
117 end_write_master_to_single_slave(3);
118 expect(router_send_frame,
119 when(destination, is_equal_to(4)));
120 update_transport();
121 transport_recv_frame(0, sent_data, sent_data_size);
122 test_object1_t* obj2 = read_master_to_single_slave();
123 assert_that(obj2, is_not_equal_to(NULL));
124 assert_that(obj2->test, is_equal_to(7));
125}
126
127Ensure(Transport, ignores_object_with_invalid_id) {
128 update_transport();
129 test_object1_t* obj = begin_write_master_to_single_slave(3);
130 obj->test = 7;
131 expect(signal_data_written);
132 end_write_master_to_single_slave(3);
133 expect(router_send_frame,
134 when(destination, is_equal_to(4)));
135 update_transport();
136 sent_data[sent_data_size - 1] = 44;
137 transport_recv_frame(0, sent_data, sent_data_size);
138 test_object1_t* obj2 = read_master_to_single_slave();
139 assert_that(obj2, is_equal_to(NULL));
140}
141
142Ensure(Transport, ignores_object_with_size_too_small) {
143 update_transport();
144 test_object1_t* obj = begin_write_master_to_slave();
145 obj->test = 7;
146 expect(signal_data_written);
147 end_write_master_to_slave();
148 expect(router_send_frame);
149 update_transport();
150 sent_data[sent_data_size - 2] = 0;
151 transport_recv_frame(0, sent_data, sent_data_size - 1);
152 test_object1_t* obj2 = read_master_to_slave();
153 assert_that(obj2, is_equal_to(NULL));
154}
155
156Ensure(Transport, ignores_object_with_size_too_big) {
157 update_transport();
158 test_object1_t* obj = begin_write_master_to_slave();
159 obj->test = 7;
160 expect(signal_data_written);
161 end_write_master_to_slave();
162 expect(router_send_frame);
163 update_transport();
164 sent_data[sent_data_size + 21] = 0;
165 transport_recv_frame(0, sent_data, sent_data_size + 22);
166 test_object1_t* obj2 = read_master_to_slave();
167 assert_that(obj2, is_equal_to(NULL));
168}
diff --git a/quantum/serial_link/tests/triple_buffered_object_tests.c b/quantum/serial_link/tests/triple_buffered_object_tests.c
new file mode 100644
index 000000000..6f7c82b46
--- /dev/null
+++ b/quantum/serial_link/tests/triple_buffered_object_tests.c
@@ -0,0 +1,82 @@
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 <cgreen/cgreen.h>
26#include "serial_link/protocol/triple_buffered_object.c"
27
28typedef struct {
29 uint8_t state;
30 uint32_t buffer[3];
31}test_object_t;
32
33test_object_t test_object;
34
35Describe(TripleBufferedObject);
36BeforeEach(TripleBufferedObject) {
37 triple_buffer_init((triple_buffer_object_t*)&test_object);
38}
39AfterEach(TripleBufferedObject) {}
40
41
42Ensure(TripleBufferedObject, writes_and_reads_object) {
43 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
44 triple_buffer_end_write(&test_object);
45 assert_that(*triple_buffer_read(&test_object), is_equal_to(0x3456ABCC));
46}
47
48Ensure(TripleBufferedObject, does_not_read_empty) {
49 assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
50}
51
52Ensure(TripleBufferedObject, writes_twice_and_reads_object) {
53 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
54 triple_buffer_end_write(&test_object);
55 *triple_buffer_begin_write(&test_object) = 0x44778899;
56 triple_buffer_end_write(&test_object);
57 assert_that(*triple_buffer_read(&test_object), is_equal_to(0x44778899));
58}
59
60Ensure(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
61 *triple_buffer_begin_write(&test_object) = 1;
62 triple_buffer_end_write(&test_object);
63 uint32_t* read = triple_buffer_read(&test_object);
64 *triple_buffer_begin_write(&test_object) = 2;
65 triple_buffer_end_write(&test_object);
66 assert_that(*read, is_equal_to(1));
67 assert_that(*triple_buffer_read(&test_object), is_equal_to(2));
68 assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
69}
70
71Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
72 *triple_buffer_begin_write(&test_object) = 1;
73 triple_buffer_end_write(&test_object);
74 uint32_t* read = triple_buffer_read(&test_object);
75 *triple_buffer_begin_write(&test_object) = 2;
76 triple_buffer_end_write(&test_object);
77 *triple_buffer_begin_write(&test_object) = 3;
78 triple_buffer_end_write(&test_object);
79 assert_that(*read, is_equal_to(1));
80 assert_that(*triple_buffer_read(&test_object), is_equal_to(3));
81 assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
82}