2 Copyright 2018 Massdrop Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "samd51j18a.h"
19 #include "tmk_core/common/keyboard.h"
23 #include "host_driver.h"
24 #include "keycode_config.h"
28 //From protocol directory
29 #include "arm_atsam_protocol.h"
31 //From keyboard's directory
32 #include "config_led.h"
34 uint8_t g_usb_state = USB_FSMSTATUS_FSMSTATE_OFF_Val; //Saved USB state from hardware value to detect changes
36 void main_subtasks(void);
37 uint8_t keyboard_leds(void);
38 void send_keyboard(report_keyboard_t *report);
39 void send_mouse(report_mouse_t *report);
40 void send_system(uint16_t data);
41 void send_consumer(uint16_t data);
43 host_driver_t arm_atsam_driver = {
53 uint8_t keyboard_leds(void)
56 if (keymap_config.nkro)
57 return udi_hid_nkro_report_set;
60 return udi_hid_kbd_report_set;
63 void send_keyboard(report_keyboard_t *report)
68 if (!keymap_config.nkro)
71 while (udi_hid_kbd_b_report_trans_ongoing) { main_subtasks(); } //Run other tasks while waiting for USB to be free
73 irqflags = __get_PRIMASK();
77 memcpy(udi_hid_kbd_report, report->raw, UDI_HID_KBD_REPORT_SIZE);
78 udi_hid_kbd_b_report_valid = 1;
79 udi_hid_kbd_send_report();
82 __set_PRIMASK(irqflags);
87 while (udi_hid_nkro_b_report_trans_ongoing) { main_subtasks(); } //Run other tasks while waiting for USB to be free
89 irqflags = __get_PRIMASK();
93 memcpy(udi_hid_nkro_report, report->raw, UDI_HID_NKRO_REPORT_SIZE);
94 udi_hid_nkro_b_report_valid = 1;
95 udi_hid_nkro_send_report();
98 __set_PRIMASK(irqflags);
103 void send_mouse(report_mouse_t *report)
105 #ifdef MOUSEKEY_ENABLE
108 irqflags = __get_PRIMASK();
112 memcpy(udi_hid_mou_report, report, UDI_HID_MOU_REPORT_SIZE);
113 udi_hid_mou_b_report_valid = 1;
114 udi_hid_mou_send_report();
117 __set_PRIMASK(irqflags);
118 #endif //MOUSEKEY_ENABLE
121 void send_system(uint16_t data)
123 #ifdef EXTRAKEY_ENABLE
126 irqflags = __get_PRIMASK();
130 udi_hid_exk_report.desc.report_id = REPORT_ID_SYSTEM;
131 if (data != 0) data = data - SYSTEM_POWER_DOWN + 1;
132 udi_hid_exk_report.desc.report_data = data;
133 udi_hid_exk_b_report_valid = 1;
134 udi_hid_exk_send_report();
137 __set_PRIMASK(irqflags);
138 #endif //EXTRAKEY_ENABLE
141 void send_consumer(uint16_t data)
143 #ifdef EXTRAKEY_ENABLE
146 irqflags = __get_PRIMASK();
150 udi_hid_exk_report.desc.report_id = REPORT_ID_CONSUMER;
151 udi_hid_exk_report.desc.report_data = data;
152 udi_hid_exk_b_report_valid = 1;
153 udi_hid_exk_send_report();
156 __set_PRIMASK(irqflags);
157 #endif //EXTRAKEY_ENABLE
160 void main_subtask_usb_state(void)
162 static uint64_t fsmstate_on_delay = 0; //Delay timer to be sure USB is actually operating before bringing up hardware
163 uint8_t fsmstate_now = USB->DEVICE.FSMSTATUS.reg; //Current state from hardware register
165 if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_SUSPEND_Val) //If USB SUSPENDED
167 fsmstate_on_delay = 0; //Clear ON delay timer
169 if (g_usb_state != USB_FSMSTATUS_FSMSTATE_SUSPEND_Val) //If previously not SUSPENDED
171 suspend_power_down(); //Run suspend routine
172 g_usb_state = fsmstate_now; //Save current USB state
175 else if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_SLEEP_Val) //Else if USB SLEEPING
177 fsmstate_on_delay = 0; //Clear ON delay timer
179 if (g_usb_state != USB_FSMSTATUS_FSMSTATE_SLEEP_Val) //If previously not SLEEPING
181 suspend_power_down(); //Run suspend routine
182 g_usb_state = fsmstate_now; //Save current USB state
185 else if (fsmstate_now == USB_FSMSTATUS_FSMSTATE_ON_Val) //Else if USB ON
187 if (g_usb_state != USB_FSMSTATUS_FSMSTATE_ON_Val) //If previously not ON
189 if (fsmstate_on_delay == 0) //If ON delay timer is cleared
191 fsmstate_on_delay = timer_read64() + 250; //Set ON delay timer
193 else if (timer_read64() > fsmstate_on_delay) //Else if ON delay timer is active and timed out
195 suspend_wakeup_init(); //Run wakeup routine
196 g_usb_state = fsmstate_now; //Save current USB state
200 else //Else if USB is in a state not being tracked
202 fsmstate_on_delay = 0; //Clear ON delay timer
206 void main_subtask_power_check(void)
208 static uint64_t next_5v_checkup = 0;
210 if (timer_read64() > next_5v_checkup)
212 next_5v_checkup = timer_read64() + 5;
214 v_5v = adc_get(ADC_5V);
215 v_5v_avg = 0.9 * v_5v_avg + 0.1 * v_5v;
217 #ifdef RGB_MATRIX_ENABLE
223 void main_subtask_usb_extra_device(void)
225 static uint64_t next_usb_checkup = 0;
227 if (timer_read64() > next_usb_checkup)
229 next_usb_checkup = timer_read64() + 10;
231 USB_HandleExtraDevice();
235 void main_subtasks(void)
237 main_subtask_usb_state();
238 main_subtask_power_check();
239 main_subtask_usb_extra_device();
260 #ifdef RGB_MATRIX_ENABLE
262 #endif // RGB_MATRIX_ENABLE
268 DBGC(DC_MAIN_UDC_START_BEGIN);
270 DBGC(DC_MAIN_UDC_START_COMPLETE);
272 DBGC(DC_MAIN_CDC_INIT_BEGIN);
274 DBGC(DC_MAIN_CDC_INIT_COMPLETE);
276 while (USB2422_Port_Detect_Init() == 0) {}
280 #ifdef RGB_MATRIX_ENABLE
281 while (I2C3733_Init_Control() != 1) {}
282 while (I2C3733_Init_Drivers() != 1) {}
288 for (uint8_t drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++)
289 I2C_LED_Q_ONOFF(drvid); //Queue data
290 #endif // RGB_MATRIX_ENABLE
296 host_set_driver(&arm_atsam_driver);
298 #ifdef CONSOLE_ENABLE
299 uint64_t next_print = 0;
300 #endif //CONSOLE_ENABLE
302 v_5v_avg = adc_get(ADC_5V);
304 debug_code_disable();
308 main_subtasks(); //Note these tasks will also be run while waiting for USB keyboard polling intervals
310 if (g_usb_state == USB_FSMSTATUS_FSMSTATE_SUSPEND_Val || g_usb_state == USB_FSMSTATUS_FSMSTATE_SLEEP_Val)
312 if (suspend_wakeup_condition())
314 udc_remotewakeup(); //Send remote wakeup signal
323 #ifdef CONSOLE_ENABLE
324 if (timer_read64() > next_print)
326 next_print = timer_read64() + 250;
327 //Add any debug information here that you want to see very often
328 //dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n", v_5v, v_5v_avg, v_5v_avg - V5_LOW, v_5v_avg - V5_HIGH, gcr_actual, gcr_desired);
330 #endif //CONSOLE_ENABLE