pocket-hid: port OLED menu from reform incl battery status, some refactoring
This commit is contained in:
parent
d12064b469
commit
ee66d3c149
7 changed files with 683 additions and 222 deletions
|
|
@ -17,6 +17,8 @@ target_sources(${PROJECT} PUBLIC
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/oled.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/remote.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/menu.c
|
||||
)
|
||||
|
||||
# Example include
|
||||
|
|
|
|||
22
pocket-reform-keyboard-fw/pocket-hid/src/keyboard.h
Normal file
22
pocket-reform-keyboard-fw/pocket-hid/src/keyboard.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
MNT Reform 2.0 Keyboard Firmware
|
||||
See keyboard.c for Copyright
|
||||
SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef _KEYBOARD_H_
|
||||
#define _KEYBOARD_H_
|
||||
|
||||
#define PREF_HID_FW_REV "PREFHID20240412"
|
||||
|
||||
void reset_keyboard_state(void);
|
||||
|
||||
void led_set(uint32_t rgb);
|
||||
void led_task(uint32_t rgb);
|
||||
void led_mod_hue(int d);
|
||||
void led_mod_brightness(int d);
|
||||
void led_set_brightness(int b);
|
||||
void led_mod_saturation(int d);
|
||||
void led_cycle_hue();
|
||||
|
||||
#endif
|
||||
|
|
@ -1,27 +1,8 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
Copyright (c) 2021-2024 MNT Research GmbH (mntre.com)
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -39,6 +20,9 @@
|
|||
|
||||
#include "usb_descriptors.h"
|
||||
#include "oled.h"
|
||||
#include "menu.h"
|
||||
#include "remote.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
#include "ws2812.pio.h"
|
||||
|
||||
|
|
@ -86,12 +70,6 @@ static int pressed_keys = 0;
|
|||
static volatile uint32_t led_value = 0;
|
||||
|
||||
void hid_task(void);
|
||||
void led_set(uint32_t rgb);
|
||||
void led_task(uint32_t rgb);
|
||||
void led_mod_hue(int d);
|
||||
void led_mod_brightness(int d);
|
||||
void led_set_brightness(int b);
|
||||
void led_cycle_hue();
|
||||
int process_keyboard(uint8_t* resulting_scancodes);
|
||||
|
||||
#define UART_ID uart1
|
||||
|
|
@ -100,75 +78,6 @@ int process_keyboard(uint8_t* resulting_scancodes);
|
|||
#define STOP_BITS 1
|
||||
#define PARITY UART_PARITY_NONE
|
||||
|
||||
static char uart_rx_line[128];
|
||||
static int uart_rx_i=0;
|
||||
|
||||
void insert_bat_icon(char* str, int x, float v) {
|
||||
char icon = 0;
|
||||
if (v>=80) {
|
||||
icon = 8;
|
||||
} else if (v>=60) {
|
||||
icon = 6;
|
||||
} else if (v>=40) {
|
||||
icon = 4;
|
||||
} else if (v>=20) {
|
||||
icon = 2;
|
||||
} else {
|
||||
icon = 0;
|
||||
}
|
||||
str[x] = 4*32+icon;
|
||||
str[x+1] = 4*32+icon+1;
|
||||
}
|
||||
|
||||
void on_uart_rx() {
|
||||
while (uart_is_readable(UART_ID)) {
|
||||
char c = uart_getc(UART_ID);
|
||||
if (uart_rx_i<127) {
|
||||
uart_rx_line[uart_rx_i++] = c;
|
||||
uart_rx_line[uart_rx_i] = 0;
|
||||
} else {
|
||||
uart_rx_i = 0;
|
||||
}
|
||||
if (c == '\n') {
|
||||
// TODO hack
|
||||
|
||||
if (uart_rx_i>6) {
|
||||
gfx_clear();
|
||||
//gfx_poke_str(0, 3, uart_rx_line);
|
||||
// cut off after 4 digits
|
||||
uart_rx_line[4] = 0;
|
||||
float percentage = ((float)atoi(uart_rx_line))/(float)10.0;
|
||||
|
||||
char batinfo[32];
|
||||
sprintf(batinfo, " %.1f%%", (double)percentage);
|
||||
insert_bat_icon(batinfo, 0, percentage);
|
||||
gfx_poke_str(7, 1, batinfo);
|
||||
gfx_flush();
|
||||
}
|
||||
uart_rx_i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void anim_hello(void) {
|
||||
gfx_clear();
|
||||
gfx_on();
|
||||
for (int y=0; y<3; y++) {
|
||||
for (int x=0; x<12; x++) {
|
||||
gfx_poke((uint8_t)(x+4),(uint8_t)(y+1),(uint8_t)((5+y)*32+x));
|
||||
}
|
||||
gfx_flush();
|
||||
}
|
||||
for (uint8_t y=0; y<0xff; y++) {
|
||||
gfx_contrast(y);
|
||||
sleep_ms(0);
|
||||
}
|
||||
for (uint8_t y=0; y<0xff; y++) {
|
||||
gfx_contrast(0xff-y);
|
||||
sleep_ms(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------- MAIN -------------*/
|
||||
int main(void)
|
||||
{
|
||||
|
|
@ -191,40 +100,28 @@ int main(void)
|
|||
|
||||
gpio_init(PIN_COL1);
|
||||
gpio_set_dir(PIN_COL1, true);
|
||||
//gpio_pull_up(PIN_COL1);
|
||||
gpio_init(PIN_COL2);
|
||||
gpio_set_dir(PIN_COL2, true);
|
||||
//gpio_pull_up(PIN_COL2);
|
||||
gpio_init(PIN_COL3);
|
||||
gpio_set_dir(PIN_COL3, true);
|
||||
//gpio_pull_up(PIN_COL3);
|
||||
gpio_init(PIN_COL4);
|
||||
gpio_set_dir(PIN_COL4, true);
|
||||
//gpio_pull_up(PIN_COL4);
|
||||
gpio_init(PIN_COL5);
|
||||
gpio_set_dir(PIN_COL5, true);
|
||||
//gpio_pull_up(PIN_COL5);
|
||||
gpio_init(PIN_COL6);
|
||||
gpio_set_dir(PIN_COL6, true);
|
||||
//gpio_pull_up(PIN_COL6);
|
||||
gpio_init(PIN_COL7);
|
||||
gpio_set_dir(PIN_COL7, true);
|
||||
//gpio_pull_up(PIN_COL7);
|
||||
gpio_init(PIN_COL8);
|
||||
gpio_set_dir(PIN_COL8, true);
|
||||
//gpio_pull_up(PIN_COL8);
|
||||
gpio_init(PIN_COL9);
|
||||
gpio_set_dir(PIN_COL9, true);
|
||||
//gpio_pull_up(PIN_COL9);
|
||||
gpio_init(PIN_COL10);
|
||||
gpio_set_dir(PIN_COL10, true);
|
||||
//gpio_pull_up(PIN_COL10);
|
||||
gpio_init(PIN_COL11);
|
||||
gpio_set_dir(PIN_COL11, true);
|
||||
//gpio_pull_up(PIN_COL11);
|
||||
gpio_init(PIN_COL12);
|
||||
gpio_set_dir(PIN_COL12, true);
|
||||
//gpio_pull_up(PIN_COL12);
|
||||
|
||||
gpio_init(PIN_ROW1);
|
||||
gpio_set_dir(PIN_ROW1, false);
|
||||
|
|
@ -267,11 +164,12 @@ int main(void)
|
|||
led_set_brightness(0x0);
|
||||
|
||||
gfx_init(false);
|
||||
anim_hello();
|
||||
//anim_hello();
|
||||
|
||||
irq_set_exclusive_handler(UART_IRQ, on_uart_rx);
|
||||
irq_set_exclusive_handler(UART_IRQ, remote_on_uart_rx);
|
||||
irq_set_enabled(UART_IRQ, true);
|
||||
uart_set_irq_enables(UART_ID, true, false); // bool rx_has_data, bool tx_needs_data
|
||||
// bool rx_has_data, bool tx_needs_data
|
||||
uart_set_irq_enables(UART_ID, true, false);
|
||||
|
||||
while (1) {
|
||||
pressed_keys = process_keyboard(pressed_scancodes);
|
||||
|
|
@ -351,31 +249,38 @@ bool tud_hid_trackball_report(uint8_t report_id,
|
|||
|
||||
uint8_t matrix_debounce[KBD_COLS*KBD_ROWS];
|
||||
uint8_t matrix_state[KBD_COLS*KBD_ROWS];
|
||||
|
||||
int active_meta_mode = 0;
|
||||
uint8_t last_meta_key = 0;
|
||||
|
||||
uint8_t* active_matrix = matrix;
|
||||
bool media_toggle = 0;
|
||||
bool fn_key = 0; // Am I holding FN?
|
||||
bool circle = 0; // Am I holding circle?
|
||||
|
||||
int command_sent = 0;
|
||||
int soc_power_on = 0; // fixme
|
||||
|
||||
void remote_turn_on_som() {
|
||||
uart_puts(UART_ID, "\r\n1p\r\n");
|
||||
led_set_brightness(10);
|
||||
soc_power_on = 1;
|
||||
// enter the menu
|
||||
void enter_meta_mode(void) {
|
||||
active_meta_mode = 1;
|
||||
reset_and_render_menu();
|
||||
if (!remote_get_power_state()) {
|
||||
led_set_brightness(10);
|
||||
}
|
||||
}
|
||||
|
||||
void remote_turn_off_som() {
|
||||
uart_puts(UART_ID, "\r\n0p\r\n");
|
||||
led_set_brightness(0);
|
||||
soc_power_on = 0;
|
||||
void exit_meta_mode(void) {
|
||||
active_meta_mode = 0;
|
||||
if (!remote_get_power_state()) {
|
||||
led_set_brightness(0);
|
||||
}
|
||||
}
|
||||
|
||||
void remote_wake_som() {
|
||||
uart_puts(UART_ID, "\r\n1w\r\n");
|
||||
anim_hello();
|
||||
void reset_keyboard_state(void) {
|
||||
for (int i = 0; i < KBD_COLS*KBD_ROWS; i++) {
|
||||
matrix_debounce[i] = 0;
|
||||
matrix_state[i] = 0;
|
||||
}
|
||||
last_meta_key = 0;
|
||||
reset_menu();
|
||||
}
|
||||
|
||||
int process_keyboard(uint8_t* resulting_scancodes) {
|
||||
|
|
@ -450,17 +355,10 @@ int process_keyboard(uint8_t* resulting_scancodes) {
|
|||
if (debounced_pressed) {
|
||||
total_pressed++;
|
||||
|
||||
// Is circle key pressed?
|
||||
// FIXME HACK
|
||||
|
||||
if (keycode == KEY_ENTER && fn_key && !command_sent) {
|
||||
if (!soc_power_on) {
|
||||
remote_turn_on_som();
|
||||
command_sent = 1;
|
||||
//anim_hello();
|
||||
} else {
|
||||
remote_turn_off_som();
|
||||
command_sent = 1;
|
||||
// hyper + enter? open OLED menu
|
||||
if (keycode == KEY_ENTER && fn_key) {
|
||||
if (!active_meta_mode && !last_meta_key) {
|
||||
enter_meta_mode();
|
||||
}
|
||||
} else if (keycode == KEY_F12) {
|
||||
remote_wake_som();
|
||||
|
|
@ -472,19 +370,19 @@ int process_keyboard(uint8_t* resulting_scancodes) {
|
|||
// not holding the same key?
|
||||
if (last_meta_key != keycode) {
|
||||
// hyper/circle/menu functions
|
||||
int stay_meta = 0; //execute_meta_function(keycode);
|
||||
int stay_meta = execute_meta_function(keycode);
|
||||
// don't repeat action while key is held down
|
||||
last_meta_key = keycode;
|
||||
|
||||
// exit meta mode
|
||||
if (!stay_meta) {
|
||||
active_meta_mode = 0;
|
||||
exit_meta_mode();
|
||||
}
|
||||
|
||||
// after wake-up from sleep mode, skip further keymap processing
|
||||
if (stay_meta == 2) {
|
||||
//reset_keyboard_state();
|
||||
//enter_meta_mode();
|
||||
reset_keyboard_state();
|
||||
enter_meta_mode();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -499,7 +397,6 @@ int process_keyboard(uint8_t* resulting_scancodes) {
|
|||
} else {
|
||||
// key not pressed
|
||||
if (keycode == KEY_COMPOSE) {
|
||||
command_sent = 0;
|
||||
fn_key = 0;
|
||||
active_matrix = matrix;
|
||||
}
|
||||
|
|
@ -518,75 +415,84 @@ int prev_buttons = 0;
|
|||
int scroll_toggle = 0;
|
||||
int prev_num_keys = 0;
|
||||
|
||||
int8_t tb_nx = 0;
|
||||
int8_t tb_ny = 0;
|
||||
int tb_btn1 = 0;
|
||||
int tb_btn2 = 0;
|
||||
int tb_btn3 = 0;
|
||||
int tb_btn4 = 0;
|
||||
|
||||
// returns motion yes/no
|
||||
static int poll_trackball()
|
||||
{
|
||||
tb_btn3 = matrix_state[KBD_COLS*5+3]>0;
|
||||
tb_btn1 = matrix_state[KBD_COLS*5+4]>0;
|
||||
tb_btn2 = matrix_state[KBD_COLS*5+7]>0;
|
||||
tb_btn4 = matrix_state[KBD_COLS*5+8]>0;
|
||||
|
||||
uint8_t buf[] = {0x7f, 0x00, 0x00, 0x00};
|
||||
|
||||
buf[0] = 0x02;
|
||||
|
||||
i2c_write_blocking_until(i2c0, ADDR_SENSOR, buf, 1, true, make_timeout_time_ms(2));
|
||||
i2c_read_blocking_until(i2c0, ADDR_SENSOR, buf, 1, false, make_timeout_time_ms(2));
|
||||
|
||||
if (buf[0] & 0xf0) {
|
||||
buf[0] = 0x03;
|
||||
i2c_write_blocking_until(i2c0, ADDR_SENSOR, buf, 1, true, make_timeout_time_ms(2));
|
||||
i2c_read_blocking_until(i2c0, ADDR_SENSOR, buf, 2, false, make_timeout_time_ms(2));
|
||||
|
||||
tb_nx = (int8_t)buf[0];
|
||||
tb_ny = (int8_t)buf[1];
|
||||
|
||||
// HACK hue/value wheel
|
||||
if (matrix_state[KBD_COLS*4+0]) {
|
||||
if (tb_ny) {
|
||||
// shift held? saturation
|
||||
if (matrix_state[KBD_COLS*3+0]) {
|
||||
led_mod_saturation(tb_ny);
|
||||
} else {
|
||||
led_mod_brightness(tb_ny);
|
||||
}
|
||||
}
|
||||
if (tb_nx) {
|
||||
led_mod_hue(tb_nx);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_hid_report(uint8_t report_id)
|
||||
{
|
||||
// skip if hid is not ready yet
|
||||
if ( !tud_hid_ready() ) return;
|
||||
if (!tud_hid_ready()) return;
|
||||
|
||||
switch (report_id) {
|
||||
case REPORT_ID_KEYBOARD:
|
||||
{
|
||||
//int num_keys = process_keyboard(pressed_scancodes);
|
||||
|
||||
//if (num_keys > 0) {
|
||||
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, pressed_scancodes);
|
||||
//} else {
|
||||
// send empty key report if previously has key pressed
|
||||
//if (prev_num_keys) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL);
|
||||
//}
|
||||
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, pressed_scancodes);
|
||||
prev_num_keys = pressed_keys;
|
||||
}
|
||||
break;
|
||||
|
||||
case REPORT_ID_MOUSE:
|
||||
{
|
||||
uint8_t buf[] = {0x7f, 0x00, 0x00, 0x00};
|
||||
|
||||
buf[0] = 0x02;
|
||||
|
||||
i2c_write_blocking_until(i2c0, ADDR_SENSOR, buf, 1, true, make_timeout_time_ms(2));
|
||||
i2c_read_blocking_until(i2c0, ADDR_SENSOR, buf, 1, false, make_timeout_time_ms(2));
|
||||
//i2c_write_blocking(i2c0, ADDR_SENSOR, buf, 1, true);
|
||||
//i2c_read_blocking(i2c0, ADDR_SENSOR, buf, 1, false);
|
||||
|
||||
int btn3 = matrix_state[KBD_COLS*5+3]>0;
|
||||
int btn1 = matrix_state[KBD_COLS*5+4]>0;
|
||||
int btn2 = matrix_state[KBD_COLS*5+7]>0;
|
||||
int btn4 = matrix_state[KBD_COLS*5+8]>0;
|
||||
|
||||
int buttons = btn1 | (btn2<<1) | (btn4<<2);
|
||||
|
||||
if (buf[0] & 0xf0) {
|
||||
buf[0] = 0x03;
|
||||
//i2c_write_blocking(i2c0, ADDR_SENSOR, buf, 1, true);
|
||||
//i2c_read_blocking(i2c0, ADDR_SENSOR, buf, 2, false);
|
||||
i2c_write_blocking_until(i2c0, ADDR_SENSOR, buf, 1, true, make_timeout_time_ms(2));
|
||||
i2c_read_blocking_until(i2c0, ADDR_SENSOR, buf, 2, false, make_timeout_time_ms(2));
|
||||
|
||||
int8_t nx = (int8_t)buf[0];
|
||||
int8_t ny = (int8_t)buf[1];
|
||||
int buttons = tb_btn1 | (tb_btn2<<1) | (tb_btn4<<2);
|
||||
int motion = poll_trackball();
|
||||
|
||||
if (motion) {
|
||||
// no button, right + down, no scroll pan
|
||||
if (btn3 || scroll_toggle) {
|
||||
tud_hid_mouse_report(REPORT_ID_MOUSE, (uint8_t)buttons, 0, 0, 2*ny, -2*nx);
|
||||
if (tb_btn3 || scroll_toggle) {
|
||||
tud_hid_mouse_report(REPORT_ID_MOUSE, (uint8_t)buttons, 0, 0, 2*tb_ny, -2*tb_nx);
|
||||
} else {
|
||||
tud_hid_mouse_report(REPORT_ID_MOUSE, (uint8_t)buttons, -2*nx, -2*ny, 0, 0);
|
||||
}
|
||||
|
||||
// HACK hue/value wheel
|
||||
if (matrix_state[KBD_COLS*4+0]) {
|
||||
if (ny) {
|
||||
led_mod_brightness(ny);
|
||||
}
|
||||
if (nx) {
|
||||
led_mod_hue(nx);
|
||||
}
|
||||
tud_hid_mouse_report(REPORT_ID_MOUSE, (uint8_t)buttons, -2*tb_nx, -2*tb_ny, 0, 0);
|
||||
}
|
||||
|
||||
} else {
|
||||
//if (buttons != prev_buttons) {
|
||||
tud_hid_mouse_report(REPORT_ID_MOUSE, (uint8_t)buttons, 0, 0, 0, 0);
|
||||
//}
|
||||
tud_hid_mouse_report(REPORT_ID_MOUSE, (uint8_t)buttons, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
prev_buttons = buttons;
|
||||
|
|
@ -616,29 +522,7 @@ static void send_hid_report(uint8_t report_id)
|
|||
|
||||
case REPORT_ID_GAMEPAD:
|
||||
{
|
||||
// use to avoid send multiple consecutive zero report for keyboard
|
||||
/*static bool has_gamepad_key = false;
|
||||
|
||||
hid_gamepad_report_t report =
|
||||
{
|
||||
.x = 0, .y = 0, .z = 0, .rz = 0, .rx = 0, .ry = 0,
|
||||
.hat = 0, .buttons = 0
|
||||
};
|
||||
|
||||
if ( btn )
|
||||
{
|
||||
report.hat = GAMEPAD_HAT_UP;
|
||||
report.buttons = GAMEPAD_BUTTON_A;
|
||||
tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report));
|
||||
|
||||
has_gamepad_key = true;
|
||||
}else
|
||||
{
|
||||
report.hat = GAMEPAD_HAT_CENTERED;
|
||||
report.buttons = 0;
|
||||
if (has_gamepad_key) tud_hid_report(REPORT_ID_GAMEPAD, &report, sizeof(report));
|
||||
has_gamepad_key = false;
|
||||
}*/
|
||||
// TODO: later
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -687,6 +571,9 @@ void led_bitmap(uint8_t row, const uint8_t* row_rgb) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int hid_task_counter = 0;
|
||||
|
||||
// Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..)
|
||||
// tud_hid_report_complete_cb() is used to send the next report after previous one is complete
|
||||
void hid_task(void)
|
||||
|
|
@ -695,11 +582,21 @@ void hid_task(void)
|
|||
const uint32_t interval_ms = 10;
|
||||
static uint32_t start_ms = 0;
|
||||
|
||||
if ( board_millis() - start_ms < interval_ms) return; // not enough time
|
||||
if (board_millis() - start_ms < interval_ms) {
|
||||
// not enough time passed
|
||||
return;
|
||||
}
|
||||
start_ms += interval_ms;
|
||||
|
||||
// allow trackball backlight control even if there's no USB yet
|
||||
if (hid_task_counter%10 == 0) {
|
||||
if (tud_suspended() && remote_get_power_state()) {
|
||||
poll_trackball();
|
||||
}
|
||||
}
|
||||
|
||||
// Remote wakeup
|
||||
if ( tud_suspended() && pressed_keycodes[0] )
|
||||
if (tud_suspended() && pressed_keys > 0)
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
|
|
@ -708,9 +605,15 @@ void hid_task(void)
|
|||
// Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb()
|
||||
send_hid_report(REPORT_ID_KEYBOARD);
|
||||
}
|
||||
|
||||
hid_task_counter++;
|
||||
if (hid_task_counter%100 == 0) {
|
||||
refresh_menu_page();
|
||||
}
|
||||
}
|
||||
|
||||
int led_brightness = 0;
|
||||
int led_saturation = 255;
|
||||
int led_hue = 127;
|
||||
|
||||
typedef struct RgbColor
|
||||
|
|
@ -780,7 +683,7 @@ void led_set_hsv() {
|
|||
HsvColor hsv;
|
||||
RgbColor rgb;
|
||||
hsv.h = (unsigned char)led_hue;
|
||||
hsv.s = 0xff;
|
||||
hsv.s = (unsigned char)led_saturation;
|
||||
hsv.v = (unsigned char)led_brightness;
|
||||
|
||||
rgb = HsvToRgb(hsv);
|
||||
|
|
@ -801,6 +704,17 @@ void led_mod_hue(int d) {
|
|||
led_set_hsv();
|
||||
}
|
||||
|
||||
void led_mod_saturation(int d) {
|
||||
led_saturation+=d;
|
||||
if (led_saturation>0xff) led_saturation = 0xff;
|
||||
if (led_saturation<0) led_saturation = 0;
|
||||
led_set_hsv();
|
||||
}
|
||||
|
||||
void led_set_saturation(int s) {
|
||||
led_saturation = s;
|
||||
}
|
||||
|
||||
void led_set_brightness(int b) {
|
||||
led_brightness = b;
|
||||
led_set_hsv();
|
||||
|
|
@ -812,7 +726,6 @@ void led_cycle_hue() {
|
|||
led_set_hsv();
|
||||
}
|
||||
|
||||
|
||||
// Invoked when sent REPORT successfully to host
|
||||
// Application can use this to send the next report
|
||||
// Note: For composite reports, report[0] is report ID
|
||||
|
|
@ -928,7 +841,8 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
|
|||
led_task(pixel_grb);
|
||||
}
|
||||
else if (cmd == strnstr(cmd, CMD_LOGO, 4)) {
|
||||
anim_hello();
|
||||
// FIXME
|
||||
//anim_hello();
|
||||
}
|
||||
else if (cmd == strnstr(cmd, CMD_OLED_BRITE, 4)) {
|
||||
uint8_t val = (uint8_t)atoi((const char*)&buffer[4]);
|
||||
|
|
@ -959,5 +873,5 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
|
|||
|
||||
//uint8_t const kbd_leds = buffer[0];
|
||||
}
|
||||
}*/
|
||||
}*/
|
||||
}
|
||||
|
|
|
|||
222
pocket-reform-keyboard-fw/pocket-hid/src/menu.c
Normal file
222
pocket-reform-keyboard-fw/pocket-hid/src/menu.c
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
MNT Reform 2.0 Keyboard Firmware
|
||||
See keyboard.c for Copyright
|
||||
SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
//#include "backlight.h"
|
||||
//#include "keyboard.h"
|
||||
#include "menu.h"
|
||||
#include "oled.h"
|
||||
#include "remote.h"
|
||||
#include "usb_hid_keys.h"
|
||||
#include "keyboard.h"
|
||||
#include "pico/stdlib.h"
|
||||
//#include "scancodes.h"
|
||||
|
||||
int current_menu_y = 0;
|
||||
int current_scroll_y = 0;
|
||||
int current_menu_page = 0;
|
||||
int8_t logo_timeout_ticks = 0;
|
||||
|
||||
#ifdef KBD_MODE_STANDALONE
|
||||
#define MENU_NUM_ITEMS 5
|
||||
const MenuItem menu_items[] = {
|
||||
{ "Exit Menu ESC", KEY_ESC },
|
||||
{ "Key Backlight- F1", KEY_F1 },
|
||||
{ "Key Backlight+ F2", KEY_F2 },
|
||||
{ "System Status s", KEY_S },
|
||||
{ "USB Flashing Mode x", KEY_X },
|
||||
};
|
||||
#else
|
||||
#define MENU_NUM_ITEMS 7
|
||||
const MenuItem menu_items[] = {
|
||||
{ "Exit Menu ESC", KEY_ESC },
|
||||
{ "Power On 1", KEY_1 },
|
||||
{ "Power Off 0", KEY_0 },
|
||||
{ "Reset r", KEY_R },
|
||||
{ "Battery Status b", KEY_B },
|
||||
{ "Wake SPC", KEY_SPACE },
|
||||
{ "System Status s", KEY_S },
|
||||
|
||||
// Only needed for debugging.
|
||||
// The keyboard will go to sleep when turning off
|
||||
// main system power.
|
||||
{ "KBD Power-Off p", KEY_P },
|
||||
};
|
||||
#endif
|
||||
|
||||
void reset_menu() {
|
||||
current_scroll_y = 0;
|
||||
current_menu_y = 0;
|
||||
current_menu_page = MENU_PAGE_NONE;
|
||||
gfx_clear();
|
||||
gfx_flush();
|
||||
}
|
||||
|
||||
void reset_and_render_menu() {
|
||||
reset_menu();
|
||||
render_menu(current_scroll_y);
|
||||
}
|
||||
|
||||
void render_menu(int y) {
|
||||
gfx_clear();
|
||||
gfx_invert_row((uint8_t)(current_menu_y-y));
|
||||
for (int i=0; i<MENU_NUM_ITEMS; i++) {
|
||||
gfx_poke_cstr(0,(uint8_t)(i-y),menu_items[i].title);
|
||||
}
|
||||
gfx_on();
|
||||
gfx_flush();
|
||||
}
|
||||
|
||||
// automatically refresh the current menu page if needed
|
||||
void refresh_menu_page() {
|
||||
if (current_menu_page == MENU_PAGE_BATTERY_STATUS) {
|
||||
remote_get_voltages();
|
||||
} else if (current_menu_page == MENU_PAGE_MNT_LOGO && --logo_timeout_ticks <= 0) {
|
||||
reset_menu();
|
||||
}
|
||||
}
|
||||
|
||||
int execute_menu_function(int y) {
|
||||
current_menu_page = MENU_PAGE_NONE;
|
||||
|
||||
if (y>=0 && y<MENU_NUM_ITEMS) {
|
||||
current_menu_page = MENU_PAGE_OTHER;
|
||||
return execute_meta_function(menu_items[y].keycode);
|
||||
}
|
||||
return execute_meta_function(KEY_ESC);
|
||||
}
|
||||
|
||||
// returns 1 for navigation function (stay in meta mode), 0 for terminal function
|
||||
int execute_meta_function(int keycode) {
|
||||
if (keycode == KEY_0) {
|
||||
// TODO: are you sure?
|
||||
anim_goodbye();
|
||||
remote_turn_off_som();
|
||||
//keyboard_power_off();
|
||||
reset_keyboard_state();
|
||||
// Directly enter menu again
|
||||
return 2;
|
||||
}
|
||||
else if (keycode == KEY_1) {
|
||||
//kbd_brightness_init();
|
||||
if (remote_turn_on_som()) {
|
||||
anim_hello();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (keycode == KEY_R) {
|
||||
// TODO: are you sure?
|
||||
//remote_reset_som();
|
||||
}
|
||||
else if (keycode == KEY_SPACE) {
|
||||
remote_wake_som();
|
||||
}
|
||||
else if (keycode == KEY_B) {
|
||||
current_menu_page = MENU_PAGE_BATTERY_STATUS;
|
||||
remote_get_voltages();
|
||||
return 0;
|
||||
}
|
||||
else if (keycode == KEY_S) {
|
||||
remote_get_status();
|
||||
return 0;
|
||||
}
|
||||
else if (keycode == KEY_F1) {
|
||||
//kbd_brightness_dec();
|
||||
return 1;
|
||||
}
|
||||
else if (keycode == KEY_F2) {
|
||||
//kbd_brightness_inc();
|
||||
return 1;
|
||||
}
|
||||
else if (keycode == KEY_UP) {
|
||||
current_menu_y--;
|
||||
if (current_menu_y<0) current_menu_y = 0;
|
||||
if (current_menu_y<=current_scroll_y) current_scroll_y--;
|
||||
if (current_scroll_y<0) current_scroll_y = 0;
|
||||
render_menu(current_scroll_y);
|
||||
return 1;
|
||||
}
|
||||
else if (keycode == KEY_DOWN) {
|
||||
current_menu_y++;
|
||||
if (current_menu_y>=MENU_NUM_ITEMS) current_menu_y = MENU_NUM_ITEMS-1;
|
||||
if (current_menu_y>=current_scroll_y+3) current_scroll_y++;
|
||||
render_menu(current_scroll_y);
|
||||
return 1;
|
||||
}
|
||||
else if (keycode == KEY_ENTER) {
|
||||
return execute_menu_function(current_menu_y);
|
||||
}
|
||||
else if (keycode == KEY_ESC) {
|
||||
gfx_clear();
|
||||
gfx_flush();
|
||||
}
|
||||
/*else if (keycode == KEY_X) {
|
||||
gfx_clear();
|
||||
gfx_poke_str(1, 1, "Entered firmware");
|
||||
gfx_poke_str(1, 2, "update mode.");
|
||||
gfx_on();
|
||||
gfx_flush();
|
||||
jump_to_bootloader();
|
||||
}*/
|
||||
else if (keycode == KEY_L) {
|
||||
anim_hello();
|
||||
return 0;
|
||||
}
|
||||
|
||||
gfx_clear();
|
||||
gfx_flush();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void anim_hello(void) {
|
||||
current_menu_page = MENU_PAGE_MNT_LOGO;
|
||||
logo_timeout_ticks = 10; // ~30sec
|
||||
gfx_clear();
|
||||
//kbd_brightness_set(0);
|
||||
gfx_on();
|
||||
for (uint8_t y=0; y<3; y++) {
|
||||
for (uint8_t x=0; x<12; x++) {
|
||||
gfx_poke(x+4,y+1,(uint8_t)((5+y)*32+x));
|
||||
}
|
||||
gfx_flush();
|
||||
}
|
||||
for (uint8_t y=0; y<0xff; y++) {
|
||||
/*if ((y % 32) == 0) {
|
||||
kbd_brightness_inc();
|
||||
}*/
|
||||
gfx_contrast(y);
|
||||
sleep_ms(0);
|
||||
}
|
||||
for (uint8_t y=0; y<0xff; y++) {
|
||||
/*if ((y % 64) == 0) {
|
||||
kbd_brightness_dec();
|
||||
}*/
|
||||
gfx_contrast(0xff-y);
|
||||
sleep_ms(0);
|
||||
}
|
||||
}
|
||||
|
||||
void anim_goodbye(void) {
|
||||
gfx_clear();
|
||||
gfx_on();
|
||||
for (uint8_t y=0; y<3; y++) {
|
||||
for (uint8_t x=0; x<12; x++) {
|
||||
gfx_poke(x+4,y+1,(uint8_t)((5+y)*32+x));
|
||||
}
|
||||
}
|
||||
for (uint8_t y=0; y<3; y++) {
|
||||
for (uint8_t x=0; x<12; x++) {
|
||||
gfx_poke(x+4,y+1,' ');
|
||||
}
|
||||
gfx_flush();
|
||||
}
|
||||
//int16_t brt = kbd_brightness_get();
|
||||
/*while (brt--) {
|
||||
kbd_brightness_dec();
|
||||
Delay_MS(64);
|
||||
}*/
|
||||
gfx_off();
|
||||
}
|
||||
29
pocket-reform-keyboard-fw/pocket-hid/src/menu.h
Normal file
29
pocket-reform-keyboard-fw/pocket-hid/src/menu.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
MNT Reform 2.0 Keyboard Firmware
|
||||
See keyboard.c for Copyright
|
||||
SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef _MENU_H_
|
||||
#define _MENU_H_
|
||||
|
||||
typedef struct MenuItem {
|
||||
const char* title;
|
||||
int keycode;
|
||||
} MenuItem;
|
||||
|
||||
#define MENU_PAGE_NONE 0
|
||||
#define MENU_PAGE_OTHER 1
|
||||
#define MENU_PAGE_BATTERY_STATUS 2
|
||||
#define MENU_PAGE_MNT_LOGO 3
|
||||
|
||||
void reset_and_render_menu(void);
|
||||
void reset_menu(void);
|
||||
void render_menu(int y);
|
||||
void refresh_menu_page(void);
|
||||
int execute_menu_function(int y);
|
||||
int execute_meta_function(int keycode);
|
||||
void anim_hello(void);
|
||||
void anim_goodbye(void);
|
||||
|
||||
#endif
|
||||
242
pocket-reform-keyboard-fw/pocket-hid/src/remote.c
Normal file
242
pocket-reform-keyboard-fw/pocket-hid/src/remote.c
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
MNT Reform 2.0 Keyboard Firmware
|
||||
See keyboard.c for Copyright
|
||||
SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "remote.h"
|
||||
#include "oled.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
#include "bsp/board_api.h"
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#define UART_ID uart1
|
||||
|
||||
// received by uart
|
||||
#define RESPONSE_MAX 128
|
||||
static char response[RESPONSE_MAX];
|
||||
static int uart_rx_i = 0;
|
||||
static int uart_print_response = 0;
|
||||
static int uart_response_complete = 0;
|
||||
|
||||
uint8_t term_x = 0;
|
||||
uint8_t term_y = 0;
|
||||
double voltages[8];
|
||||
int alert_low_battery = 0;
|
||||
int alert_blink = 0;
|
||||
uint8_t remote_som_power_expected_state = 0;
|
||||
|
||||
int command_sent = 0;
|
||||
int soc_power_on = 0; // fixme
|
||||
|
||||
void insert_bat_icon(char* str, int x, double v) {
|
||||
char icon = 0;
|
||||
if (v>=3.3) {
|
||||
icon = 8;
|
||||
} else if (v>=3.1) {
|
||||
icon = 6;
|
||||
} else if (v>=3.0) {
|
||||
icon = 4;
|
||||
} else if (v>=2.9) {
|
||||
icon = 2;
|
||||
} else {
|
||||
icon = 0;
|
||||
}
|
||||
str[x] = 4*32+icon;
|
||||
str[x+1] = 4*32+icon+1;
|
||||
}
|
||||
|
||||
int remote_turn_on_som() {
|
||||
uart_puts(UART_ID, "1p\r\n");
|
||||
//led_set_brightness(10);
|
||||
soc_power_on = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remote_turn_off_som() {
|
||||
uart_puts(UART_ID, "0p\r\n");
|
||||
//led_set_brightness(0);
|
||||
soc_power_on = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remote_wake_som() {
|
||||
uart_puts(UART_ID, "1w\r\n");
|
||||
//anim_hello();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remote_get_power_state() {
|
||||
return soc_power_on;
|
||||
}
|
||||
|
||||
void remote_on_uart_rx() {
|
||||
while (uart_is_readable(UART_ID)) {
|
||||
char c = uart_getc(UART_ID);
|
||||
if (uart_rx_i < RESPONSE_MAX-1) {
|
||||
response[uart_rx_i++] = c;
|
||||
response[uart_rx_i] = 0;
|
||||
} else {
|
||||
uart_rx_i = 0;
|
||||
}
|
||||
|
||||
uint8_t poke_chr = c;
|
||||
|
||||
if (c == '\n') {
|
||||
// TODO hack
|
||||
|
||||
/*if (uart_rx_i>6) {
|
||||
gfx_clear();
|
||||
//gfx_poke_str(0, 3, uart_rx_line);
|
||||
// cut off after 4 digits
|
||||
uart_rx_line[4] = 0;
|
||||
float percentage = ((float)atoi(uart_rx_line))/(float)10.0;
|
||||
|
||||
char batinfo[32];
|
||||
sprintf(batinfo, " %.1f%%", (double)percentage);
|
||||
insert_bat_icon(batinfo, 0, percentage);
|
||||
gfx_poke_str(7, 1, batinfo);
|
||||
gfx_flush();
|
||||
}*/
|
||||
|
||||
uart_rx_i = 0;
|
||||
poke_chr=' ';
|
||||
}
|
||||
|
||||
if (c!='\r') {
|
||||
if (uart_print_response) {
|
||||
gfx_poke(term_x,term_y,poke_chr);
|
||||
gfx_poke(term_x+1,term_y,' ');
|
||||
term_x++;
|
||||
if (term_x>=20) {
|
||||
term_x=0;
|
||||
term_y++;
|
||||
if (term_y>=3) {
|
||||
term_y=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uart_response_complete = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int remote_try_command(const char* cmd, int print_response) {
|
||||
int ok = 1;
|
||||
|
||||
memset(response, 0, RESPONSE_MAX);
|
||||
uart_rx_i = 0;
|
||||
uart_response_complete = 0;
|
||||
uart_print_response = print_response;
|
||||
if (print_response) {
|
||||
term_x = 0;
|
||||
term_y = 0;
|
||||
}
|
||||
uart_puts(UART_ID, cmd);
|
||||
|
||||
int timeout = 0;
|
||||
while (!uart_response_complete) {
|
||||
sleep_ms(10);
|
||||
timeout++;
|
||||
if (timeout > 10) {
|
||||
gfx_poke(0,0,'T');
|
||||
gfx_flush();
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (print_response) {
|
||||
gfx_flush();
|
||||
};
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int remote_get_status(void) {
|
||||
gfx_clear();
|
||||
|
||||
gfx_poke_cstr(0, 2, "MNT Pocket Reform HID");
|
||||
gfx_poke_cstr(0, 3, PREF_HID_FW_REV);
|
||||
gfx_on();
|
||||
gfx_flush();
|
||||
|
||||
int ok = remote_try_command("s\r", 1);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int remote_get_voltages(void) {
|
||||
term_x = 0;
|
||||
term_y = 0;
|
||||
|
||||
double bat_volts = 0;
|
||||
double bat_amps = 0;
|
||||
char bat_gauge[5] = {0,0,0,0,0};
|
||||
|
||||
int ok = remote_try_command("c\r", 0);
|
||||
if (!ok) return ok;
|
||||
|
||||
// lpc format: 32 32 32 32 32 32 32 32 mA 0256mV26143 ???% P1
|
||||
// | | | | | | | | | | | | |
|
||||
// 0 3 6 9 12 15 18 21 24| | | |
|
||||
// 26 33 39 44
|
||||
// |
|
||||
// `- can be a minus
|
||||
double sum_volts = 0;
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
voltages[i] = ((double)((response[i*3]-'0')*10 + (response[i*3+1]-'0')))/10.0;
|
||||
if (voltages[i]<0) voltages[i]=0;
|
||||
if (voltages[i]>=10) voltages[i]=9.9;
|
||||
sum_volts += voltages[i];
|
||||
}
|
||||
|
||||
int amps_offset = 3*8+2;
|
||||
// cut off string
|
||||
response[amps_offset+5]=0;
|
||||
bat_amps = ((double)atoi(&response[amps_offset]))/1000.0;
|
||||
int volts_offset = amps_offset+5+2;
|
||||
response[volts_offset+5]=0;
|
||||
bat_volts = ((double)atoi(&response[volts_offset]))/1000.0;
|
||||
int gauge_offset = volts_offset+5+1;
|
||||
strncpy(bat_gauge, &response[gauge_offset], 4);
|
||||
|
||||
const char* power_str = " ";
|
||||
int syspower_offset = gauge_offset+5;
|
||||
char power_digit = response[syspower_offset+1];
|
||||
if (power_digit == '1') {
|
||||
power_str = " On";
|
||||
soc_power_on = 1;
|
||||
} else if (power_digit == '0') {
|
||||
power_str = "Off";
|
||||
soc_power_on = 0;
|
||||
}
|
||||
|
||||
// plot
|
||||
gfx_clear();
|
||||
char str[32];
|
||||
|
||||
sprintf(str,"[] %.1f %s",voltages[0],bat_gauge);
|
||||
insert_bat_icon(str,0,voltages[0]);
|
||||
gfx_poke_str(0,0,str);
|
||||
|
||||
sprintf(str,"[] %.1f %s",voltages[1],power_str);
|
||||
insert_bat_icon(str,0,voltages[1]);
|
||||
gfx_poke_str(0,1,str);
|
||||
|
||||
if (bat_amps>=0) {
|
||||
sprintf(str," %2.3fA",bat_amps);
|
||||
} else {
|
||||
sprintf(str," %2.2fA",bat_amps);
|
||||
}
|
||||
gfx_poke_str(0,2,str);
|
||||
|
||||
sprintf(str," %2.2fV",bat_volts);
|
||||
gfx_poke_str(0,3,str);
|
||||
gfx_flush();
|
||||
|
||||
return ok;
|
||||
}
|
||||
30
pocket-reform-keyboard-fw/pocket-hid/src/remote.h
Normal file
30
pocket-reform-keyboard-fw/pocket-hid/src/remote.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
MNT Reform 2.0 Keyboard Firmware
|
||||
See keyboard.c for Copyright
|
||||
SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef _REMOTE_H_
|
||||
#define _REMOTE_H_
|
||||
|
||||
void insert_bat_icon(char* str, int x, double v);
|
||||
void empty_serial(void);
|
||||
int remote_receive_string(int print);
|
||||
int remote_try_wakeup(void);
|
||||
int remote_try_command(const char* cmd, int print_response);
|
||||
int remote_get_voltages(void);
|
||||
int remote_check_for_low_battery(void);
|
||||
int remote_get_status(void);
|
||||
int remote_turn_on_som(void);
|
||||
int remote_turn_off_som(void);
|
||||
int remote_reset_som(void);
|
||||
int remote_wake_som(void);
|
||||
int remote_report_voltages(void);
|
||||
int remote_enable_som_uart(void);
|
||||
int remote_disable_som_uart(void);
|
||||
void remote_process_alerts(void);
|
||||
void remote_init(void);
|
||||
void remote_on_uart_rx(void);
|
||||
int remote_get_power_state(void);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue