|
| 1 | +/***************************************************************************** |
| 2 | +# # |
| 3 | +# KVMD - The main PiKVM daemon. # |
| 4 | +# # |
| 5 | +# Copyright (C) 2018-2023 Maxim Devaev <[email protected]> # |
| 6 | +# # |
| 7 | +# This program is free software: you can redistribute it and/or modify # |
| 8 | +# it under the terms of the GNU General Public License as published by # |
| 9 | +# the Free Software Foundation, either version 3 of the License, or # |
| 10 | +# (at your option) any later version. # |
| 11 | +# # |
| 12 | +# This program is distributed in the hope that it will be useful, # |
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of # |
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # |
| 15 | +# GNU General Public License for more details. # |
| 16 | +# # |
| 17 | +# You should have received a copy of the GNU General Public License # |
| 18 | +# along with this program. If not, see <https://www.gnu.org/licenses/>. # |
| 19 | +# # |
| 20 | +*****************************************************************************/ |
| 21 | + |
| 22 | + |
| 23 | +#include "pico/stdlib.h" |
| 24 | +#include "hardware/gpio.h" |
| 25 | +#include "hardware/watchdog.h" |
| 26 | + |
| 27 | +#include "ph_types.h" |
| 28 | +#include "ph_tools.h" |
| 29 | +#include "ph_outputs.h" |
| 30 | +#include "ph_usb.h" |
| 31 | +#include "ph_spi.h" |
| 32 | +#include "ph_proto.h" |
| 33 | +#include "ph_cmds.h" |
| 34 | +#include "ph_debug.h" |
| 35 | + |
| 36 | + |
| 37 | +static bool _reset_required = false; |
| 38 | + |
| 39 | + |
| 40 | +static u8 _handle_request(const u8 *data) { // 8 bytes |
| 41 | + // FIXME: See kvmd/kvmd#80 |
| 42 | + // Should input buffer be cleared in this case? |
| 43 | + if (data[0] == PH_PROTO_MAGIC && ph_crc16(data, 6) == ph_merge8_u16(data[6], data[7])) { |
| 44 | +# define HANDLE(x_handler, x_reset) { \ |
| 45 | + x_handler(data + 2); \ |
| 46 | + if (x_reset) { _reset_required = true; } \ |
| 47 | + return PH_PROTO_PONG_OK; \ |
| 48 | + } |
| 49 | + switch (data[1]) { |
| 50 | + case PH_PROTO_CMD_PING: return PH_PROTO_PONG_OK; |
| 51 | + case PH_PROTO_CMD_SET_KBD: HANDLE(ph_cmd_set_kbd, true); |
| 52 | + case PH_PROTO_CMD_SET_MOUSE: HANDLE(ph_cmd_set_mouse, true); |
| 53 | + case PH_PROTO_CMD_SET_CONNECTED: return PH_PROTO_PONG_OK; // Arduino AUM |
| 54 | + case PH_PROTO_CMD_CLEAR_HID: HANDLE(ph_cmd_send_clear, false); |
| 55 | + case PH_PROTO_CMD_KBD_KEY: HANDLE(ph_cmd_kbd_send_key, false); |
| 56 | + case PH_PROTO_CMD_MOUSE_BUTTON: HANDLE(ph_cmd_mouse_send_button, false); |
| 57 | + case PH_PROTO_CMD_MOUSE_ABS: HANDLE(ph_cmd_mouse_send_abs, false); |
| 58 | + case PH_PROTO_CMD_MOUSE_REL: HANDLE(ph_cmd_mouse_send_rel, false); |
| 59 | + case PH_PROTO_CMD_MOUSE_WHEEL: HANDLE(ph_cmd_mouse_send_wheel, false); |
| 60 | + case PH_PROTO_CMD_REPEAT: return 0; |
| 61 | + } |
| 62 | +# undef HANDLE |
| 63 | + return PH_PROTO_RESP_INVALID_ERROR; |
| 64 | + } |
| 65 | + return PH_PROTO_RESP_CRC_ERROR; |
| 66 | +} |
| 67 | + |
| 68 | +static void _send_response(u8 code) { |
| 69 | + static u8 prev_code = PH_PROTO_RESP_NONE; |
| 70 | + if (code == 0) { |
| 71 | + code = prev_code; // Repeat the last code |
| 72 | + } else { |
| 73 | + prev_code = code; |
| 74 | + } |
| 75 | + |
| 76 | + u8 resp[8] = {0}; |
| 77 | + resp[0] = PH_PROTO_MAGIC_RESP; |
| 78 | + |
| 79 | + if (code & PH_PROTO_PONG_OK) { |
| 80 | + resp[1] = PH_PROTO_PONG_OK; |
| 81 | + if (_reset_required) { |
| 82 | + resp[1] |= PH_PROTO_PONG_RESET_REQUIRED; |
| 83 | + } |
| 84 | + resp[2] = PH_PROTO_OUT1_DYNAMIC; |
| 85 | + |
| 86 | + resp[1] |= ph_cmd_get_offlines(); |
| 87 | + resp[1] |= ph_cmd_kbd_get_leds(); |
| 88 | + resp[2] |= ph_g_outputs_active; |
| 89 | + resp[3] |= ph_g_outputs_avail; |
| 90 | + } else { |
| 91 | + resp[1] = code; |
| 92 | + } |
| 93 | + |
| 94 | + ph_split16(ph_crc16(resp, 6), &resp[6], &resp[7]); |
| 95 | + |
| 96 | + ph_spi_write(resp); |
| 97 | + |
| 98 | + if (_reset_required) { |
| 99 | + watchdog_reboot(0, 0, 100); // Даем немного времени чтобы отправить ответ, а потом ребутимся |
| 100 | + } |
| 101 | +} |
| 102 | + |
| 103 | +static void _spi_data_handler(const u8 *data) { |
| 104 | + _send_response(_handle_request(data)); |
| 105 | +} |
| 106 | + |
| 107 | + |
| 108 | +int main(void) { |
| 109 | + ph_debug_init(false); // No UART |
| 110 | + ph_outputs_init(); |
| 111 | + ph_usb_init(); |
| 112 | + ph_spi_init(_spi_data_handler); |
| 113 | + |
| 114 | + while (true) { |
| 115 | + ph_usb_task(); |
| 116 | + if (!_reset_required) { |
| 117 | + ph_spi_task(); |
| 118 | + ph_debug_act_pulse(50); |
| 119 | + } |
| 120 | + } |
| 121 | + return 0; |
| 122 | +} |
0 commit comments