pocket-hid: add backlight control commands etc
This commit is contained in:
parent
6270add22f
commit
5c381dbd63
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
gcc -O2 -o kbdgfx ./kbdgfx.c -lm
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
kbdgfx.c -- Demo for drawing realtime graphics to the MNT Reform Keyboard
|
||||
Copyright 2022 MNT Research GmbH (https://mntre.com)
|
||||
License: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define ROWS 6
|
||||
#define COLS 12
|
||||
#define BUFSZ (6+COLS*3)
|
||||
#define FBUFSZ COLS*ROWS*3
|
||||
|
||||
// our unpacked, wasteful framebuffer (3 bytes per pixel)
|
||||
uint8_t fb[FBUFSZ];
|
||||
// the buffer we send over HID
|
||||
uint8_t buf[BUFSZ];
|
||||
|
||||
void draw_sine(float t, uint8_t* dst, uint8_t r, uint8_t g, uint8_t b, float brite) {
|
||||
for (int x=0; x<COLS; x++) {
|
||||
float fy = 2.5 + sin(t + ((float)x/12.0 * 3.141))*2;
|
||||
for (int y=0; y<ROWS; y++) {
|
||||
float d = 1.0 / (10.0 * (abs((float)y - fy)));
|
||||
if (d > 1) d = 1;
|
||||
|
||||
dst[3*(y*COLS + x)] |= (uint8_t)(r * d * brite);
|
||||
dst[3*(y*COLS + x)+1] |= (uint8_t)(g * d * brite);
|
||||
dst[3*(y*COLS + x)+2] |= (uint8_t)(b * d * brite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_box(uint8_t* dst, uint8_t r, uint8_t g, uint8_t b, float brite) {
|
||||
for (int x=0; x<COLS; x++) {
|
||||
for (int y=0; y<ROWS; y++) {
|
||||
dst[3*(y*COLS + x)] |= (uint8_t)(r * brite);
|
||||
dst[3*(y*COLS + x)+1] |= (uint8_t)(g * brite);
|
||||
dst[3*(y*COLS + x)+2] |= (uint8_t)(b * brite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// just a counter
|
||||
uint32_t t = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: sudo kbdgfx /dev/hidraw0 [bitmap.raw]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// loop forever
|
||||
while (1) {
|
||||
|
||||
// start with the command
|
||||
buf[0] = 'x';
|
||||
buf[1] = 'X';
|
||||
buf[2] = 'R';
|
||||
buf[3] = 'G';
|
||||
buf[4] = 'B';
|
||||
|
||||
// clear
|
||||
memset(fb, 0, FBUFSZ);
|
||||
|
||||
if (argc == 3) {
|
||||
// read bitmap from file
|
||||
FILE* bmf = fopen(argv[2],"r");
|
||||
if (!bmf) {
|
||||
printf("Couldn't open bitmap %s!\n", argv[2]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int res = fread(fb, FBUFSZ, 1, bmf);
|
||||
fclose(bmf);
|
||||
|
||||
if (res<1) {
|
||||
printf("Couldn't read bitmap or wrong size.\n", argv[2]);
|
||||
exit(3);
|
||||
}
|
||||
} else {
|
||||
// graphics demo
|
||||
|
||||
// paint
|
||||
//draw_sine((float)t*0.03, fb);
|
||||
if (t>500) {
|
||||
draw_sine((float)t*0.025+1.0, fb, 0xff, 0x00, 0x00, fmaxf(0.0, fminf(1.0, (700-((float)t/1.6))/200.0)));
|
||||
draw_sine((float)t*0.025, fb, 0x00, 0x00, 0xff, fmaxf(0.0, fminf(1.0, (700-((float)t/1.5))/200.0)));
|
||||
draw_sine((float)t*0.025-1.0, fb, 0x00, 0xff, 0x00, fmaxf(0.0, fminf(1.0, (700-((float)t/1.2))/200.0)));
|
||||
|
||||
if (t>700) {
|
||||
draw_box(fb, 0xff, 0xff, 0xff, fmaxf(0.0, fminf(1.0, (((float)t/1.5)-500.0)/200.0)));
|
||||
}
|
||||
} else {
|
||||
draw_sine((float)t*0.025+1.0, fb, 0xff, 0x00, 0x00, fmaxf(0.0, fminf(1.0, (((float)t)-100)/200.0)));
|
||||
draw_sine((float)t*0.025, fb, 0x00, 0x00, 0xff, fmaxf(0.0, fminf(1.0, (((float)t/1.2)-200)/200.0)));
|
||||
draw_sine((float)t*0.025-1.0, fb, 0x00, 0xff, 0x00, fmaxf(0.0, fminf(1.0, (((float)t/1.1)-300)/200.0)));
|
||||
}
|
||||
}
|
||||
|
||||
// send our buffer to the keyboard, one line at a time
|
||||
|
||||
for (int row = 0; row < 6; row++) {
|
||||
FILE* f = fopen(argv[1],"w");
|
||||
if (!f) {
|
||||
printf("Couldn't open %s. Try sudo.\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
buf[5] = row;
|
||||
memcpy(buf+6, fb+row*(COLS*3), COLS*3);
|
||||
fwrite(buf, BUFSZ, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
// if we're in bitmap file mode, exit now
|
||||
if (argc == 3) exit(0);
|
||||
|
||||
// ~50 FPS
|
||||
usleep(100*20);
|
||||
// ~2 FPS
|
||||
//usleep(1000*500);
|
||||
t++;
|
||||
}
|
||||
}
|
|
@ -141,7 +141,7 @@ void on_uart_rx() {
|
|||
char batinfo[32];
|
||||
sprintf(batinfo, " %.1f%%", (double)percentage);
|
||||
insert_bat_icon(batinfo, 0, percentage);
|
||||
gfx_poke_str(0, 0, batinfo);
|
||||
gfx_poke_str(7, 1, batinfo);
|
||||
gfx_flush();
|
||||
}
|
||||
uart_rx_i = 0;
|
||||
|
@ -255,7 +255,7 @@ int main(void)
|
|||
|
||||
ws2812_program_init(pio, sm, offset, PIN_LEDS, 800000, false);
|
||||
|
||||
led_set_brightness(0x80);
|
||||
led_set_brightness(0x0);
|
||||
|
||||
gfx_init(false);
|
||||
anim_hello();
|
||||
|
@ -350,6 +350,19 @@ 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;
|
||||
}
|
||||
|
||||
void remote_turn_off_som() {
|
||||
uart_puts(UART_ID, "\r\n0p\r\n");
|
||||
led_set_brightness(0);
|
||||
soc_power_on = 0;
|
||||
}
|
||||
|
||||
int process_keyboard(uint8_t* resulting_scancodes) {
|
||||
// how many keys are pressed this round
|
||||
|
@ -415,26 +428,18 @@ int process_keyboard(uint8_t* resulting_scancodes) {
|
|||
// Is circle key pressed?
|
||||
// FIXME HACK
|
||||
|
||||
if (keycode == KEY_COMPOSE &&
|
||||
( matrix_state[1]
|
||||
|| matrix_state[10]
|
||||
) && !command_sent) {
|
||||
if (matrix_state[1]) {
|
||||
// 1
|
||||
//remote_turn_som_power_on();
|
||||
uart_puts(UART_ID, "\r\n1p\r\n");
|
||||
led_set_brightness(10);
|
||||
if (keycode == KEY_POWER && !command_sent) {
|
||||
if (!soc_power_on) {
|
||||
remote_turn_on_som();
|
||||
command_sent = 1;
|
||||
//anim_hello();
|
||||
} else if (matrix_state[10]) {
|
||||
//remote_turn_som_power_off();
|
||||
led_set_brightness(0);
|
||||
uart_puts(UART_ID, "\r\n0p\r\n");
|
||||
} else {
|
||||
remote_turn_off_som();
|
||||
command_sent = 1;
|
||||
}
|
||||
} else if (keycode == HID_KEY_EXECUTE) {
|
||||
} else if (keycode == KEY_COMPOSE) {
|
||||
fn_key = 1;
|
||||
//active_matrix = matrix_fn;
|
||||
active_matrix = matrix_fn;
|
||||
} else {
|
||||
if (active_meta_mode) {
|
||||
// not holding the same key?
|
||||
|
@ -468,25 +473,8 @@ int process_keyboard(uint8_t* resulting_scancodes) {
|
|||
// key not pressed
|
||||
if (keycode == KEY_COMPOSE) {
|
||||
command_sent = 0;
|
||||
}
|
||||
else if (keycode == HID_KEY_EXECUTE) {
|
||||
fn_key = 0;
|
||||
if (media_toggle) {
|
||||
//active_matrix = matrix_fn_toggled;
|
||||
} else {
|
||||
//active_matrix = matrix;
|
||||
}
|
||||
} else if (keycode == KEY_SYSRQ) {
|
||||
if (fn_key && circle) {
|
||||
if (!media_toggle) {
|
||||
media_toggle = 1;
|
||||
//active_matrix = matrix_fn_toggled;
|
||||
} else {
|
||||
media_toggle = 0;
|
||||
//active_matrix = matrix_fn;
|
||||
}
|
||||
}
|
||||
circle = 0;
|
||||
active_matrix = matrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -652,6 +640,35 @@ void led_task(uint32_t color) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t led_rgb_buf[12*3*6];
|
||||
|
||||
void led_bitmap(uint8_t row, uint8_t* row_rgb) {
|
||||
// row = 5 -> commit
|
||||
if (row > 5) return;
|
||||
|
||||
uint8_t* store = &led_rgb_buf[row*3*12];
|
||||
int offset = 0;
|
||||
for (int x=0; x<3*12; x++) {
|
||||
if (row == 5 && x == 0*3) offset = 3*3;
|
||||
if (row == 5 && x == 2*3) offset = 7*3;
|
||||
store[x] = row_rgb[x+offset];
|
||||
if (row == 5 && x == 4*3) break;
|
||||
}
|
||||
|
||||
if (row == 5) {
|
||||
for (int y=0; y<6; y++) {
|
||||
int w = 12;
|
||||
if (y==5) w = 4;
|
||||
uint8_t* bitmap = &led_rgb_buf[y*3*12];
|
||||
for (int x=0; x<w; x++) {
|
||||
uint32_t pixel_grb = (bitmap[1]<<16u) | (bitmap[2]<<8u) | bitmap[0];
|
||||
pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
|
||||
bitmap+=3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -678,7 +695,7 @@ void hid_task(void)
|
|||
}
|
||||
|
||||
int led_brightness = 0;
|
||||
int led_hue = 0;
|
||||
int led_hue = 127;
|
||||
|
||||
typedef struct RgbColor
|
||||
{
|
||||
|
@ -811,6 +828,17 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
// hid commands are all 4-letter, so they fit in a 32 bit integer
|
||||
#define cmd(_s) (*(uint32_t *)(_s))
|
||||
#define CMD_TEXT_FRAME cmd("OLED") // fill the screen with a single wall of text
|
||||
#define CMD_OLED_CLEAR cmd("WCLR") // clear the oled display
|
||||
#define CMD_OLED_BITMAP cmd("WBIT") // (u16 offset, u8 bytes...) write raw bytes into the oled framebuffer
|
||||
#define CMD_POWER_OFF cmd("PWR0") // turn off power rails
|
||||
#define CMD_BACKLIGHT cmd("LITE") // keyboard backlight level
|
||||
#define CMD_RGB_BACKLIGHT cmd("LRGB") // keyboard backlight rgb
|
||||
#define CMD_RGB_BITMAP cmd("XRGB") // push rgb backlight bitmap
|
||||
#define CMD_LOGO cmd("LOGO") // play logo animation
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
||||
|
@ -818,7 +846,78 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
|
|||
(void) instance;
|
||||
(void) buffer;
|
||||
|
||||
if (report_type == HID_REPORT_TYPE_OUTPUT)
|
||||
char repinfo[64];
|
||||
|
||||
//sprintf(repinfo, "Rep: %d/%d ", report_type, report_id);
|
||||
//gfx_poke_str(1, 1, repinfo);
|
||||
//sprintf(repinfo, "Len: %d ", bufsize);
|
||||
//gfx_poke_str(1, 2, repinfo);
|
||||
/*if (buffer) {
|
||||
sprintf(repinfo, "%02x %02x %02x %02x %02x %02x", buffer[0], buffer[1], buffer[2],
|
||||
buffer[3], buffer[4], buffer[5]);
|
||||
gfx_poke_str(0, 0, repinfo);
|
||||
}
|
||||
|
||||
gfx_flush();*/
|
||||
|
||||
//return;
|
||||
|
||||
if (bufsize < 5) return;
|
||||
|
||||
// FIXME
|
||||
if (report_type == 2) {
|
||||
// Big Reform style
|
||||
if (report_id == 'x') {
|
||||
const uint32_t command = (buffer[3]<<24u)|(buffer[2]<<16u)|(buffer[1]<<8u)|buffer[0];
|
||||
|
||||
if (command == CMD_TEXT_FRAME) {
|
||||
gfx_clear();
|
||||
gfx_on();
|
||||
|
||||
int c = 4;
|
||||
for (uint8_t y=0; y<4; y++) {
|
||||
for (uint8_t x=0; x<21; x++) {
|
||||
if (buffer[c] == '\n') {
|
||||
c++;
|
||||
x = 0;
|
||||
y++;
|
||||
} else if (x < 21 && y < 4) {
|
||||
gfx_poke(x, y, buffer[c++]);
|
||||
}
|
||||
if (c>=bufsize) break;
|
||||
}
|
||||
}
|
||||
gfx_flush();
|
||||
}
|
||||
else if (command == CMD_POWER_OFF) {
|
||||
//reset_menu();
|
||||
//anim_goodbye();
|
||||
remote_turn_off_som();
|
||||
//keyboard_power_off();
|
||||
//reset_keyboard_state();
|
||||
}
|
||||
else if (command == CMD_OLED_CLEAR) {
|
||||
gfx_clear();
|
||||
gfx_flush();
|
||||
}
|
||||
else if (command == CMD_OLED_BITMAP) {
|
||||
matrix_render_direct((uint8_t*)buffer+4);
|
||||
}
|
||||
else if (command == CMD_RGB_BITMAP) {
|
||||
// row, data (12 * 3 rgb bytes)
|
||||
led_bitmap(buffer[4], (uint8_t*)buffer+5);
|
||||
}
|
||||
else if (command == CMD_RGB_BACKLIGHT) {
|
||||
uint32_t pixel_grb = (buffer[5]<<16u) | (buffer[6]<<8u) | buffer[4];
|
||||
led_task(pixel_grb);
|
||||
}
|
||||
else if (command == CMD_LOGO) {
|
||||
anim_hello();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if (report_type == HID_REPORT_TYPE_OUTPUT)
|
||||
{
|
||||
// Set keyboard LED e.g Capslock, Numlock etc...
|
||||
if (report_id == REPORT_ID_KEYBOARD)
|
||||
|
@ -828,5 +927,5 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
|
|||
|
||||
//uint8_t const kbd_leds = buffer[0];
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -92,29 +92,62 @@ uint8_t matrix[KBD_MATRIX_SZ] = {
|
|||
};
|
||||
|
||||
// When holding down HYPER
|
||||
/*uint8_t matrix_fn[KBD_MATRIX_SZ] = {
|
||||
uint8_t matrix_fn[KBD_MATRIX_SZ] = {
|
||||
// Media keys on Hyper + F7-F12
|
||||
KEY_ESC,
|
||||
KEY_GRAVE,
|
||||
KEY_F1,
|
||||
KEY_F2,
|
||||
KEY_F3,
|
||||
KEY_F4,
|
||||
KEY_F5,
|
||||
KEY_F6,
|
||||
HID_KEYBOARD_SC_MEDIA_BACKWARD,
|
||||
HID_KEYBOARD_SC_MEDIA_PLAY,
|
||||
HID_KEYBOARD_SC_MEDIA_FORWARD,
|
||||
HID_KEYBOARD_SC_MEDIA_MUTE,
|
||||
HID_KEYBOARD_SC_MEDIA_VOLUME_DOWN,
|
||||
HID_KEYBOARD_SC_MEDIA_VOLUME_UP,
|
||||
KEY_CIRCLE,
|
||||
KEY_F7,
|
||||
KEY_F8,
|
||||
KEY_F9,
|
||||
KEY_F10,
|
||||
KEY_DELETE,
|
||||
|
||||
KEY_TAB,
|
||||
KEY_F11,
|
||||
KEY_F12,
|
||||
KEY_F13,
|
||||
KEY_R,
|
||||
KEY_T,
|
||||
KEY_Y,
|
||||
KEY_U,
|
||||
KEY_I,
|
||||
KEY_LEFTBRACE,
|
||||
KEY_RIGHTBRACE,
|
||||
KEY_SEMICOLON,
|
||||
|
||||
MATRIX_DEFAULT_ROW_2,
|
||||
MATRIX_DEFAULT_ROW_3,
|
||||
MATRIX_DEFAULT_ROW_4,
|
||||
MATRIX_DEFAULT_ROW_5,
|
||||
MATRIX_DEFAULT_ROW_6
|
||||
};*/
|
||||
|
||||
KEY_LEFTSHIFT,
|
||||
KEY_Z,
|
||||
KEY_X,
|
||||
KEY_C,
|
||||
KEY_V,
|
||||
KEY_B,
|
||||
KEY_N,
|
||||
KEY_M,
|
||||
KEY_COMMA,
|
||||
KEY_DOT,
|
||||
KEY_PAGEUP,
|
||||
KEY_RIGHTSHIFT,
|
||||
|
||||
KEY_COMPOSE,
|
||||
KEY_RIGHTMETA,
|
||||
KEY_RIGHTALT,
|
||||
KEY_BACKSLASH,
|
||||
KEY_EQUAL,
|
||||
KEY_POWER,
|
||||
KEY_POWER,
|
||||
KEY_MINUS,
|
||||
KEY_SLASH,
|
||||
KEY_HOME,
|
||||
KEY_PAGEDOWN,
|
||||
KEY_END
|
||||
};
|
||||
|
||||
// Second layer (toggled by HYPER+CIRCLE)
|
||||
/*uint8_t matrix_fn_toggled[KBD_MATRIX_SZ] = {
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
#define CFG_TUD_VENDOR 0
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 16
|
||||
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue