diff options
author | Jack Humbert <jack.humb@gmail.com> | 2016-07-06 08:56:57 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-06 08:56:57 -0400 |
commit | c6d671e54c249497b5c01ad9badaa50425f394f9 (patch) | |
tree | 69685292a135d5d342f34955dae348c405871f4e | |
parent | 3577e26fd9916ceab58779ec6323d43da54eb3b5 (diff) | |
parent | d5e7603d551a31836bf0c59db259ddc3593a1aa7 (diff) | |
download | qmk_firmware-c6d671e54c249497b5c01ad9badaa50425f394f9.tar.gz qmk_firmware-c6d671e54c249497b5c01ad9badaa50425f394f9.zip |
Merge pull request #482 from fredizzimo/serial_link
Add serial link library
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 @@ | |||
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. | ||
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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
37 | typedef 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 | |||
44 | static byte_stuffer_state_t states[NUM_LINKS]; | ||
45 | |||
46 | void 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 | |||
52 | void 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 | |||
59 | void 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 | |||
108 | static 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 | |||
115 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_BYTE_STUFFER_H | ||
26 | #define SERIAL_LINK_BYTE_STUFFER_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | void init_byte_stuffer(void); | ||
31 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data); | ||
32 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
29 | static bool is_master; | ||
30 | |||
31 | void router_set_master(bool master) { | ||
32 | is_master = master; | ||
33 | } | ||
34 | |||
35 | void 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 | |||
56 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
34 | void router_set_master(bool master); | ||
35 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
36 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
30 | const 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 | |||
98 | static 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 | |||
106 | void 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 | |||
117 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_FRAME_VALIDATOR_H | ||
26 | #define SERIAL_LINK_FRAME_VALIDATOR_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
31 | // The buffer pointed to by the data needs 4 additional bytes | ||
32 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_PHYSICAL_H | ||
26 | #define SERIAL_LINK_PHYSICAL_H | ||
27 | |||
28 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | ||
31 | static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS]; | ||
32 | static uint32_t num_remote_objects = 0; | ||
33 | |||
34 | void 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 | |||
72 | void 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 | |||
96 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | ||
37 | typedef enum { | ||
38 | MASTER_TO_ALL_SLAVES, | ||
39 | MASTER_TO_SINGLE_SLAVE, | ||
40 | SLAVE_TO_MASTER, | ||
41 | } remote_object_type; | ||
42 | |||
43 | typedef 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) \ | ||
55 | typedef 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 | |||
147 | void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects); | ||
148 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size); | ||
149 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
40 | void 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 | |||
48 | void* 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 | |||
65 | void* 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 | |||
70 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H | ||
26 | #define SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | typedef struct { | ||
31 | uint8_t state; | ||
32 | uint8_t buffer[] __attribute__((aligned(4))); | ||
33 | }triple_buffer_object_t; | ||
34 | |||
35 | void 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 | |||
46 | void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object); | ||
47 | void triple_buffer_end_write_internal(triple_buffer_object_t* object); | ||
48 | void* 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
36 | static event_source_t new_data_event; | ||
37 | static bool serial_link_connected; | ||
38 | static bool is_master = false; | ||
39 | |||
40 | static uint8_t keyboard_leds(void); | ||
41 | static void send_keyboard(report_keyboard_t *report); | ||
42 | static void send_mouse(report_mouse_t *report); | ||
43 | static void send_system(uint16_t data); | ||
44 | static void send_consumer(uint16_t data); | ||
45 | |||
46 | host_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 | |||
63 | static SerialConfig config = { | ||
64 | .sc_speed = SERIAL_LINK_BAUD | ||
65 | }; | ||
66 | |||
67 | //#define DEBUG_LINK_ERRORS | ||
68 | |||
69 | static 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 | |||
82 | static 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 | |||
113 | bool is_serial_link_master(void) { | ||
114 | return is_master; | ||
115 | } | ||
116 | |||
117 | // TODO: Optimize the stack size, this is probably way too big | ||
118 | static THD_WORKING_AREA(serialThreadStack, 1024); | ||
119 | static 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 | |||
162 | void 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 | |||
171 | static systime_t last_update = 0; | ||
172 | |||
173 | typedef struct { | ||
174 | matrix_row_t rows[MATRIX_ROWS]; | ||
175 | } matrix_object_t; | ||
176 | |||
177 | static matrix_object_t last_matrix = {}; | ||
178 | |||
179 | SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t); | ||
180 | MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool); | ||
181 | |||
182 | static remote_object_t* remote_objects[] = { | ||
183 | REMOTE_OBJECT(serial_link_connected), | ||
184 | REMOTE_OBJECT(keyboard_matrix), | ||
185 | }; | ||
186 | |||
187 | void 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 | |||
199 | void matrix_set_remote(matrix_row_t* rows, uint8_t index); | ||
200 | |||
201 | void 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 | |||
233 | void signal_data_written(void) { | ||
234 | chEvtBroadcast(&new_data_event); | ||
235 | } | ||
236 | |||
237 | bool is_serial_link_connected(void) { | ||
238 | return serial_link_connected; | ||
239 | } | ||
240 | |||
241 | host_driver_t* get_serial_link_driver(void) { | ||
242 | return &serial_driver; | ||
243 | } | ||
244 | |||
245 | // NOTE: The driver does nothing, because the master handles everything | ||
246 | uint8_t keyboard_leds(void) { | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | void send_keyboard(report_keyboard_t *report) { | ||
251 | (void)report; | ||
252 | } | ||
253 | |||
254 | void send_mouse(report_mouse_t *report) { | ||
255 | (void)report; | ||
256 | } | ||
257 | |||
258 | void send_system(uint16_t data) { | ||
259 | (void)data; | ||
260 | } | ||
261 | |||
262 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_H | ||
26 | #define SERIAL_LINK_H | ||
27 | |||
28 | #include "host_driver.h" | ||
29 | #include <stdbool.h> | ||
30 | |||
31 | void init_serial_link(void); | ||
32 | void init_serial_link_hal(void); | ||
33 | bool is_serial_link_connected(void); | ||
34 | bool is_serial_link_master(void); | ||
35 | host_driver_t* get_serial_link_driver(void); | ||
36 | void serial_link_update(void); | ||
37 | |||
38 | #if defined(PROTOCOL_CHIBIOS) | ||
39 | #include "ch.h" | ||
40 | |||
41 | static inline void serial_link_lock(void) { | ||
42 | chSysLock(); | ||
43 | } | ||
44 | |||
45 | static inline void serial_link_unlock(void) { | ||
46 | chSysUnlock(); | ||
47 | } | ||
48 | |||
49 | void signal_data_written(void); | ||
50 | |||
51 | #else | ||
52 | |||
53 | inline void serial_link_lock(void) { | ||
54 | } | ||
55 | |||
56 | inline void serial_link_unlock(void) { | ||
57 | } | ||
58 | |||
59 | void 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 | |||
23 | CC = gcc | ||
24 | CFLAGS = | ||
25 | INCLUDES = -I. -I../../ | ||
26 | LDFLAGS = -L$(BUILDDIR)/cgreen/build-c/src -shared | ||
27 | LDLIBS = -lcgreen | ||
28 | UNITOBJ = $(BUILDDIR)/serialtest/unitobj | ||
29 | DEPDIR = $(BUILDDIR)/serialtest/unit.d | ||
30 | UNITTESTS = $(BUILDDIR)/serialtest/unittests | ||
31 | DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td | ||
32 | EXT = .so | ||
33 | UNAME := $(shell uname) | ||
34 | ifneq (, $(findstring MINGW, $(UNAME))) | ||
35 | EXT = .dll | ||
36 | endif | ||
37 | ifneq (, $(findstring CYGWIN, $(UNAME))) | ||
38 | EXT = .dll | ||
39 | endif | ||
40 | |||
41 | SRC = $(wildcard *.c) | ||
42 | TESTFILES = $(patsubst %.c, $(UNITTESTS)/%$(EXT), $(SRC)) | ||
43 | $(shell mkdir -p $(DEPDIR) >/dev/null) | ||
44 | |||
45 | test: $(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
32 | static uint8_t sent_data[MAX_FRAME_SIZE*2]; | ||
33 | static uint16_t sent_data_size; | ||
34 | |||
35 | Describe(ByteStuffer); | ||
36 | BeforeEach(ByteStuffer) { | ||
37 | init_byte_stuffer(); | ||
38 | sent_data_size = 0; | ||
39 | } | ||
40 | AfterEach(ByteStuffer) {} | ||
41 | |||
42 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
43 | mock(data, size); | ||
44 | } | ||
45 | |||
46 | void 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 | |||
51 | Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { | ||
52 | never_expect(validator_recv_frame); | ||
53 | byte_stuffer_recv_byte(0, 0); | ||
54 | } | ||
55 | |||
56 | Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { | ||
57 | never_expect(validator_recv_frame); | ||
58 | byte_stuffer_recv_byte(0, 0xFF); | ||
59 | } | ||
60 | |||
61 | Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) { | ||
62 | never_expect(validator_recv_frame); | ||
63 | byte_stuffer_recv_byte(0, 0x4A); | ||
64 | } | ||
65 | |||
66 | Ensure(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 | |||
72 | Ensure(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 | |||
83 | Ensure(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 | |||
96 | Ensure(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 | |||
107 | Ensure(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 | |||
121 | Ensure(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 | |||
141 | Ensure(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 | |||
156 | Ensure(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 | |||
172 | Ensure(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 | |||
189 | Ensure(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 | |||
209 | Ensure(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 | |||
229 | Ensure(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 | |||
264 | Ensure(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 | |||
278 | Ensure(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 | |||
290 | Ensure(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 | |||
306 | Ensure(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 | |||
311 | Ensure(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 | |||
319 | Ensure(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 | |||
327 | Ensure(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 | |||
335 | Ensure(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 | |||
343 | Ensure(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 | |||
351 | Ensure(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 | |||
359 | Ensure(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 | |||
367 | Ensure(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 | |||
375 | Ensure(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 | |||
392 | Ensure(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 | |||
411 | Ensure(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 | |||
431 | Ensure(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 | |||
444 | Ensure(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 | |||
457 | Ensure(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 | |||
473 | Ensure(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 | |||
491 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
32 | static uint8_t received_data[256]; | ||
33 | static uint16_t received_data_size; | ||
34 | |||
35 | typedef struct { | ||
36 | uint8_t sent_data[256]; | ||
37 | uint16_t sent_data_size; | ||
38 | } receive_buffer_t; | ||
39 | |||
40 | typedef struct { | ||
41 | receive_buffer_t send_buffers[2]; | ||
42 | } router_buffer_t; | ||
43 | |||
44 | router_buffer_t router_buffers[8]; | ||
45 | |||
46 | router_buffer_t* current_router_buffer; | ||
47 | |||
48 | |||
49 | Describe(FrameRouter); | ||
50 | BeforeEach(FrameRouter) { | ||
51 | init_byte_stuffer(); | ||
52 | memset(router_buffers, 0, sizeof(router_buffers)); | ||
53 | current_router_buffer = 0; | ||
54 | } | ||
55 | AfterEach(FrameRouter) {} | ||
56 | |||
57 | typedef struct { | ||
58 | uint32_t data; | ||
59 | uint8_t extra[16]; | ||
60 | } frame_buffer_t; | ||
61 | |||
62 | |||
63 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
64 | receive_buffer_t* buffer = ¤t_router_buffer->send_buffers[link]; | ||
65 | memcpy(buffer->sent_data + buffer->sent_data_size, data, size); | ||
66 | buffer->sent_data_size += size; | ||
67 | } | ||
68 | |||
69 | static 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 | |||
76 | static void activate_router(uint8_t num) { | ||
77 | current_router_buffer = router_buffers + num; | ||
78 | router_set_master(num==0); | ||
79 | } | ||
80 | |||
81 | static 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 | |||
95 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { | ||
96 | mock(from, data, size); | ||
97 | } | ||
98 | |||
99 | |||
100 | Ensure(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 | |||
127 | Ensure(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 | |||
158 | Ensure(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 | |||
176 | Ensure(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 | |||
198 | Ensure(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 | |||
207 | Ensure(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 | |||
216 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #include <cgreen/cgreen.h> | ||
26 | #include <cgreen/mocks.h> | ||
27 | #include "serial_link/protocol/frame_validator.c" | ||
28 | |||
29 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
30 | mock(data, size); | ||
31 | } | ||
32 | |||
33 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
34 | mock(data, size); | ||
35 | } | ||
36 | |||
37 | Describe(FrameValidator); | ||
38 | BeforeEach(FrameValidator) {} | ||
39 | AfterEach(FrameValidator) {} | ||
40 | |||
41 | Ensure(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 | |||
50 | Ensure(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 | |||
59 | Ensure(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 | |||
65 | Ensure(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 | |||
74 | Ensure(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 | |||
83 | Ensure(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 | |||
93 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
30 | void signal_data_written(void) { | ||
31 | mock(); | ||
32 | } | ||
33 | |||
34 | static uint8_t sent_data[2048]; | ||
35 | static uint16_t sent_data_size; | ||
36 | |||
37 | void 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 | |||
43 | typedef struct { | ||
44 | uint32_t test; | ||
45 | } test_object1_t; | ||
46 | |||
47 | typedef struct { | ||
48 | uint32_t test1; | ||
49 | uint32_t test2; | ||
50 | } test_object2_t; | ||
51 | |||
52 | MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t); | ||
53 | MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t); | ||
54 | SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t); | ||
55 | |||
56 | static 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 | |||
62 | Describe(Transport); | ||
63 | BeforeEach(Transport) { | ||
64 | add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); | ||
65 | sent_data_size = 0; | ||
66 | } | ||
67 | AfterEach(Transport) {} | ||
68 | |||
69 | Ensure(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 | |||
81 | Ensure(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 | |||
96 | Ensure(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 | |||
112 | Ensure(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 | |||
127 | Ensure(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 | |||
142 | Ensure(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 | |||
156 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #include <cgreen/cgreen.h> | ||
26 | #include "serial_link/protocol/triple_buffered_object.c" | ||
27 | |||
28 | typedef struct { | ||
29 | uint8_t state; | ||
30 | uint32_t buffer[3]; | ||
31 | }test_object_t; | ||
32 | |||
33 | test_object_t test_object; | ||
34 | |||
35 | Describe(TripleBufferedObject); | ||
36 | BeforeEach(TripleBufferedObject) { | ||
37 | triple_buffer_init((triple_buffer_object_t*)&test_object); | ||
38 | } | ||
39 | AfterEach(TripleBufferedObject) {} | ||
40 | |||
41 | |||
42 | Ensure(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 | |||
48 | Ensure(TripleBufferedObject, does_not_read_empty) { | ||
49 | assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); | ||
50 | } | ||
51 | |||
52 | Ensure(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 | |||
60 | Ensure(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 | |||
71 | Ensure(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 | } | ||