aboutsummaryrefslogtreecommitdiff
path: root/keyboards/nullbitsco/nibble/remote_kb.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/nullbitsco/nibble/remote_kb.c')
-rw-r--r--keyboards/nullbitsco/nibble/remote_kb.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/keyboards/nullbitsco/nibble/remote_kb.c b/keyboards/nullbitsco/nibble/remote_kb.c
new file mode 100644
index 000000000..2e36f5f22
--- /dev/null
+++ b/keyboards/nullbitsco/nibble/remote_kb.c
@@ -0,0 +1,177 @@
1/* Copyright 2020 Jay Greco
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17/*
18Remote keyboard is an experimental feature that allows for connecting another
19keyboard, macropad, numpad, or accessory without requiring an additional USB connection.
20The "remote keyboard" forwards its keystrokes using UART serial over TRRS. Dynamic VUSB
21detect allows the keyboard automatically switch to host or remote mode depending on
22which is connected to the USB port.
23
24Possible functionality includes the ability to send data from the host to the remote using
25a reverse link, allowing for LED sync, configuration, and more data sharing between devices.
26This will require a new communication protocol, as the current one is limited.
27*/
28
29#include "remote_kb.h"
30
31uint8_t
32 msg[UART_MSG_LEN],
33 msg_idx = 0;
34
35bool
36 is_host = true;
37
38// Private functions
39
40static bool vbus_detect(void) {
41 #if defined(__AVR_ATmega32U4__)
42 //returns true if VBUS is present, false otherwise.
43 USBCON |= (1 << OTGPADE); //enables VBUS pad
44 _delay_us(10);
45 return (USBSTA & (1<<VBUS)); //checks state of VBUS
46 #else
47 #error vbus_detect is not implemented for this architecure!
48 #endif
49}
50
51static uint8_t chksum8(const unsigned char *buf, size_t len) {
52 unsigned int sum;
53 for (sum = 0 ; len != 0 ; len--)
54 sum += *(buf++);
55 return (uint8_t)sum;
56}
57
58static void send_msg(uint16_t keycode, bool pressed) {
59 msg[IDX_PREAMBLE] = UART_PREAMBLE;
60 msg[IDX_KCLSB] = (keycode & 0xFF);
61 msg[IDX_KCMSB] = (keycode >> 8) & 0xFF;
62 msg[IDX_PRESSED] = pressed;
63 msg[IDX_CHECKSUM] = chksum8(msg, UART_MSG_LEN-1);
64
65 for (int i=0; i<UART_MSG_LEN; i++) {
66 uart_putchar(msg[i]);
67 }
68}
69
70static void print_message_buffer(void) {
71 for (int i=0; i<UART_MSG_LEN; i++) {
72 dprintf("msg[%u]: %u\n", i, msg[i]);
73 }
74}
75
76static void process_uart(void) {
77 uint8_t chksum = chksum8(msg, UART_MSG_LEN-1);
78 if (msg[IDX_PREAMBLE] != UART_PREAMBLE || msg[IDX_CHECKSUM] != chksum) {
79 dprintf("UART checksum mismatch!\n");
80 print_message_buffer();
81 dprintf("calc checksum: %u\n", chksum);
82 } else {
83 uint16_t keycode = (uint16_t)msg[IDX_KCLSB] | ((uint16_t)msg[IDX_KCMSB] << 8);
84 bool pressed = (bool)msg[IDX_PRESSED];
85 if (IS_RM_KC(keycode)) {
86 keyrecord_t record;
87 record.event.pressed = pressed;
88 if (pressed) dprintf("Remote macro: press [%u]\n", keycode);
89 else dprintf("Remote macro: release [%u]\n", keycode);
90 process_record_user(keycode, &record);
91 } else {
92 if (pressed) {
93 dprintf("Remote: press [%u]\n", keycode);
94 register_code(keycode);
95 } else {
96 dprintf("Remote: release [%u]\n", keycode);
97 unregister_code(keycode);
98 }
99 }
100 }
101}
102
103static void get_msg(void) {
104 while (uart_available()) {
105 msg[msg_idx] = uart_getchar();
106 dprintf("idx: %u, recv: %u\n", msg_idx, msg[msg_idx]);
107 if (msg_idx == 0 && (msg[msg_idx] != UART_PREAMBLE)) {
108 dprintf("Byte sync error!\n");
109 msg_idx = 0;
110 } else if (msg_idx == (UART_MSG_LEN-1)) {
111 process_uart();
112 msg_idx = 0;
113 } else {
114 msg_idx++;
115 }
116 }
117}
118
119static void handle_host_incoming(void) {
120 get_msg();
121}
122
123static void handle_host_outgoing(void) {
124 // for future reverse link use
125}
126
127static void handle_remote_incoming(void) {
128 // for future reverse link use
129}
130
131static void handle_remote_outgoing(uint16_t keycode, keyrecord_t *record) {
132 if (IS_HID_KC(keycode) || IS_RM_KC(keycode)) {
133 dprintf("Remote: send [%u]\n", keycode);
134 send_msg(keycode, record->event.pressed);
135 }
136}
137
138// Public functions
139
140void matrix_init_remote_kb(void) {
141 uart_init(SERIAL_UART_BAUD);
142 is_host = vbus_detect();
143}
144
145void process_record_remote_kb(uint16_t keycode, keyrecord_t *record) {
146 #if defined (KEYBOARD_HOST)
147 handle_host_outgoing();
148
149 #elif defined(KEYBOARD_REMOTE)
150 handle_remote_outgoing(keycode, record);
151
152 #else //auto check with VBUS
153 if (is_host) {
154 handle_host_outgoing();
155 }
156 else {
157 handle_remote_outgoing(keycode, record);
158 }
159 #endif
160}
161
162void matrix_scan_remote_kb(void) {
163 #if defined(KEYBOARD_HOST)
164 handle_host_incoming();
165
166 #elif defined (KEYBOARD_REMOTE)
167 handle_remote_incoming();
168
169 #else //auto check with VBUS
170 if (is_host) {
171 handle_host_incoming();
172 }
173 else {
174 handle_remote_incoming();
175 }
176 #endif
177}