aboutsummaryrefslogtreecommitdiff
path: root/quantum/serial_link/system/serial_link.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/serial_link/system/serial_link.c')
-rw-r--r--quantum/serial_link/system/serial_link.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/quantum/serial_link/system/serial_link.c b/quantum/serial_link/system/serial_link.c
new file mode 100644
index 000000000..75c7e77a7
--- /dev/null
+++ b/quantum/serial_link/system/serial_link.c
@@ -0,0 +1,265 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24#include "report.h"
25#include "host_driver.h"
26#include "serial_link/system/serial_link.h"
27#include "hal.h"
28#include "serial_link/protocol/byte_stuffer.h"
29#include "serial_link/protocol/transport.h"
30#include "serial_link/protocol/frame_router.h"
31#include "matrix.h"
32#include <stdbool.h>
33#include "print.h"
34#include "config.h"
35
36static event_source_t new_data_event;
37static bool serial_link_connected;
38static bool is_master = false;
39
40static uint8_t keyboard_leds(void);
41static void send_keyboard(report_keyboard_t *report);
42static void send_mouse(report_mouse_t *report);
43static void send_system(uint16_t data);
44static void send_consumer(uint16_t data);
45
46host_driver_t serial_driver = {
47 keyboard_leds,
48 send_keyboard,
49 send_mouse,
50 send_system,
51 send_consumer
52};
53
54// Define these in your Config.h file
55#ifndef SERIAL_LINK_BAUD
56#error "Serial link baud is not set"
57#endif
58
59#ifndef SERIAL_LINK_THREAD_PRIORITY
60#error "Serial link thread priority not set"
61#endif
62
63static SerialConfig config = {
64 .sc_speed = SERIAL_LINK_BAUD
65};
66
67//#define DEBUG_LINK_ERRORS
68
69static uint32_t read_from_serial(SerialDriver* driver, uint8_t link) {
70 const uint32_t buffer_size = 16;
71 uint8_t buffer[buffer_size];
72 uint32_t bytes_read = sdAsynchronousRead(driver, buffer, buffer_size);
73 uint8_t* current = buffer;
74 uint8_t* end = current + bytes_read;
75 while(current < end) {
76 byte_stuffer_recv_byte(link, *current);
77 current++;
78 }
79 return bytes_read;
80}
81
82static void print_error(char* str, eventflags_t flags, SerialDriver* driver) {
83#ifdef DEBUG_LINK_ERRORS
84 if (flags & SD_PARITY_ERROR) {
85 print(str);
86 print(" Parity error\n");
87 }
88 if (flags & SD_FRAMING_ERROR) {
89 print(str);
90 print(" Framing error\n");
91 }
92 if (flags & SD_OVERRUN_ERROR) {
93 print(str);
94 uint32_t size = qSpaceI(&(driver->iqueue));
95 xprintf(" Overrun error, queue size %d\n", size);
96
97 }
98 if (flags & SD_NOISE_ERROR) {
99 print(str);
100 print(" Noise error\n");
101 }
102 if (flags & SD_BREAK_DETECTED) {
103 print(str);
104 print(" Break detected\n");
105 }
106#else
107 (void)str;
108 (void)flags;
109 (void)driver;
110#endif
111}
112
113bool is_serial_link_master(void) {
114 return is_master;
115}
116
117// TODO: Optimize the stack size, this is probably way too big
118static THD_WORKING_AREA(serialThreadStack, 1024);
119static THD_FUNCTION(serialThread, arg) {
120 (void)arg;
121 event_listener_t new_data_listener;
122 event_listener_t sd1_listener;
123 event_listener_t sd2_listener;
124 chEvtRegister(&new_data_event, &new_data_listener, 0);
125 eventflags_t events = CHN_INPUT_AVAILABLE
126 | SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR | SD_NOISE_ERROR | SD_BREAK_DETECTED;
127 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD1),
128 &sd1_listener,
129 EVENT_MASK(1),
130 events);
131 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD2),
132 &sd2_listener,
133 EVENT_MASK(2),
134 events);
135 bool need_wait = false;
136 while(true) {
137 eventflags_t flags1 = 0;
138 eventflags_t flags2 = 0;
139 if (need_wait) {
140 eventmask_t mask = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
141 if (mask & EVENT_MASK(1)) {
142 flags1 = chEvtGetAndClearFlags(&sd1_listener);
143 print_error("DOWNLINK", flags1, &SD1);
144 }
145 if (mask & EVENT_MASK(2)) {
146 flags2 = chEvtGetAndClearFlags(&sd2_listener);
147 print_error("UPLINK", flags2, &SD2);
148 }
149 }
150
151 // Always stay as master, even if the USB goes into sleep mode
152 is_master |= usbGetDriverStateI(&USBD1) == USB_ACTIVE;
153 router_set_master(is_master);
154
155 need_wait = true;
156 need_wait &= read_from_serial(&SD2, UP_LINK) == 0;
157 need_wait &= read_from_serial(&SD1, DOWN_LINK) == 0;
158 update_transport();
159 }
160}
161
162void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
163 if (link == DOWN_LINK) {
164 sdWrite(&SD1, data, size);
165 }
166 else {
167 sdWrite(&SD2, data, size);
168 }
169}
170
171static systime_t last_update = 0;
172
173typedef struct {
174 matrix_row_t rows[MATRIX_ROWS];
175} matrix_object_t;
176
177static matrix_object_t last_matrix = {};
178
179SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t);
180MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool);
181
182static remote_object_t* remote_objects[] = {
183 REMOTE_OBJECT(serial_link_connected),
184 REMOTE_OBJECT(keyboard_matrix),
185};
186
187void init_serial_link(void) {
188 serial_link_connected = false;
189 init_serial_link_hal();
190 add_remote_objects(remote_objects, sizeof(remote_objects)/sizeof(remote_object_t*));
191 init_byte_stuffer();
192 sdStart(&SD1, &config);
193 sdStart(&SD2, &config);
194 chEvtObjectInit(&new_data_event);
195 (void)chThdCreateStatic(serialThreadStack, sizeof(serialThreadStack),
196 SERIAL_LINK_THREAD_PRIORITY, serialThread, NULL);
197}
198
199void matrix_set_remote(matrix_row_t* rows, uint8_t index);
200
201void serial_link_update(void) {
202 if (read_serial_link_connected()) {
203 serial_link_connected = true;
204 }
205
206 matrix_object_t matrix;
207 bool changed = false;
208 for(uint8_t i=0;i<MATRIX_ROWS;i++) {
209 matrix.rows[i] = matrix_get_row(i);
210 changed |= matrix.rows[i] != last_matrix.rows[i];
211 }
212
213 systime_t current_time = chVTGetSystemTimeX();
214 systime_t delta = current_time - last_update;
215 if (changed || delta > US2ST(1000)) {
216 last_update = current_time;
217 last_matrix = matrix;
218 matrix_object_t* m = begin_write_keyboard_matrix();
219 for(uint8_t i=0;i<MATRIX_ROWS;i++) {
220 m->rows[i] = matrix.rows[i];
221 }
222 end_write_keyboard_matrix();
223 *begin_write_serial_link_connected() = true;
224 end_write_serial_link_connected();
225 }
226
227 matrix_object_t* m = read_keyboard_matrix(0);
228 if (m) {
229 matrix_set_remote(m->rows, 0);
230 }
231}
232
233void signal_data_written(void) {
234 chEvtBroadcast(&new_data_event);
235}
236
237bool is_serial_link_connected(void) {
238 return serial_link_connected;
239}
240
241host_driver_t* get_serial_link_driver(void) {
242 return &serial_driver;
243}
244
245// NOTE: The driver does nothing, because the master handles everything
246uint8_t keyboard_leds(void) {
247 return 0;
248}
249
250void send_keyboard(report_keyboard_t *report) {
251 (void)report;
252}
253
254void send_mouse(report_mouse_t *report) {
255 (void)report;
256}
257
258void send_system(uint16_t data) {
259 (void)data;
260}
261
262void send_consumer(uint16_t data) {
263 (void)data;
264}
265