DeskHop v0.62 (Minor Bugfixes)

- Fixed screen lock regression bug
  - Cleaned up trailing spaces

Due to MacOS having issues:
  - Moved screen lock shortcut to right control + L
  - Moved switch lock shortcut to right control + K
This commit is contained in:
Hrvoje Cavrak 2024-08-03 19:03:38 +02:00
parent 7a0e7f31ff
commit 1fd0049039
24 changed files with 188 additions and 184 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.6) cmake_minimum_required(VERSION 3.6)
set(VERSION_MAJOR 00) set(VERSION_MAJOR 00)
set(VERSION_MINOR 139) set(VERSION_MINOR 147)
set(PICO_SDK_FETCH_FROM_GIT off) set(PICO_SDK_FETCH_FROM_GIT off)
set(PICO_BOARD=pico) set(PICO_BOARD=pico)

View File

@ -93,9 +93,14 @@ Ever tried to move that YT video slider to a specific position but your mouse mo
### Switch Lock ### Switch Lock
If you want to lock yourself to one screen, use ```RIGHT CTRL + L```. If you want to lock yourself to one screen, use ```RIGHT CTRL + K```.
This will make sure you won't accidentally leave your current screen. To turn off, press the same key combo again. This will make sure you won't accidentally leave your current screen. To turn off, press the same key combo again.
### Lock Both Screens
You can lock both computers at once by using ```RIGHT CTRL + L```.
To make use of this feature, first set up the OS for each output in config (since the shortcuts are different).
### Screensaver ### Screensaver
Supposedly built in to prevent computer from entering standby, but truth be told - it is just fun to watch. **Off by default**, will make your mouse pointer bounce around the screen like a Pong ball. When enabled, it activates after a period of inactivity defined in user config header and automatically switches off as soon as you send any output towards that screen. Supposedly built in to prevent computer from entering standby, but truth be told - it is just fun to watch. **Off by default**, will make your mouse pointer bounce around the screen like a Pong ball. When enabled, it activates after a period of inactivity defined in user config header and automatically switches off as soon as you send any output towards that screen.
@ -209,8 +214,8 @@ _Config_
_Usage_ _Usage_
- ```Right CTRL + Right ALT``` - Toggle slower mouse mode - ```Right CTRL + Right ALT``` - Toggle slower mouse mode
- ```Right CTRL + L``` - Lock/Unlock mouse desktop switching - ```Right CTRL + K``` - Lock/Unlock mouse desktop switching
- ```Right ALT + Right Shift + L``` - Lock both outputs at once (set output OS before, see shortcuts below) - ```Right CTRL + L``` - Lock both outputs at once (set output OS before, see shortcuts below)
- ```Caps Lock``` - Switch between outputs - ```Caps Lock``` - Switch between outputs
### Switch cursor height calibration ### Switch cursor height calibration

Binary file not shown.

View File

@ -21,9 +21,9 @@ const config_t default_config = {
.mode = SCREENSAVER_A_MODE, .mode = SCREENSAVER_A_MODE,
.only_if_inactive = SCREENSAVER_A_ONLY_IF_INACTIVE, .only_if_inactive = SCREENSAVER_A_ONLY_IF_INACTIVE,
.idle_time_us = SCREENSAVER_A_IDLE_TIME_SEC * 1000000, .idle_time_us = SCREENSAVER_A_IDLE_TIME_SEC * 1000000,
.max_time_us = SCREENSAVER_A_MAX_TIME_SEC * 1000000, .max_time_us = SCREENSAVER_A_MAX_TIME_SEC * 1000000,
} }
}, },
.output[OUTPUT_B] = .output[OUTPUT_B] =
{ {
.number = OUTPUT_B, .number = OUTPUT_B,
@ -41,7 +41,7 @@ const config_t default_config = {
.mode = SCREENSAVER_B_MODE, .mode = SCREENSAVER_B_MODE,
.only_if_inactive = SCREENSAVER_B_ONLY_IF_INACTIVE, .only_if_inactive = SCREENSAVER_B_ONLY_IF_INACTIVE,
.idle_time_us = SCREENSAVER_B_IDLE_TIME_SEC * 1000000, .idle_time_us = SCREENSAVER_B_IDLE_TIME_SEC * 1000000,
.max_time_us = SCREENSAVER_B_MAX_TIME_SEC * 1000000, .max_time_us = SCREENSAVER_B_MAX_TIME_SEC * 1000000,
} }
}, },
.enforce_ports = ENFORCE_PORTS, .enforce_ports = ENFORCE_PORTS,

View File

@ -79,14 +79,14 @@ void screenlock_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
lock_report.keycode[0] = HID_KEY_L; lock_report.keycode[0] = HID_KEY_L;
break; break;
case MACOS: case MACOS:
lock_report.modifier = KEYBOARD_MODIFIER_LEFTCTRL | KEYBOARD_MODIFIER_LEFTALT; lock_report.modifier = KEYBOARD_MODIFIER_LEFTCTRL | KEYBOARD_MODIFIER_LEFTGUI;
lock_report.keycode[0] = HID_KEY_Q; lock_report.keycode[0] = HID_KEY_Q;
break; break;
default: default:
break; break;
} }
if (global_state.active_output == out) { if (BOARD_ROLE == out) {
queue_kbd_report(&lock_report, state); queue_kbd_report(&lock_report, state);
release_all_keys(state); release_all_keys(state);
} else { } else {
@ -111,14 +111,14 @@ void mouse_zoom_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
/* Put the device into a special configuration mode */ /* Put the device into a special configuration mode */
void config_enable_hotkey_handler(device_t *state, hid_keyboard_report_t *report) { void config_enable_hotkey_handler(device_t *state, hid_keyboard_report_t *report) {
/* If config mode is already active, skip this and reboot to return to normal mode */ /* If config mode is already active, skip this and reboot to return to normal mode */
if (!state->config_mode_active) { if (!state->config_mode_active) {
watchdog_hw->scratch[5] = MAGIC_WORD_1; watchdog_hw->scratch[5] = MAGIC_WORD_1;
watchdog_hw->scratch[6] = MAGIC_WORD_2; watchdog_hw->scratch[6] = MAGIC_WORD_2;
} }
release_all_keys(state); release_all_keys(state);
state->reboot_requested = true; state->reboot_requested = true;
}; };
@ -226,9 +226,9 @@ void handle_api_msgs(uart_packet_t *packet, device_t *state) {
/* If we don't have a valid map entry, return immediately */ /* If we don't have a valid map entry, return immediately */
if (map == NULL) if (map == NULL)
return; return;
/* Create a pointer to the offset into the structure we need to access */ /* Create a pointer to the offset into the structure we need to access */
uint8_t *ptr = (((uint8_t *)&global_state) + map->offset); uint8_t *ptr = (((uint8_t *)&global_state) + map->offset);
if (packet->type == SET_VAL_MSG) { if (packet->type == SET_VAL_MSG) {
@ -237,7 +237,7 @@ void handle_api_msgs(uart_packet_t *packet, device_t *state) {
return; return;
memcpy(ptr, &packet->data[1], map->len); memcpy(ptr, &packet->data[1], map->len);
} }
else if (packet->type == GET_VAL_MSG) { else if (packet->type == GET_VAL_MSG) {
uart_packet_t response = {.type=GET_VAL_MSG, .data={0}}; uart_packet_t response = {.type=GET_VAL_MSG, .data={0}};
memcpy(response.data, ptr, map->len); memcpy(response.data, ptr, map->len);
@ -252,14 +252,14 @@ void handle_api_msgs(uart_packet_t *packet, device_t *state) {
/* Process request packet and create a response */ /* Process request packet and create a response */
void handle_request_byte_msg(uart_packet_t *packet, device_t *state) { void handle_request_byte_msg(uart_packet_t *packet, device_t *state) {
uint32_t address = packet->data32[0]; uint32_t address = packet->data32[0];
if (address > STAGING_IMAGE_SIZE) if (address > STAGING_IMAGE_SIZE)
return; return;
/* Add requested data to bytes 4-7 in the packet and return it with a different type */ /* Add requested data to bytes 4-7 in the packet and return it with a different type */
uint32_t data = *(uint32_t *)&ADDR_FW_RUNNING[address]; uint32_t data = *(uint32_t *)&ADDR_FW_RUNNING[address];
packet->data32[1] = data; packet->data32[1] = data;
queue_packet(packet->data, RESPONSE_BYTE_MSG, PACKET_DATA_LENGTH); queue_packet(packet->data, RESPONSE_BYTE_MSG, PACKET_DATA_LENGTH);
} }
@ -279,27 +279,27 @@ void handle_response_byte_msg(uart_packet_t *packet, device_t *state) {
if((address & 0xfff) == 0x000) if((address & 0xfff) == 0x000)
toggle_led(); toggle_led();
} }
/* Update checksum as we receive each byte */ /* Update checksum as we receive each byte */
if (address < STAGING_IMAGE_SIZE - FLASH_SECTOR_SIZE) if (address < STAGING_IMAGE_SIZE - FLASH_SECTOR_SIZE)
for (int i=0; i<4; i++) for (int i=0; i<4; i++)
state->fw.checksum = crc32_iter(state->fw.checksum, packet->data[4 + i]); state->fw.checksum = crc32_iter(state->fw.checksum, packet->data[4 + i]);
memcpy(state->page_buffer + offset, &packet->data32[1], sizeof(uint32_t)); memcpy(state->page_buffer + offset, &packet->data32[1], sizeof(uint32_t));
/* Neeeeeeext byte, please! */ /* Neeeeeeext byte, please! */
state->fw.address += sizeof(uint32_t); state->fw.address += sizeof(uint32_t);
state->fw.byte_done = true; state->fw.byte_done = true;
} }
/* Process a request to read a firmware package from flash */ /* Process a request to read a firmware package from flash */
void handle_heartbeat_msg(uart_packet_t *packet, device_t *state) { void handle_heartbeat_msg(uart_packet_t *packet, device_t *state) {
uint16_t other_running_version = packet->data16[0]; uint16_t other_running_version = packet->data16[0];
if (state->fw.upgrade_in_progress) if (state->fw.upgrade_in_progress)
return; return;
/* If the other board isn't running a newer version, we are done */ /* If the other board isn't running a newer version, we are done */
if (other_running_version <= state->_running_fw.version) if (other_running_version <= state->_running_fw.version)
return; return;
@ -309,7 +309,7 @@ void handle_heartbeat_msg(uart_packet_t *packet, device_t *state) {
.byte_done = true, .byte_done = true,
.address = 0, .address = 0,
.checksum = 0xffffffff, .checksum = 0xffffffff,
}; };
} }

View File

@ -46,7 +46,7 @@ void update_usage(parser_state_t *parser, int i) {
*(parser->p_usage + i) = *(parser->p_usage + i - 1); *(parser->p_usage + i) = *(parser->p_usage + i - 1);
} }
void store_element(parser_state_t *parser, report_val_t *val, int i, uint32_t data, uint16_t size, hid_interface_t *iface) { void store_element(parser_state_t *parser, report_val_t *val, int i, uint32_t data, uint16_t size, hid_interface_t *iface) {
*val = (report_val_t){ *val = (report_val_t){
.offset = parser->offset_in_bits, .offset = parser->offset_in_bits,
.offset_idx = parser->offset_in_bits >> 3, .offset_idx = parser->offset_in_bits >> 3,
@ -68,9 +68,9 @@ void store_element(parser_state_t *parser, report_val_t *val, int i, uint32_t da
} }
void handle_global_item(parser_state_t *parser, item_t *item) { void handle_global_item(parser_state_t *parser, item_t *item) {
if (item->hdr.tag == RI_GLOBAL_REPORT_ID) if (item->hdr.tag == RI_GLOBAL_REPORT_ID)
parser->report_id = item->val; parser->report_id = item->val;
parser->globals[item->hdr.tag] = *item; parser->globals[item->hdr.tag] = *item;
} }
@ -80,7 +80,7 @@ void handle_local_item(parser_state_t *parser, item_t *item) {
parser->locals[item->hdr.tag] = *item; parser->locals[item->hdr.tag] = *item;
if (item->hdr.tag == RI_LOCAL_USAGE) { if (item->hdr.tag == RI_LOCAL_USAGE) {
if(IS_BLOCK_END) if(IS_BLOCK_END)
parser->global_usage = item->val; parser->global_usage = item->val;
else if (parser->usage_count < HID_MAX_USAGES - 1) else if (parser->usage_count < HID_MAX_USAGES - 1)
@ -94,20 +94,20 @@ void handle_main_input(parser_state_t *parser, item_t *item, hid_interface_t *if
report_val_t val = {0}; report_val_t val = {0};
/* Swap count and size for 1-bit variables, it makes sense to process e.g. NKRO with /* Swap count and size for 1-bit variables, it makes sense to process e.g. NKRO with
size = 1 and count = 240 in one go instead of doing 240 iterations size = 1 and count = 240 in one go instead of doing 240 iterations
Don't do this if there are usages in the queue, though. Don't do this if there are usages in the queue, though.
*/ */
if (size == 1 && parser->usage_count <= 1) { if (size == 1 && parser->usage_count <= 1) {
size = count; size = count;
count = 1; count = 1;
} }
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
update_usage(parser, i); update_usage(parser, i);
store_element(parser, &val, i, item->val, size, iface); store_element(parser, &val, i, item->val, size, iface);
/* Use the parsed data to populate internal device structures */ /* Use the parsed data to populate internal device structures */
extract_data(iface, &val); extract_data(iface, &val);
/* Iterate <count> times and increase offset by <size> amount, moving by <count> x <size> bits */ /* Iterate <count> times and increase offset by <size> amount, moving by <count> x <size> bits */
parser->offset_in_bits += size; parser->offset_in_bits += size;
@ -152,7 +152,7 @@ void handle_main_item(parser_state_t *parser, item_t *item, hid_interface_t *ifa
parser_state_t parser_state = {0}; // Avoid placing it on the stack, it's large parser_state_t parser_state = {0}; // Avoid placing it on the stack, it's large
void parse_report_descriptor(hid_interface_t *iface, void parse_report_descriptor(hid_interface_t *iface,
uint8_t const *report, uint8_t const *report,
int desc_len int desc_len
) { ) {
item_t item = {0}; item_t item = {0};
@ -181,5 +181,5 @@ void parse_report_descriptor(hid_interface_t *iface,
/* Move to the next position and decrement size by header length + data length */ /* Move to the next position and decrement size by header length + data length */
report += SIZE_LOOKUP[item.hdr.size]; report += SIZE_LOOKUP[item.hdr.size];
desc_len -= (SIZE_LOOKUP[item.hdr.size] + 1); desc_len -= (SIZE_LOOKUP[item.hdr.size] + 1);
} }
} }

View File

@ -55,17 +55,17 @@ int32_t get_report_value(uint8_t *report, report_val_t *val) {
} }
/* After processing the descriptor, assign the values so we can later use them to interpret reports */ /* After processing the descriptor, assign the values so we can later use them to interpret reports */
void handle_consumer_control_values(report_val_t *src, report_val_t *dst, hid_interface_t *iface) { void handle_consumer_control_values(report_val_t *src, report_val_t *dst, hid_interface_t *iface) {
if (src->offset > MAX_CC_BUTTONS) { if (src->offset > MAX_CC_BUTTONS) {
return; return;
} }
if (src->data_type == VARIABLE) { if (src->data_type == VARIABLE) {
iface->keyboard.cc_array[src->offset] = src->usage; iface->keyboard.cc_array[src->offset] = src->usage;
iface->consumer.is_variable = true; iface->consumer.is_variable = true;
} }
iface->consumer.is_array |= (src->data_type == ARRAY); iface->consumer.is_array |= (src->data_type == ARRAY);
} }
/* After processing the descriptor, assign the values so we can later use them to interpret reports */ /* After processing the descriptor, assign the values so we can later use them to interpret reports */
@ -73,13 +73,13 @@ void handle_system_control_values(report_val_t *src, report_val_t *dst, hid_inte
if (src->offset > MAX_SYS_BUTTONS) { if (src->offset > MAX_SYS_BUTTONS) {
return; return;
} }
if (src->data_type == VARIABLE) { if (src->data_type == VARIABLE) {
iface->keyboard.sys_array[src->offset] = src->usage; iface->keyboard.sys_array[src->offset] = src->usage;
iface->system.is_variable = true; iface->system.is_variable = true;
} }
iface->system.is_array |= (src->data_type == ARRAY); iface->system.is_array |= (src->data_type == ARRAY);
} }
/* After processing the descriptor, assign the values so we can later use them to interpret reports */ /* After processing the descriptor, assign the values so we can later use them to interpret reports */
@ -143,54 +143,54 @@ void extract_data(hid_interface_t *iface, report_val_t *val) {
.id = &iface->mouse.report_id}, .id = &iface->mouse.report_id},
{.usage_page = HID_USAGE_PAGE_DESKTOP, {.usage_page = HID_USAGE_PAGE_DESKTOP,
.global_usage = HID_USAGE_DESKTOP_MOUSE, .global_usage = HID_USAGE_DESKTOP_MOUSE,
.usage = HID_USAGE_DESKTOP_X, .usage = HID_USAGE_DESKTOP_X,
.handler = _store, .handler = _store,
.receiver = process_mouse_report, .receiver = process_mouse_report,
.dst = &iface->mouse.move_x, .dst = &iface->mouse.move_x,
.id = &iface->mouse.report_id}, .id = &iface->mouse.report_id},
{.usage_page = HID_USAGE_PAGE_DESKTOP, {.usage_page = HID_USAGE_PAGE_DESKTOP,
.global_usage = HID_USAGE_DESKTOP_MOUSE, .global_usage = HID_USAGE_DESKTOP_MOUSE,
.usage = HID_USAGE_DESKTOP_Y, .usage = HID_USAGE_DESKTOP_Y,
.handler = _store, .handler = _store,
.receiver = process_mouse_report, .receiver = process_mouse_report,
.dst = &iface->mouse.move_y, .dst = &iface->mouse.move_y,
.id = &iface->mouse.report_id}, .id = &iface->mouse.report_id},
{.usage_page = HID_USAGE_PAGE_DESKTOP, {.usage_page = HID_USAGE_PAGE_DESKTOP,
.global_usage = HID_USAGE_DESKTOP_MOUSE, .global_usage = HID_USAGE_DESKTOP_MOUSE,
.usage = HID_USAGE_DESKTOP_WHEEL, .usage = HID_USAGE_DESKTOP_WHEEL,
.handler = _store, .handler = _store,
.receiver = process_mouse_report, .receiver = process_mouse_report,
.dst = &iface->mouse.wheel, .dst = &iface->mouse.wheel,
.id = &iface->mouse.report_id}, .id = &iface->mouse.report_id},
{.usage_page = HID_USAGE_PAGE_KEYBOARD, {.usage_page = HID_USAGE_PAGE_KEYBOARD,
.global_usage = HID_USAGE_DESKTOP_KEYBOARD, .global_usage = HID_USAGE_DESKTOP_KEYBOARD,
.handler = handle_keyboard_descriptor_values, .handler = handle_keyboard_descriptor_values,
.receiver = process_keyboard_report, .receiver = process_keyboard_report,
.id = &iface->keyboard.report_id}, .id = &iface->keyboard.report_id},
{.usage_page = HID_USAGE_PAGE_CONSUMER, {.usage_page = HID_USAGE_PAGE_CONSUMER,
.global_usage = HID_USAGE_CONSUMER_CONTROL, .global_usage = HID_USAGE_CONSUMER_CONTROL,
.handler = handle_consumer_control_values, .handler = handle_consumer_control_values,
.receiver = process_consumer_report, .receiver = process_consumer_report,
.dst = &iface->consumer.val, .dst = &iface->consumer.val,
.id = &iface->consumer.report_id}, .id = &iface->consumer.report_id},
{.usage_page = HID_USAGE_PAGE_DESKTOP, {.usage_page = HID_USAGE_PAGE_DESKTOP,
.global_usage = HID_USAGE_DESKTOP_SYSTEM_CONTROL, .global_usage = HID_USAGE_DESKTOP_SYSTEM_CONTROL,
.handler = _store, .handler = _store,
.receiver = process_system_report, .receiver = process_system_report,
.dst = &iface->system.val, .dst = &iface->system.val,
.id = &iface->system.report_id}, .id = &iface->system.report_id},
}; };
/* We extracted all we could find in the descriptor to report_values, now go through them and /* We extracted all we could find in the descriptor to report_values, now go through them and
match them up with the values in the table above, then store those values for later reference */ match them up with the values in the table above, then store those values for later reference */
for (const usage_map_t *hay = map; hay != &map[ARRAY_SIZE(map)]; hay++) { for (const usage_map_t *hay = map; hay != &map[ARRAY_SIZE(map)]; hay++) {
/* ---> If any condition is not defined, we consider it as matched <--- */ /* ---> If any condition is not defined, we consider it as matched <--- */
bool global_usages_match = (val->global_usage == hay->global_usage) || (hay->global_usage == 0); bool global_usages_match = (val->global_usage == hay->global_usage) || (hay->global_usage == 0);
bool usages_match = (val->usage == hay->usage) || (hay->usage == 0); bool usages_match = (val->usage == hay->usage) || (hay->usage == 0);
@ -236,7 +236,7 @@ int32_t _extract_kbd_other(uint8_t *raw_report, int len, hid_interface_t *iface,
uint8_t *src = raw_report; uint8_t *src = raw_report;
keyboard_t *kb = &iface->keyboard; keyboard_t *kb = &iface->keyboard;
if (iface->uses_report_id) if (iface->uses_report_id)
src++; src++;
report->modifier = src[kb->modifier.offset_idx]; report->modifier = src[kb->modifier.offset_idx];
@ -286,7 +286,7 @@ int32_t extract_kbd_data(
/* NKRO is a special case */ /* NKRO is a special case */
if (report_id > 0 if (report_id > 0
&& report_id == iface->keyboard.nkro.report_id && report_id == iface->keyboard.nkro.report_id
&& iface->keyboard.is_nkro) && iface->keyboard.is_nkro)
return _extract_kbd_nkro(raw_report, len, iface, report); return _extract_kbd_nkro(raw_report, len, iface, report);

View File

@ -31,7 +31,7 @@ typedef struct {
int usage_page; int usage_page;
int usage; int usage;
uint8_t *id; uint8_t *id;
report_val_t *dst; report_val_t *dst;
value_handler_f handler; value_handler_f handler;
process_report_f receiver; process_report_f receiver;
} usage_map_t; } usage_map_t;

View File

@ -255,7 +255,7 @@ typedef struct {
uint8_t enforce_ports; uint8_t enforce_ports;
uint16_t jump_treshold; uint16_t jump_treshold;
output_t output[NUM_SCREENS]; output_t output[NUM_SCREENS];
uint32_t _reserved; uint32_t _reserved;
// Keep checksum at the end of the struct // Keep checksum at the end of the struct
@ -402,7 +402,7 @@ typedef struct {
bool onboard_led_state; // True when LED is ON bool onboard_led_state; // True when LED is ON
bool relative_mouse; // True when relative mouse mode is used bool relative_mouse; // True when relative mouse mode is used
bool config_mode_active; // True when config mode is active bool config_mode_active; // True when config mode is active
/* Onboard LED blinky (provide feedback when e.g. mouse connected) */ /* Onboard LED blinky (provide feedback when e.g. mouse connected) */
int32_t blinks_left; // How many blink transitions are left int32_t blinks_left; // How many blink transitions are left
int32_t last_led_change; // Timestamp of the last time led state transitioned int32_t last_led_change; // Timestamp of the last time led state transitioned
@ -411,7 +411,7 @@ typedef struct {
typedef struct { typedef struct {
void (*exec)(device_t *state); void (*exec)(device_t *state);
uint64_t frequency; uint64_t frequency;
uint64_t next_run; uint64_t next_run;
bool *enabled; bool *enabled;
} task_t; } task_t;

View File

@ -17,7 +17,7 @@ typedef enum {
typedef struct { typedef struct {
uint32_t idx; uint32_t idx;
bool readonly; bool readonly;
type_e type; type_e type;
uint32_t len; uint32_t len;
size_t offset; size_t offset;
} field_map_t; } field_map_t;

View File

@ -1,4 +1,4 @@
/* /*
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2019 Ha Thach (tinyusb.org) * Copyright (c) 2019 Ha Thach (tinyusb.org)

View File

@ -29,7 +29,7 @@
* a key that is unlikely to ever appear on a keyboard that you will use. * a key that is unlikely to ever appear on a keyboard that you will use.
* HID_KEY_F24 is probably a good choice as keyboards with 24 function keys * HID_KEY_F24 is probably a good choice as keyboards with 24 function keys
* are rare. * are rare.
* *
* */ * */
#define HOTKEY_TOGGLE HID_KEY_F24 #define HOTKEY_TOGGLE HID_KEY_F24
@ -50,7 +50,7 @@
* This is now configurable per-screen. * This is now configurable per-screen.
* *
* ENABLE_ACCELERATION: [0-1], disables or enables mouse acceleration. * ENABLE_ACCELERATION: [0-1], disables or enables mouse acceleration.
* *
* */ * */
/* Output A values */ /* Output A values */
@ -180,10 +180,10 @@
* ================================================== * ==================================================
* *
* If enabled, fixes some device incompatibilities by * If enabled, fixes some device incompatibilities by
* enforcing the boot protocol (which is simpler to parse * enforcing the boot protocol (which is simpler to parse
* and with less variation) * and with less variation)
* *
* ENFORCE_KEYBOARD_BOOT_PROTOCOL: [0, 1] - 1 means keyboard will forcefully use * ENFORCE_KEYBOARD_BOOT_PROTOCOL: [0, 1] - 1 means keyboard will forcefully use
* the boot protocol * the boot protocol
* - 0 means no such thing is enforced * - 0 means no such thing is enforced
* *

View File

@ -39,13 +39,13 @@ hotkey_combo_t hotkeys[] = {
/* Switch lock */ /* Switch lock */
{.modifier = KEYBOARD_MODIFIER_RIGHTCTRL, {.modifier = KEYBOARD_MODIFIER_RIGHTCTRL,
.keys = {HID_KEY_L}, .keys = {HID_KEY_K},
.key_count = 1, .key_count = 1,
.acknowledge = true, .acknowledge = true,
.action_handler = &switchlock_hotkey_handler}, .action_handler = &switchlock_hotkey_handler},
/* Screen lock */ /* Screen lock */
{.modifier = KEYBOARD_MODIFIER_RIGHTALT | KEYBOARD_MODIFIER_RIGHTSHIFT, {.modifier = KEYBOARD_MODIFIER_RIGHTCTRL,
.keys = {HID_KEY_L}, .keys = {HID_KEY_L},
.key_count = 1, .key_count = 1,
.acknowledge = true, .acknowledge = true,
@ -162,7 +162,7 @@ void process_kbd_queue_task(device_t *state) {
void queue_kbd_report(hid_keyboard_report_t *report, device_t *state) { void queue_kbd_report(hid_keyboard_report_t *report, device_t *state) {
/* It wouldn't be fun to queue up a bunch of messages and then dump them all on host */ /* It wouldn't be fun to queue up a bunch of messages and then dump them all on host */
if (!state->tud_connected) if (!state->tud_connected)
return; return;
queue_try_add(&state->kbd_queue, report); queue_try_add(&state->kbd_queue, report);
} }
@ -252,7 +252,7 @@ void process_consumer_report(uint8_t *raw_report, int length, uint8_t itf, hid_i
int byte_idx = i >> 3; int byte_idx = i >> 3;
if ((raw_report[byte_idx + 1] >> bit_idx) & 1) { if ((raw_report[byte_idx + 1] >> bit_idx) & 1) {
report_ptr[0] = iface->keyboard.cc_array[i]; report_ptr[0] = iface->keyboard.cc_array[i];
} }
} }
} }
@ -267,6 +267,6 @@ void process_consumer_report(uint8_t *raw_report, int length, uint8_t itf, hid_i
void process_system_report(uint8_t *raw_report, int length, uint8_t itf, hid_interface_t *iface) { void process_system_report(uint8_t *raw_report, int length, uint8_t itf, hid_interface_t *iface) {
uint16_t new_report = raw_report[1]; uint16_t new_report = raw_report[1];
uint8_t *report_ptr = (uint8_t *)&new_report; uint8_t *report_ptr = (uint8_t *)&new_report;
send_system_control(report_ptr, &global_state); send_system_control(report_ptr, &global_state);
} }

View File

@ -63,7 +63,7 @@ void blink_led(device_t *state) {
void led_blinking_task(device_t *state) { void led_blinking_task(device_t *state) {
const int blink_interval_us = 80000; /* 80 ms off, 80 ms on */ const int blink_interval_us = 80000; /* 80 ms off, 80 ms on */
static uint8_t leds; static uint8_t leds;
/* If there is no more blinking to be done, exit immediately */ /* If there is no more blinking to be done, exit immediately */
if (state->blinks_left == 0) if (state->blinks_left == 0)
return; return;

View File

@ -52,7 +52,7 @@ int main(void) {
while (true) { while (true) {
for (int i = 0; i < NUM_TASKS; i++) for (int i = 0; i < NUM_TASKS; i++)
task_scheduler(device, &tasks_core0[i]); task_scheduler(device, &tasks_core0[i]);
} }
} }
void core1_main() { void core1_main() {
@ -64,14 +64,14 @@ void core1_main() {
[4] = {.exec = &firmware_upgrade_task, .frequency = _HZ(4000)}, // | Send firmware to the other board if needed [4] = {.exec = &firmware_upgrade_task, .frequency = _HZ(4000)}, // | Send firmware to the other board if needed
[5] = {.exec = &heartbeat_output_task, .frequency = _HZ(1)}, // | Output periodic heartbeats [5] = {.exec = &heartbeat_output_task, .frequency = _HZ(1)}, // | Output periodic heartbeats
}; // `----- then go back and repeat forever }; // `----- then go back and repeat forever
const int NUM_TASKS = ARRAY_SIZE(tasks_core1); const int NUM_TASKS = ARRAY_SIZE(tasks_core1);
while (true) { while (true) {
// Update the timestamp, so core0 can figure out if we're dead // Update the timestamp, so core0 can figure out if we're dead
device->core1_last_loop_pass = time_us_64(); device->core1_last_loop_pass = time_us_64();
for (int i = 0; i < NUM_TASKS; i++) for (int i = 0; i < NUM_TASKS; i++)
task_scheduler(device, &tasks_core1[i]); task_scheduler(device, &tasks_core1[i]);
} }
} }
/* ======= End of Main Program Loops ======= */ /* ======= End of Main Program Loops ======= */

View File

@ -87,7 +87,7 @@ void output_mouse_report(mouse_report_t *report, device_t *state) {
state->last_activity[BOARD_ROLE] = time_us_64(); state->last_activity[BOARD_ROLE] = time_us_64();
} else { } else {
queue_packet((uint8_t *)report, MOUSE_REPORT_MSG, MOUSE_REPORT_LENGTH); queue_packet((uint8_t *)report, MOUSE_REPORT_MSG, MOUSE_REPORT_LENGTH);
} }
} }
/* Calculate and return Y coordinate when moving from screen out_from to screen out_to */ /* Calculate and return Y coordinate when moving from screen out_from to screen out_to */
@ -124,12 +124,12 @@ int16_t scale_y_coordinate(int screen_from, int screen_to, device_t *state) {
void switch_screen( void switch_screen(
device_t *state, output_t *output, int new_x, int output_from, int output_to, int direction) { device_t *state, output_t *output, int new_x, int output_from, int output_to, int direction) {
uint8_t *mouse_park_pos = &state->config.output[state->active_output].mouse_park_pos; uint8_t *mouse_park_pos = &state->config.output[state->active_output].mouse_park_pos;
int16_t mouse_y = (*mouse_park_pos == 0) ? MIN_SCREEN_COORD : /* Top */ int16_t mouse_y = (*mouse_park_pos == 0) ? MIN_SCREEN_COORD : /* Top */
(*mouse_park_pos == 1) ? MAX_SCREEN_COORD : /* Bottom */ (*mouse_park_pos == 1) ? MAX_SCREEN_COORD : /* Bottom */
state->pointer_y; /* Previous */ state->pointer_y; /* Previous */
mouse_report_t hidden_pointer = {.y = mouse_y, .x = MAX_SCREEN_COORD}; mouse_report_t hidden_pointer = {.y = mouse_y, .x = MAX_SCREEN_COORD};
output_mouse_report(&hidden_pointer, state); output_mouse_report(&hidden_pointer, state);
switch_output(state, output_to); switch_output(state, output_to);
@ -138,7 +138,7 @@ void switch_screen(
} }
void switch_desktop(device_t *state, output_t *output, int new_index, int direction) { void switch_desktop(device_t *state, output_t *output, int new_index, int direction) {
/* Fix for MACOS: Send relative mouse movement here, one or two pixels in the /* Fix for MACOS: Send relative mouse movement here, one or two pixels in the
direction of movement, BEFORE absolute report sets X to 0 */ direction of movement, BEFORE absolute report sets X to 0 */
mouse_report_t move_relative_one mouse_report_t move_relative_one
= {.x = (direction == LEFT) ? SCREEN_MIDPOINT - 2 : SCREEN_MIDPOINT + 2, .mode = RELATIVE}; = {.x = (direction == LEFT) ? SCREEN_MIDPOINT - 2 : SCREEN_MIDPOINT + 2, .mode = RELATIVE};
@ -207,7 +207,7 @@ void check_screen_switch(const mouse_values_t *values, device_t *state) {
switch_desktop(state, output, output->screen_index + 1, direction); switch_desktop(state, output, output->screen_index + 1, direction);
} }
void extract_report_values(uint8_t *raw_report, device_t *state, mouse_values_t *values, hid_interface_t *iface) { void extract_report_values(uint8_t *raw_report, device_t *state, mouse_values_t *values, hid_interface_t *iface) {
/* Interpret values depending on the current protocol used. */ /* Interpret values depending on the current protocol used. */
if (iface->protocol == HID_PROTOCOL_BOOT) { if (iface->protocol == HID_PROTOCOL_BOOT) {
hid_mouse_report_t *mouse_report = (hid_mouse_report_t *)raw_report; hid_mouse_report_t *mouse_report = (hid_mouse_report_t *)raw_report;
@ -267,7 +267,7 @@ void process_mouse_report(uint8_t *raw_report, int len, uint8_t itf, hid_interfa
output_mouse_report(&report, state); output_mouse_report(&report, state);
/* We use the mouse to switch outputs, the logic is in check_screen_switch() */ /* We use the mouse to switch outputs, the logic is in check_screen_switch() */
check_screen_switch(&values, state); check_screen_switch(&values, state);
} }
/* ==================================================== * /* ==================================================== *

View File

@ -1,6 +1,6 @@
#include "main.h" #include "main.h"
const field_map_t api_field_map[] = { const field_map_t api_field_map[] = {
/* Index, Rdonly, Type, Len, Offset in struct */ /* Index, Rdonly, Type, Len, Offset in struct */
{ 0, true, UINT8, 1, offsetof(device_t, active_output) }, { 0, true, UINT8, 1, offsetof(device_t, active_output) },
{ 1, true, INT16, 2, offsetof(device_t, pointer_x) }, { 1, true, INT16, 2, offsetof(device_t, pointer_x) },
@ -22,7 +22,7 @@ const field_map_t api_field_map[] = {
/* Until we increase the payload size from 8 bytes, clamp to avoid exceeding the field size */ /* Until we increase the payload size from 8 bytes, clamp to avoid exceeding the field size */
{ 21, false, UINT64, 7, offsetof(device_t, config.output[0].screensaver.idle_time_us) }, { 21, false, UINT64, 7, offsetof(device_t, config.output[0].screensaver.idle_time_us) },
{ 22, false, UINT64, 7, offsetof(device_t, config.output[0].screensaver.max_time_us) }, { 22, false, UINT64, 7, offsetof(device_t, config.output[0].screensaver.max_time_us) },
/* Output B */ /* Output B */
{ 40, false, UINT32, 4, offsetof(device_t, config.output[1].number) }, { 40, false, UINT32, 4, offsetof(device_t, config.output[1].number) },
@ -58,7 +58,7 @@ const field_map_t api_field_map[] = {
{ 82, true, UINT8, 1, offsetof(device_t, relative_mouse) }, { 82, true, UINT8, 1, offsetof(device_t, relative_mouse) },
}; };
const field_map_t* get_field_map_entry(uint32_t index) { const field_map_t* get_field_map_entry(uint32_t index) {
for (unsigned int i = 0; i < ARRAY_SIZE(api_field_map); i++) { for (unsigned int i = 0; i < ARRAY_SIZE(api_field_map); i++) {
if (api_field_map[i].idx == index) { if (api_field_map[i].idx == index) {
return &api_field_map[i]; return &api_field_map[i];

View File

@ -50,12 +50,12 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff
return -1; return -1;
/* We lie about the image size - actually it's 64 kB, not 512 kB, so if we're out of bounds, return zeros */ /* We lie about the image size - actually it's 64 kB, not 512 kB, so if we're out of bounds, return zeros */
else if (lba >= ACTUAL_NUMBER_OF_BLOCKS) else if (lba >= ACTUAL_NUMBER_OF_BLOCKS)
memset(buffer, 0x00, bufsize); memset(buffer, 0x00, bufsize);
else else
memcpy(buffer, addr, bufsize); memcpy(buffer, addr, bufsize);
return (int32_t)bufsize; return (int32_t)bufsize;
} }
@ -67,31 +67,31 @@ bool tud_msc_is_writable_cb(uint8_t lun) {
/* Simple firmware write routine, we get 512-byte uf2 blocks with 256 byte payload */ /* Simple firmware write routine, we get 512-byte uf2 blocks with 256 byte payload */
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) { int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
uf2_t *uf2 = (uf2_t *)&buffer[0]; uf2_t *uf2 = (uf2_t *)&buffer[0];
bool is_final_block = uf2->blockNo == (STAGING_IMAGE_SIZE / FLASH_PAGE_SIZE) - 1; bool is_final_block = uf2->blockNo == (STAGING_IMAGE_SIZE / FLASH_PAGE_SIZE) - 1;
uint32_t flash_addr = (uint32_t)ADDR_FW_RUNNING + uf2->blockNo * FLASH_PAGE_SIZE - XIP_BASE; uint32_t flash_addr = (uint32_t)ADDR_FW_RUNNING + uf2->blockNo * FLASH_PAGE_SIZE - XIP_BASE;
if (lba >= NUMBER_OF_BLOCKS) if (lba >= NUMBER_OF_BLOCKS)
return -1; return -1;
/* If we're not detecting UF2 magic constants, we have nothing to do... */ /* If we're not detecting UF2 magic constants, we have nothing to do... */
if (uf2->magicStart0 != UF2_MAGIC_START0 || uf2->magicStart1 != UF2_MAGIC_START1 || uf2->magicEnd != UF2_MAGIC_END) if (uf2->magicStart0 != UF2_MAGIC_START0 || uf2->magicStart1 != UF2_MAGIC_START1 || uf2->magicEnd != UF2_MAGIC_END)
return (int32_t)bufsize; return (int32_t)bufsize;
if (uf2->blockNo == 0) { if (uf2->blockNo == 0) {
global_state.fw.checksum = 0xffffffff; global_state.fw.checksum = 0xffffffff;
/* Make sure nobody else touches the flash during this operation, otherwise we get empty pages */ /* Make sure nobody else touches the flash during this operation, otherwise we get empty pages */
global_state.fw.upgrade_in_progress = true; global_state.fw.upgrade_in_progress = true;
} }
/* Update checksum continuously as blocks are being received */ /* Update checksum continuously as blocks are being received */
const uint32_t last_block_with_checksum = (STAGING_IMAGE_SIZE - FLASH_SECTOR_SIZE) / FLASH_PAGE_SIZE; const uint32_t last_block_with_checksum = (STAGING_IMAGE_SIZE - FLASH_SECTOR_SIZE) / FLASH_PAGE_SIZE;
for (int i=0; i<FLASH_PAGE_SIZE && uf2->blockNo < last_block_with_checksum; i++) for (int i=0; i<FLASH_PAGE_SIZE && uf2->blockNo < last_block_with_checksum; i++)
global_state.fw.checksum = crc32_iter(global_state.fw.checksum, buffer[32 + i]); global_state.fw.checksum = crc32_iter(global_state.fw.checksum, buffer[32 + i]);
write_flash_page(flash_addr, &buffer[32]); write_flash_page(flash_addr, &buffer[32]);
if (is_final_block) { if (is_final_block) {
global_state.fw.checksum = ~global_state.fw.checksum; global_state.fw.checksum = ~global_state.fw.checksum;
/* If checksums don't match, overwrite first sector and rely on ROM bootloader for recovery */ /* If checksums don't match, overwrite first sector and rely on ROM bootloader for recovery */
@ -102,18 +102,17 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *
else { else {
global_state.reboot_requested = true; global_state.reboot_requested = true;
} }
} }
/* Provide some visual indication that fw is being uploaded */ /* Provide some visual indication that fw is being uploaded */
toggle_led(); toggle_led();
watchdog_update(); watchdog_update();
return (int32_t)bufsize; return (int32_t)bufsize;
} }
/* This is a super-dumb, rudimentary disk, any other scsi command is simply rejected */ /* This is a super-dumb, rudimentary disk, any other scsi command is simply rejected */
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) { int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
return -1; return -1;
} }

View File

@ -75,7 +75,7 @@ void pio_usb_host_config(device_t *state) {
and it will drive it either high or low at any given time and it will drive it either high or low at any given time
- Before uart setup, enable it as an input - Before uart setup, enable it as an input
- Go through a probing sequence of 8 values and pull either up or down - Go through a probing sequence of 8 values and pull either up or down
to that value to that value
- Read out the value on the RX pin - Read out the value on the RX pin
- If the entire sequence of values match, we are definitely floating - If the entire sequence of values match, we are definitely floating
so IC is not connected on BOARD_A_RX, and we're BOARD B so IC is not connected on BOARD_A_RX, and we're BOARD B
@ -84,22 +84,22 @@ int board_autoprobe(void) {
const bool probing_sequence[] = {true, false, false, true, true, false, true, false}; const bool probing_sequence[] = {true, false, false, true, true, false, true, false};
const int seq_len = ARRAY_SIZE(probing_sequence); const int seq_len = ARRAY_SIZE(probing_sequence);
/* Set the pin as INPUT and initialize it */ /* Set the pin as INPUT and initialize it */
gpio_init(BOARD_A_RX); gpio_init(BOARD_A_RX);
gpio_set_dir(BOARD_A_RX, GPIO_IN); gpio_set_dir(BOARD_A_RX, GPIO_IN);
for (int i=0; i<seq_len; i++) { for (int i=0; i<seq_len; i++) {
if (probing_sequence[i]) if (probing_sequence[i])
gpio_pull_up(BOARD_A_RX); gpio_pull_up(BOARD_A_RX);
else else
gpio_pull_down(BOARD_A_RX); gpio_pull_down(BOARD_A_RX);
/* Wait for value to settle */ /* Wait for value to settle */
sleep_ms(3); sleep_ms(3);
/* Read the value */ /* Read the value */
bool value = gpio_get(BOARD_A_RX); bool value = gpio_get(BOARD_A_RX);
gpio_disable_pulls(BOARD_A_RX); gpio_disable_pulls(BOARD_A_RX);
/* If values mismatch at any point, means IC is connected and we're board A */ /* If values mismatch at any point, means IC is connected and we're board A */
if (probing_sequence[i] != value) if (probing_sequence[i] != value)
@ -122,7 +122,7 @@ bool is_config_mode_active(device_t *state) {
/* Remove, so next reboot it's no longer active */ /* Remove, so next reboot it's no longer active */
if (is_active) if (is_active)
watchdog_hw->scratch[5] = 0; watchdog_hw->scratch[5] = 0;
reset_config_timer(state); reset_config_timer(state);
@ -131,23 +131,23 @@ bool is_config_mode_active(device_t *state) {
/* ================================================== * /* ================================================== *
* Configure DMA for reliable UART transfers * Configure DMA for reliable UART transfers
* ================================================== */ * ================================================== */
const uint8_t* uart_buffer_pointers[1] = {uart_rxbuf}; const uint8_t* uart_buffer_pointers[1] = {uart_rxbuf};
uint8_t uart_rxbuf[DMA_RX_BUFFER_SIZE] __attribute__((aligned(DMA_RX_BUFFER_SIZE))) ; uint8_t uart_rxbuf[DMA_RX_BUFFER_SIZE] __attribute__((aligned(DMA_RX_BUFFER_SIZE))) ;
uint8_t uart_txbuf[DMA_TX_BUFFER_SIZE] __attribute__((aligned(DMA_TX_BUFFER_SIZE))) ; uint8_t uart_txbuf[DMA_TX_BUFFER_SIZE] __attribute__((aligned(DMA_TX_BUFFER_SIZE))) ;
static void configure_tx_dma(device_t *state) { static void configure_tx_dma(device_t *state) {
state->dma_tx_channel = dma_claim_unused_channel(true); state->dma_tx_channel = dma_claim_unused_channel(true);
dma_channel_config tx_config = dma_channel_get_default_config(state->dma_tx_channel); dma_channel_config tx_config = dma_channel_get_default_config(state->dma_tx_channel);
channel_config_set_transfer_data_size(&tx_config, DMA_SIZE_8); channel_config_set_transfer_data_size(&tx_config, DMA_SIZE_8);
/* Writing uart (always write the same address, but source addr changes as we read) */ /* Writing uart (always write the same address, but source addr changes as we read) */
channel_config_set_read_increment(&tx_config, true); channel_config_set_read_increment(&tx_config, true);
channel_config_set_write_increment(&tx_config, false); channel_config_set_write_increment(&tx_config, false);
// channel_config_set_ring(&tx_config, false, 4); // channel_config_set_ring(&tx_config, false, 4);
channel_config_set_dreq(&tx_config, DREQ_UART0_TX); channel_config_set_dreq(&tx_config, DREQ_UART0_TX);
/* Configure, but don't start immediately. We'll do this each time the outgoing /* Configure, but don't start immediately. We'll do this each time the outgoing
@ -167,7 +167,7 @@ static void configure_rx_dma(device_t *state) {
state->dma_rx_channel = dma_claim_unused_channel(true); state->dma_rx_channel = dma_claim_unused_channel(true);
state->dma_control_channel = dma_claim_unused_channel(true); state->dma_control_channel = dma_claim_unused_channel(true);
dma_channel_config config = dma_channel_get_default_config(state->dma_rx_channel); dma_channel_config config = dma_channel_get_default_config(state->dma_rx_channel);
dma_channel_config control_config = dma_channel_get_default_config(state->dma_control_channel); dma_channel_config control_config = dma_channel_get_default_config(state->dma_control_channel);
channel_config_set_transfer_data_size(&config, DMA_SIZE_8); channel_config_set_transfer_data_size(&config, DMA_SIZE_8);
@ -185,16 +185,16 @@ static void configure_rx_dma(device_t *state) {
// The UART signals when data is avaliable // The UART signals when data is avaliable
channel_config_set_dreq(&config, DREQ_UART0_RX); channel_config_set_dreq(&config, DREQ_UART0_RX);
channel_config_set_chain_to(&config, state->dma_control_channel); channel_config_set_chain_to(&config, state->dma_control_channel);
dma_channel_configure( dma_channel_configure(
state->dma_rx_channel, state->dma_rx_channel,
&config, &config,
uart_rxbuf, uart_rxbuf,
&uart0_hw->dr, &uart0_hw->dr,
DMA_RX_BUFFER_SIZE, DMA_RX_BUFFER_SIZE,
false); false);
dma_channel_configure( dma_channel_configure(
state->dma_control_channel, state->dma_control_channel,
@ -204,14 +204,14 @@ static void configure_rx_dma(device_t *state) {
1, 1,
false); false);
dma_channel_start(state->dma_control_channel); dma_channel_start(state->dma_control_channel);
} }
/* ================================================== * /* ================================================== *
* Perform initial board/usb setup * Perform initial board/usb setup
* ================================================== */ * ================================================== */
int board; int board;
void initial_setup(device_t *state) { void initial_setup(device_t *state) {
/* PIO USB requires a clock multiple of 12 MHz, setting to 120 MHz */ /* PIO USB requires a clock multiple of 12 MHz, setting to 120 MHz */
@ -248,12 +248,12 @@ void initial_setup(device_t *state) {
multicore_launch_core1(core1_main); multicore_launch_core1(core1_main);
/* Initialize and configure TinyUSB Device */ /* Initialize and configure TinyUSB Device */
tud_init(BOARD_TUD_RHPORT); tud_init(BOARD_TUD_RHPORT);
/* Initialize and configure TinyUSB Host */ /* Initialize and configure TinyUSB Host */
pio_usb_host_config(state); pio_usb_host_config(state);
/* Initialize and configure DMA */ /* Initialize and configure DMA */
configure_tx_dma(state); configure_tx_dma(state);
configure_rx_dma(state); configure_rx_dma(state);
@ -262,7 +262,7 @@ void initial_setup(device_t *state) {
/* Update the core1 initial pass timestamp before enabling the watchdog */ /* Update the core1 initial pass timestamp before enabling the watchdog */
state->core1_last_loop_pass = time_us_64(); state->core1_last_loop_pass = time_us_64();
/* Setup the watchdog so we reboot and recover from a crash */ /* Setup the watchdog so we reboot and recover from a crash */
watchdog_enable(WATCHDOG_TIMEOUT, WATCHDOG_PAUSE_ON_DEBUG); watchdog_enable(WATCHDOG_TIMEOUT, WATCHDOG_PAUSE_ON_DEBUG);
} }

View File

@ -19,7 +19,7 @@
void task_scheduler(device_t *state, task_t *task) { void task_scheduler(device_t *state, task_t *task) {
uint64_t current_time = time_us_64(); uint64_t current_time = time_us_64();
if (current_time < task->next_run) if (current_time < task->next_run)
return; return;
@ -36,7 +36,7 @@ void kick_watchdog_task(device_t *state) {
so it doesn't get updated in the meantime. */ so it doesn't get updated in the meantime. */
uint64_t core1_last_loop_pass = state->core1_last_loop_pass; uint64_t core1_last_loop_pass = state->core1_last_loop_pass;
uint64_t current_time = time_us_64(); uint64_t current_time = time_us_64();
/* If a reboot is requested, we'll stop updating watchdog */ /* If a reboot is requested, we'll stop updating watchdog */
if (state->reboot_requested) if (state->reboot_requested)
return; return;
@ -64,7 +64,7 @@ void screensaver_task(device_t *state) {
const int mouse_move_delay = 5000; const int mouse_move_delay = 5000;
screensaver_t *screensaver = &state->config.output[BOARD_ROLE].screensaver; screensaver_t *screensaver = &state->config.output[BOARD_ROLE].screensaver;
uint64_t inactivity_period = time_us_64() - state->last_activity[BOARD_ROLE]; uint64_t inactivity_period = time_us_64() - state->last_activity[BOARD_ROLE];
static mouse_report_t report = {0}; static mouse_report_t report = {0};
static int last_pointer_move = 0; static int last_pointer_move = 0;
static int dx = 20, dy = 25, jitter = 1; static int dx = 20, dy = 25, jitter = 1;
@ -119,11 +119,11 @@ void screensaver_task(device_t *state) {
} }
/* Periodically emit heartbeat packets */ /* Periodically emit heartbeat packets */
void heartbeat_output_task(device_t *state) { void heartbeat_output_task(device_t *state) {
/* If firmware upgrade is in progress, don't touch flash_cs */ /* If firmware upgrade is in progress, don't touch flash_cs */
if (state->fw.upgrade_in_progress) if (state->fw.upgrade_in_progress)
return; return;
if (state->config_mode_active) { if (state->config_mode_active) {
/* Leave config mode if timeout expired and user didn't click exit */ /* Leave config mode if timeout expired and user didn't click exit */
if (time_us_64() > state->config_mode_timer) if (time_us_64() > state->config_mode_timer)
@ -140,12 +140,12 @@ void heartbeat_output_task(device_t *state) {
uart_packet_t packet = { uart_packet_t packet = {
.type = HEARTBEAT_MSG, .type = HEARTBEAT_MSG,
.data16 = { .data16 = {
[0] = state->_running_fw.version, [0] = state->_running_fw.version,
[2] = state->active_output, [2] = state->active_output,
}, },
}; };
queue_try_add(&global_state.uart_tx_queue, &packet); queue_try_add(&global_state.uart_tx_queue, &packet);
} }
/* Process outgoing config report messages. */ /* Process outgoing config report messages. */
@ -194,14 +194,14 @@ void firmware_upgrade_task(device_t *state) {
} }
} }
/* If we're on the last element of the current page, page is done - write it. */ /* If we're on the last element of the current page, page is done - write it. */
if (TU_U32_BYTE0(state->fw.address) == 0x00) { if (TU_U32_BYTE0(state->fw.address) == 0x00) {
uint32_t page_start_addr = (state->fw.address - 1) & 0xFFFFFF00; uint32_t page_start_addr = (state->fw.address - 1) & 0xFFFFFF00;
write_flash_page((uint32_t)ADDR_FW_RUNNING + page_start_addr - XIP_BASE, state->page_buffer); write_flash_page((uint32_t)ADDR_FW_RUNNING + page_start_addr - XIP_BASE, state->page_buffer);
} }
request_byte(state, state->fw.address); request_byte(state, state->fw.address);
} }
void packet_receiver_task(device_t *state) { void packet_receiver_task(device_t *state) {
@ -210,7 +210,7 @@ void packet_receiver_task(device_t *state) {
uint32_t delta = get_ptr_delta(current_pointer, state); uint32_t delta = get_ptr_delta(current_pointer, state);
/* If we don't have enough characters for a packet, skip loop and return immediately */ /* If we don't have enough characters for a packet, skip loop and return immediately */
while (delta >= RAW_PACKET_LENGTH) { while (delta >= RAW_PACKET_LENGTH) {
if (is_start_of_packet(state)) { if (is_start_of_packet(state)) {
fetch_packet(state); fetch_packet(state);
process_packet(&state->in_packet, state); process_packet(&state->in_packet, state);

View File

@ -22,15 +22,15 @@
* ================================================== */ * ================================================== */
/* Takes a packet as uart_packet_t struct, adds preamble, checksum and encodes it to a raw array. */ /* Takes a packet as uart_packet_t struct, adds preamble, checksum and encodes it to a raw array. */
void write_raw_packet(uint8_t *dst, uart_packet_t *packet) { void write_raw_packet(uint8_t *dst, uart_packet_t *packet) {
uint8_t pkt[RAW_PACKET_LENGTH] = {[0] = START1, uint8_t pkt[RAW_PACKET_LENGTH] = {[0] = START1,
[1] = START2, [1] = START2,
[2] = packet->type, [2] = packet->type,
/* [3-10] is data, defaults to 0 */ /* [3-10] is data, defaults to 0 */
[11] = calc_checksum(packet->data, PACKET_DATA_LENGTH)}; [11] = calc_checksum(packet->data, PACKET_DATA_LENGTH)};
memcpy(&pkt[START_LENGTH + TYPE_LENGTH], packet->data, PACKET_DATA_LENGTH); memcpy(&pkt[START_LENGTH + TYPE_LENGTH], packet->data, PACKET_DATA_LENGTH);
memcpy(dst, &pkt, RAW_PACKET_LENGTH); memcpy(dst, &pkt, RAW_PACKET_LENGTH);
} }
/* Schedule packet for sending to the other box */ /* Schedule packet for sending to the other box */
@ -38,7 +38,7 @@ void queue_packet(const uint8_t *data, enum packet_type_e packet_type, int lengt
uart_packet_t packet = {.type = packet_type}; uart_packet_t packet = {.type = packet_type};
memcpy(packet.data, data, length); memcpy(packet.data, data, length);
queue_try_add(&global_state.uart_tx_queue, &packet); queue_try_add(&global_state.uart_tx_queue, &packet);
} }
/* Sends just one byte of a certain packet type to the other box. */ /* Sends just one byte of a certain packet type to the other box. */
@ -56,7 +56,7 @@ void process_uart_tx_task(device_t *state) {
if (!queue_try_remove(&state->uart_tx_queue, &packet)) if (!queue_try_remove(&state->uart_tx_queue, &packet))
return; return;
write_raw_packet(uart_txbuf, &packet); write_raw_packet(uart_txbuf, &packet);
dma_channel_transfer_from_buffer_now(state->dma_tx_channel, uart_txbuf, RAW_PACKET_LENGTH); dma_channel_transfer_from_buffer_now(state->dma_tx_channel, uart_txbuf, RAW_PACKET_LENGTH);
} }
@ -69,7 +69,7 @@ const uart_handler_t uart_handler[] = {
{.type = KEYBOARD_REPORT_MSG, .handler = handle_keyboard_uart_msg}, {.type = KEYBOARD_REPORT_MSG, .handler = handle_keyboard_uart_msg},
{.type = MOUSE_REPORT_MSG, .handler = handle_mouse_abs_uart_msg}, {.type = MOUSE_REPORT_MSG, .handler = handle_mouse_abs_uart_msg},
{.type = OUTPUT_SELECT_MSG, .handler = handle_output_select_msg}, {.type = OUTPUT_SELECT_MSG, .handler = handle_output_select_msg},
/* Box control */ /* Box control */
{.type = MOUSE_ZOOM_MSG, .handler = handle_mouse_zoom_msg}, {.type = MOUSE_ZOOM_MSG, .handler = handle_mouse_zoom_msg},
{.type = KBD_SET_REPORT_MSG, .handler = handle_set_report_msg}, {.type = KBD_SET_REPORT_MSG, .handler = handle_set_report_msg},
@ -77,7 +77,7 @@ const uart_handler_t uart_handler[] = {
{.type = SYNC_BORDERS_MSG, .handler = handle_sync_borders_msg}, {.type = SYNC_BORDERS_MSG, .handler = handle_sync_borders_msg},
{.type = FLASH_LED_MSG, .handler = handle_flash_led_msg}, {.type = FLASH_LED_MSG, .handler = handle_flash_led_msg},
{.type = CONSUMER_CONTROL_MSG, .handler = handle_consumer_control_msg}, {.type = CONSUMER_CONTROL_MSG, .handler = handle_consumer_control_msg},
/* Config */ /* Config */
{.type = WIPE_CONFIG_MSG, .handler = handle_wipe_config_msg}, {.type = WIPE_CONFIG_MSG, .handler = handle_wipe_config_msg},
{.type = SAVE_CONFIG_MSG, .handler = handle_save_config_msg}, {.type = SAVE_CONFIG_MSG, .handler = handle_save_config_msg},
@ -90,7 +90,7 @@ const uart_handler_t uart_handler[] = {
{.type = RESPONSE_BYTE_MSG, .handler = handle_response_byte_msg}, {.type = RESPONSE_BYTE_MSG, .handler = handle_response_byte_msg},
{.type = FIRMWARE_UPGRADE_MSG, .handler = handle_fw_upgrade_msg}, {.type = FIRMWARE_UPGRADE_MSG, .handler = handle_fw_upgrade_msg},
{.type = HEARTBEAT_MSG, .handler = handle_heartbeat_msg}, {.type = HEARTBEAT_MSG, .handler = handle_heartbeat_msg},
{.type = PROXY_PACKET_MSG, .handler = handle_proxy_msg}, {.type = PROXY_PACKET_MSG, .handler = handle_proxy_msg},
}; };

View File

@ -28,7 +28,7 @@ uint16_t tud_hid_get_report_cb(uint8_t instance,
uint8_t report_id, uint8_t report_id,
hid_report_type_t report_type, hid_report_type_t report_type,
uint8_t *buffer, uint8_t *buffer,
uint16_t request_len) { uint16_t request_len) {
return 0; return 0;
} }
@ -46,15 +46,15 @@ void tud_hid_set_report_cb(uint8_t instance,
uint16_t bufsize) { uint16_t bufsize) {
/* We received a report on the config report ID */ /* We received a report on the config report ID */
if (instance == ITF_NUM_HID_VENDOR && report_id == REPORT_ID_VENDOR) { if (instance == ITF_NUM_HID_VENDOR && report_id == REPORT_ID_VENDOR) {
/* Security - only if config mode is enabled are we allowed to do anything. While the report_id /* Security - only if config mode is enabled are we allowed to do anything. While the report_id
isn't even advertised when not in config mode, security must always be explicit and never assume */ isn't even advertised when not in config mode, security must always be explicit and never assume */
if (!global_state.config_mode_active) if (!global_state.config_mode_active)
return; return;
/* We insist on a fixed size packet. No overflows. */ /* We insist on a fixed size packet. No overflows. */
if (bufsize != RAW_PACKET_LENGTH) if (bufsize != RAW_PACKET_LENGTH)
return; return;
uart_packet_t *packet = (uart_packet_t *) (buffer + START_LENGTH); uart_packet_t *packet = (uart_packet_t *) (buffer + START_LENGTH);
@ -62,8 +62,8 @@ void tud_hid_set_report_cb(uint8_t instance,
if (!validate_packet(packet)) if (!validate_packet(packet))
return; return;
process_packet(packet, &global_state); process_packet(packet, &global_state);
} }
/* Only other set report we care about is LED state change, and that's exactly 1 byte long */ /* Only other set report we care about is LED state change, and that's exactly 1 byte long */
if (report_id != REPORT_ID_KEYBOARD || bufsize != 1 || report_type != HID_REPORT_TYPE_OUTPUT) if (report_id != REPORT_ID_KEYBOARD || bufsize != 1 || report_type != HID_REPORT_TYPE_OUTPUT)
@ -125,36 +125,36 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
memset(iface, 0, sizeof(hid_interface_t)); memset(iface, 0, sizeof(hid_interface_t));
} }
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) { void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
uint8_t itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); uint8_t itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
if (dev_addr >= MAX_DEVICES || instance > MAX_INTERFACES) if (dev_addr >= MAX_DEVICES || instance > MAX_INTERFACES)
return; return;
/* Get interface information */ /* Get interface information */
hid_interface_t *iface = &global_state.iface[dev_addr-1][instance]; hid_interface_t *iface = &global_state.iface[dev_addr-1][instance];
iface->protocol = tuh_hid_get_protocol(dev_addr, instance); iface->protocol = tuh_hid_get_protocol(dev_addr, instance);
/* Safeguard against memory corruption in case the number of instances exceeds our maximum */ /* Safeguard against memory corruption in case the number of instances exceeds our maximum */
if (instance >= MAX_INTERFACES) if (instance >= MAX_INTERFACES)
return; return;
/* Parse the report descriptor into our internal structure. */ /* Parse the report descriptor into our internal structure. */
parse_report_descriptor(iface, desc_report, desc_len); parse_report_descriptor(iface, desc_report, desc_len);
switch (itf_protocol) { switch (itf_protocol) {
case HID_ITF_PROTOCOL_KEYBOARD: case HID_ITF_PROTOCOL_KEYBOARD:
if (global_state.config.enforce_ports && BOARD_ROLE == OUTPUT_B) if (global_state.config.enforce_ports && BOARD_ROLE == OUTPUT_B)
return; return;
if (global_state.config.force_kbd_boot_protocol) if (global_state.config.force_kbd_boot_protocol)
tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_BOOT); tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_BOOT);
/* Keeping this is required for setting leds from device set_report callback */ /* Keeping this is required for setting leds from device set_report callback */
global_state.kbd_dev_addr = dev_addr; global_state.kbd_dev_addr = dev_addr;
global_state.kbd_instance = instance; global_state.kbd_instance = instance;
global_state.keyboard_connected = true; global_state.keyboard_connected = true;
break; break;
case HID_ITF_PROTOCOL_MOUSE: case HID_ITF_PROTOCOL_MOUSE:
@ -167,8 +167,8 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re
tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_REPORT); tuh_hid_set_protocol(dev_addr, instance, HID_PROTOCOL_REPORT);
} }
break; break;
case HID_ITF_PROTOCOL_NONE: case HID_ITF_PROTOCOL_NONE:
break; break;
} }
/* Flash local led to indicate a device was connected */ /* Flash local led to indicate a device was connected */
@ -177,7 +177,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re
/* Also signal the other board to flash LED, to enable easy verification if serial works */ /* Also signal the other board to flash LED, to enable easy verification if serial works */
send_value(ENABLE, FLASH_LED_MSG); send_value(ENABLE, FLASH_LED_MSG);
/* Kick off the report querying */ /* Kick off the report querying */
tuh_hid_receive_report(dev_addr, instance); tuh_hid_receive_report(dev_addr, instance);
} }
@ -202,7 +202,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
if (receiver != NULL) if (receiver != NULL)
receiver((uint8_t *)report, len, itf_protocol, iface); receiver((uint8_t *)report, len, itf_protocol, iface);
} }
} }
else if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { else if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
process_keyboard_report((uint8_t *)report, len, itf_protocol, iface); process_keyboard_report((uint8_t *)report, len, itf_protocol, iface);
@ -216,7 +216,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
} }
/* Set protocol in a callback. This is tied to an interface, not a specific report ID */ /* Set protocol in a callback. This is tied to an interface, not a specific report ID */
void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol) { void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol) {
if (dev_addr >= MAX_DEVICES || idx > MAX_INTERFACES) if (dev_addr >= MAX_DEVICES || idx > MAX_INTERFACES)
return; return;

View File

@ -33,14 +33,14 @@
// https://github.com/raspberrypi/usb-pid // https://github.com/raspberrypi/usb-pid
tusb_desc_device_t const desc_device = DEVICE_DESCRIPTOR(0x2e8a, 0x107c); tusb_desc_device_t const desc_device = DEVICE_DESCRIPTOR(0x2e8a, 0x107c);
// https://pid.codes/1209/C000/ // https://pid.codes/1209/C000/
tusb_desc_device_t const desc_device_config = DEVICE_DESCRIPTOR(0x1209, 0xc000); tusb_desc_device_t const desc_device_config = DEVICE_DESCRIPTOR(0x1209, 0xc000);
// Invoked when received GET DEVICE DESCRIPTOR // Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor // Application return pointer to descriptor
uint8_t const *tud_descriptor_device_cb(void) { uint8_t const *tud_descriptor_device_cb(void) {
if (global_state.config_mode_active) if (global_state.config_mode_active)
return (uint8_t const *)&desc_device_config; return (uint8_t const *)&desc_device_config;
else else
return (uint8_t const *)&desc_device; return (uint8_t const *)&desc_device;
@ -75,10 +75,10 @@ uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance) {
case ITF_NUM_HID: case ITF_NUM_HID:
return desc_hid_report; return desc_hid_report;
case ITF_NUM_HID_REL_M: case ITF_NUM_HID_REL_M:
return desc_hid_report_relmouse; return desc_hid_report_relmouse;
default: default:
return desc_hid_report; return desc_hid_report;
} }
} }
bool tud_mouse_report(uint8_t mode, uint8_t buttons, int16_t x, int16_t y, int8_t wheel) { bool tud_mouse_report(uint8_t mode, uint8_t buttons, int16_t x, int16_t y, int8_t wheel) {
@ -253,14 +253,14 @@ uint8_t const desc_configuration_config[] = {
// Interface number, string index, EP notification address and size, EP data address (out, in) and size. // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR( TUD_CDC_DESCRIPTOR(
ITF_NUM_CDC, STRID_DEBUG, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, CFG_TUD_CDC_EP_BUFSIZE), ITF_NUM_CDC, STRID_DEBUG, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, CFG_TUD_CDC_EP_BUFSIZE),
#endif #endif
}; };
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void)index; // for multiple configurations (void)index; // for multiple configurations
if (global_state.config_mode_active) if (global_state.config_mode_active)
return desc_configuration_config; return desc_configuration_config;
else else
return desc_configuration; return desc_configuration;
} }

View File

@ -37,7 +37,7 @@ bool verify_checksum(const uart_packet_t *packet) {
} }
uint32_t crc32_iter(uint32_t crc, const uint8_t byte) { uint32_t crc32_iter(uint32_t crc, const uint8_t byte) {
return crc32_lookup_table[(byte ^ crc) & 0xff] ^ (crc >> 8); return crc32_lookup_table[(byte ^ crc) & 0xff] ^ (crc >> 8);
} }
/* TODO - use DMA sniffer's built-in CRC32 */ /* TODO - use DMA sniffer's built-in CRC32 */
@ -69,12 +69,12 @@ void write_flash_page(uint32_t target_addr, uint8_t *buffer) {
/* Start of sector == first 256-byte page in a 4096 byte block */ /* Start of sector == first 256-byte page in a 4096 byte block */
bool is_sector_start = (target_addr & 0xf00) == 0; bool is_sector_start = (target_addr & 0xf00) == 0;
uint32_t ints = save_and_disable_interrupts(); uint32_t ints = save_and_disable_interrupts();
if (is_sector_start) if (is_sector_start)
flash_range_erase(target_addr, FLASH_SECTOR_SIZE); flash_range_erase(target_addr, FLASH_SECTOR_SIZE);
flash_range_program(target_addr, buffer, FLASH_PAGE_SIZE); flash_range_program(target_addr, buffer, FLASH_PAGE_SIZE);
restore_interrupts(ints); restore_interrupts(ints);
} }
void load_config(device_t *state) { void load_config(device_t *state) {
@ -82,8 +82,8 @@ void load_config(device_t *state) {
config_t *running_config = &state->config; config_t *running_config = &state->config;
/* Load the flash config first, including the checksum */ /* Load the flash config first, including the checksum */
memcpy(running_config, config, sizeof(config_t)); memcpy(running_config, config, sizeof(config_t));
/* Calculate and update checksum, size without checksum */ /* Calculate and update checksum, size without checksum */
uint8_t checksum = calc_crc32((uint8_t *)running_config, sizeof(config_t) - sizeof(uint32_t)); uint8_t checksum = calc_crc32((uint8_t *)running_config, sizeof(config_t) - sizeof(uint32_t));
@ -110,9 +110,9 @@ void save_config(device_t *state) {
/* Copy the config to buffer and pad the rest with zeros */ /* Copy the config to buffer and pad the rest with zeros */
memcpy(state->page_buffer, raw_config, sizeof(config_t)); memcpy(state->page_buffer, raw_config, sizeof(config_t));
memset(state->page_buffer + sizeof(config_t), 0, FLASH_PAGE_SIZE - sizeof(config_t)); memset(state->page_buffer + sizeof(config_t), 0, FLASH_PAGE_SIZE - sizeof(config_t));
/* Write the new config to flash */ /* Write the new config to flash */
write_flash_page((uint32_t)ADDR_CONFIG - XIP_BASE, state->page_buffer); write_flash_page((uint32_t)ADDR_CONFIG - XIP_BASE, state->page_buffer);
} }
@ -120,10 +120,10 @@ void reset_config_timer(device_t *state) {
/* Once this is reached, we leave the config mode */ /* Once this is reached, we leave the config mode */
state->config_mode_timer = time_us_64() + CONFIG_MODE_TIMEOUT; state->config_mode_timer = time_us_64() + CONFIG_MODE_TIMEOUT;
} }
void _configure_flash_cs(enum gpio_override gpo, uint pin_index) { void _configure_flash_cs(enum gpio_override gpo, uint pin_index) {
hw_write_masked(&ioqspi_hw->io[pin_index].ctrl, hw_write_masked(&ioqspi_hw->io[pin_index].ctrl,
gpo << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB, gpo << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS); IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
} }
@ -152,11 +152,11 @@ void request_byte(device_t *state, uint32_t address) {
}; };
state->fw.byte_done = false; state->fw.byte_done = false;
queue_try_add(&global_state.uart_tx_queue, &packet); queue_try_add(&global_state.uart_tx_queue, &packet);
} }
void reboot(void) { void reboot(void) {
*((volatile uint32_t*)(PPB_BASE + 0x0ED0C)) = 0x5FA0004; *((volatile uint32_t*)(PPB_BASE + 0x0ED0C)) = 0x5FA0004;
} }
bool is_start_of_packet(device_t *state) { bool is_start_of_packet(device_t *state) {
@ -204,8 +204,8 @@ bool validate_packet(uart_packet_t *packet) {
uint8_t packet_type = packet->type; uint8_t packet_type = packet->type;
/* Proxied packets are encapsulated in the data field, but same rules apply */ /* Proxied packets are encapsulated in the data field, but same rules apply */
if (packet->type == PROXY_PACKET_MSG) if (packet->type == PROXY_PACKET_MSG)
packet_type = packet->data[0]; packet_type = packet->data[0];
for (int i = 0; i < ARRAY_SIZE(ALLOWED_PACKETS); i++) { for (int i = 0; i < ARRAY_SIZE(ALLOWED_PACKETS); i++) {
if (ALLOWED_PACKETS[i] == packet_type) if (ALLOWED_PACKETS[i] == packet_type)