Update lever commands

This commit is contained in:
whowechina 2024-09-17 22:28:29 +08:00
parent c622ae7ec6
commit 41c59d8319
10 changed files with 84 additions and 235 deletions

View File

@ -183,7 +183,13 @@ You need to rotate 135 degrees on Z axis to fit the bed.
* If it's already running Geki Pico firmware, you can either use "update" in command line or hold down at least 4 buttons while connecting to USB to enter update mode. * If it's already running Geki Pico firmware, you can either use "update" in command line or hold down at least 4 buttons while connecting to USB to enter update mode.
* To access the command line, you can use this Web Serial Terminal to connect to the USB serial port of the Geki Pico. (Note: "?" is for help) * To access the command line, you can use this Web Serial Terminal to connect to the USB serial port of the Geki Pico. (Note: "?" is for help)
https://googlechromelabs.github.io/serial-terminal/ https://googlechromelabs.github.io/serial-terminal/
* **NOTE:** You need to calibrate the lever by "lever calibrate" command after you flash the firmware.
### Usage
* You need to calibrate the lever by "lever calibrate" command after you flash the firmware.
* If you feel the lever direction is in correct, you can use "lever invert \<on|off\>" command to change it.
* Volume of sound feedback can be set by "volume \<0~255\>" command.
* To emulate IO4 TEST/SERVICE/COIN, you can put your hand at higher position over the right ToF sensor. When you see the WAD lights flashing, the AUX buttons become TEST and SERVICE, swing the lever for "INSERT COINS".
* AIME is on a secondary COM port. You can set mode or toggle virtual AIC function.
## CAD Source File ## CAD Source File
I'm using OnShape free subscription. It's powerful but it can't archive original designs to local, so I can only share the link here. STL/DXF/DWG files are exported from this online document. I'm using OnShape free subscription. It's powerful but it can't archive original designs to local, so I can only share the link here. STL/DXF/DWG files are exported from this online document.

View File

@ -1,7 +1,7 @@
function(make_firmware board board_def) function(make_firmware board board_def)
pico_sdk_init() pico_sdk_init()
add_executable(${board} add_executable(${board}
main.c light.c button.c gimbal.c sound.c airkey.c vl53l0x.c save.c config.c main.c light.c button.c lever.c sound.c airkey.c vl53l0x.c save.c config.c
commands.c cli.c hid.c usb_descriptors.c) commands.c cli.c hid.c usb_descriptors.c)
target_compile_definitions(${board} PUBLIC ${board_def}) target_compile_definitions(${board} PUBLIC ${board_def})
pico_enable_stdio_usb(${board} 1) pico_enable_stdio_usb(${board} 1)

View File

@ -11,7 +11,7 @@
#include "save.h" #include "save.h"
#include "cli.h" #include "cli.h"
#include "gimbal.h" #include "lever.h"
extern uint8_t RING_DATA[]; extern uint8_t RING_DATA[];
@ -23,52 +23,18 @@ extern uint8_t RING_DATA[];
#define SENSE_LIMIT_MAX 9 #define SENSE_LIMIT_MAX 9
#define SENSE_LIMIT_MIN -9 #define SENSE_LIMIT_MIN -9
static inline int sprintf_hsv_rgb(char *buf, const rgb_hsv_t *color)
{
return sprintf(buf, "%s(%d,%d,%d)", color->rgb_hsv ? "hsv" : "rgb",
color->val[0], color->val[1], color->val[2]);
}
static const char *color_str(const rgb_hsv_t *color, bool left_right)
{
static char buf[64];
int count = 0;
if (left_right) {
count += sprintf(buf + count, "LEFT ");
}
count += sprintf_hsv_rgb(buf + count, color);
if (left_right) {
count += sprintf(buf + count, ", RIGHT ");
count += sprintf_hsv_rgb(buf + count, color + 1);
}
return buf;
}
static void disp_light() static void disp_light()
{ {
printf("[Light]\n"); printf("[Light]\n");
printf(" Level: %d.\n", geki_cfg->light.level); printf(" Level: %d.\n", geki_cfg->light.level);
printf(" Colors:\n");
printf(" base0: %s\n", color_str(geki_cfg->light.base[0], true));
printf(" base1: %s\n", color_str(geki_cfg->light.base[0], true));
printf(" button: %s\n", color_str(geki_cfg->light.button, true));
printf(" boost: %s\n", color_str(geki_cfg->light.boost, true));
printf(" steer: %s\n", color_str(geki_cfg->light.steer, true));
printf(" aux_on: %s\n", color_str(&geki_cfg->light.aux_on, false));
printf(" aux_off: %s\n", color_str(&geki_cfg->light.aux_off, false));
} }
static void disp_gimbal() static void disp_lever()
{ {
printf("[Gimbal]\n"); printf("[Lever]\n");
printf(" %s, %s, raw %d-%d.\n", printf(" %s, raw %d-%d.\n",
geki_cfg->gimbal.invert ? "invert" : "normal", geki_cfg->lever.invert ? "invert" : "normal",
geki_cfg->gimbal.analog ? "analog" : "digital", geki_cfg->lever.min, geki_cfg->lever.max);
geki_cfg->gimbal.min, geki_cfg->gimbal.max);
} }
static void disp_sound() static void disp_sound()
@ -95,7 +61,7 @@ static void disp_aime()
void handle_display(int argc, char *argv[]) void handle_display(int argc, char *argv[])
{ {
const char *usage = "Usage: display [light|sound|hid|gimbal|aime]\n"; const char *usage = "Usage: display [light|sound|hid|lever|aime]\n";
if (argc > 1) { if (argc > 1) {
printf(usage); printf(usage);
return; return;
@ -103,20 +69,20 @@ void handle_display(int argc, char *argv[])
if (argc == 0) { if (argc == 0) {
disp_light(); disp_light();
disp_gimbal(); disp_lever();
disp_sound(); disp_sound();
disp_hid(); disp_hid();
disp_aime(); disp_aime();
return; return;
} }
const char *choices[] = {"light", "gimbal", "sound", "hid", "aime"}; const char *choices[] = {"light", "lever", "sound", "hid", "aime"};
switch (cli_match_prefix(choices, count_of(choices), argv[0])) { switch (cli_match_prefix(choices, count_of(choices), argv[0])) {
case 0: case 0:
disp_light(); disp_light();
break; break;
case 1: case 1:
disp_gimbal(); disp_lever();
break; break;
case 2: case 2:
disp_sound(); disp_sound();
@ -198,7 +164,7 @@ static void calibrate_range(uint32_t seconds)
uint64_t start = time_us_64(); uint64_t start = time_us_64();
while (time_us_64() - start < seconds * 1000000) { while (time_us_64() - start < seconds * 1000000) {
uint16_t val = gimbal_raw(); uint16_t val = lever_raw();
printf("%4d\n", val); printf("%4d\n", val);
if (val < mins) { if (val < mins) {
mins -= (mins - val) / 2; mins -= (mins - val) / 2;
@ -208,13 +174,13 @@ static void calibrate_range(uint32_t seconds)
sleep_ms(7); sleep_ms(7);
} }
geki_cfg->gimbal.min = mins; geki_cfg->lever.min = mins;
geki_cfg->gimbal.max = maxs; geki_cfg->lever.max = maxs;
} }
static void gimbal_calibrate() static void lever_calibrate()
{ {
printf("Slowly move the stick in full range.\n"); printf("Slowly swing the lever in full range.\n");
printf("Now calibrating ..."); printf("Now calibrating ...");
fflush(stdout); fflush(stdout);
@ -222,9 +188,9 @@ static void gimbal_calibrate()
printf(" done.\n"); printf(" done.\n");
} }
static void gimbal_invert(const char *param) static void lever_invert(const char *param)
{ {
const char *usage = "Usage: gimbal invert <on|off>\n"; const char *usage = "Usage: lever invert <on|off>\n";
int invert = cli_match_prefix((const char *[]){"off", "on"}, 2, param); int invert = cli_match_prefix((const char *[]){"off", "on"}, 2, param);
if (invert < 0) { if (invert < 0) {
@ -234,125 +200,33 @@ static void gimbal_invert(const char *param)
printf("param:%s, invert:%d\n", param, invert); printf("param:%s, invert:%d\n", param, invert);
geki_cfg->gimbal.invert = invert; geki_cfg->lever.invert = invert;
} }
static void gimbal_analog(const char *param) static void handle_lever(int argc, char *argv[])
{ {
const char *usage = "Usage: gimbal analog <on|off>\n"; const char *usage = "Usage: lever calibrate\n"
int analog = cli_match_prefix((const char *[]){"off", "on"}, 2, param); " lever invert <on|off>\n";
if (analog < 0) {
printf(usage);
return;
}
geki_cfg->gimbal.analog = analog;
}
static void handle_gimbal(int argc, char *argv[])
{
const char *usage = "Usage: gimbal calibrate\n"
" gimbal invert <on|off>\n"
" gimbal analog <on|off>\n";
if (argc == 1) { if (argc == 1) {
if (strncasecmp(argv[0], "calibrate", strlen(argv[0])) != 0) { if (strncasecmp(argv[0], "calibrate", strlen(argv[0])) != 0) {
printf(usage); printf(usage);
return; return;
} }
gimbal_calibrate(); lever_calibrate();
} else if (argc == 2) { } else if (argc == 2) {
int op = cli_match_prefix((const char *[]){"invert", "analog"}, 2, argv[0]); if (strncasecmp(argv[0], "invert", strlen(argv[0])) != 0) {
if (op == 0) {
gimbal_invert(argv[1]);
} else if (op == 1) {
gimbal_analog(argv[1]);
} else {
printf(usage); printf(usage);
return; return;
} }
lever_invert(argv[1]);
} else { } else {
printf(usage); printf(usage);
return; return;
} }
config_changed(); config_changed();
disp_gimbal(); disp_lever();
}
static bool extract_color(rgb_hsv_t *color, char *argv[4])
{
int rgb_hsv = cli_match_prefix((const char *[]){"rgb", "hsv"}, 2, argv[0]);
if (rgb_hsv < 0) {
return false;
}
color->rgb_hsv = rgb_hsv;
for (int i = 0; i < 3; i++) {
int v = cli_extract_non_neg_int(argv[1 + i], 0);
if ((v < 0) || (v > 255)) {
return false;
}
color->val[i] = v;
}
return true;
}
static void handle_color(int argc, char *argv[])
{
const char *usage = "Usage: color <name> [left|right] <rgb|hsv> <0..255> <0..255> <0..255>\n"
" name: base0 base1 button boost steer aux_on aux_off\n";
if ((argc != 5) && (argc != 6)) {
printf(usage);
return;
}
rgb_hsv_t *names[] = {
&geki_cfg->light.aux_on,
&geki_cfg->light.aux_off,
geki_cfg->light.base[0],
geki_cfg->light.base[1],
geki_cfg->light.button,
geki_cfg->light.boost,
geki_cfg->light.steer,
};
const char *choices[] = {"aux_on", "aux_off", "base0", "base1", "button", "boost", "steer"};
static_assert(count_of(choices) == count_of(names));
int name = cli_match_prefix(choices, count_of(choices), argv[0]);
if (name < 0) {
printf(usage);
return;
}
bool left = true;
bool right = true;
if (argc == 6) {
int left_right = cli_match_prefix((const char *[]){"left", "right"}, 2, argv[1]);
if (left_right < 0) {
printf(usage);
return;
}
left = (left_right == 0);
right = (left_right == 1);
}
rgb_hsv_t color;
if (!extract_color(&color, argv + argc - 4)) {
printf(usage);
return;
}
rgb_hsv_t *target = names[name];
if (left) {
target[0] = color;
}
if ((name >= 2) && right) {
target[1] = color;
}
config_changed();
disp_light();
} }
static void handle_save() static void handle_save()
@ -458,9 +332,8 @@ void commands_init()
{ {
cli_register("display", handle_display, "Display all config."); cli_register("display", handle_display, "Display all config.");
cli_register("level", handle_level, "Set LED brightness level."); cli_register("level", handle_level, "Set LED brightness level.");
cli_register("color", handle_color, "Set LED color.");
cli_register("hid", handle_hid, "Set HID mode."); cli_register("hid", handle_hid, "Set HID mode.");
cli_register("gimbal", handle_gimbal, "Calibrate the gimbals."); cli_register("lever", handle_lever, "Lever related settings.");
cli_register("volume", handle_volume, "Sound feedback volume settings."); cli_register("volume", handle_volume, "Sound feedback volume settings.");
cli_register("save", handle_save, "Save config to flash."); cli_register("save", handle_save, "Save config to flash.");
cli_register("factory", handle_factory_reset, "Reset everything to default."); cli_register("factory", handle_factory_reset, "Reset everything to default.");

View File

@ -12,35 +12,11 @@
geki_cfg_t *geki_cfg; geki_cfg_t *geki_cfg;
static geki_cfg_t default_cfg = { static geki_cfg_t default_cfg = {
.gimbal = { .lever = {
2000, 2500, 0, 80, 1, 2000, 2500, 0,
}, },
.light = { .light = {
.level = 128, .level = 128,
.base = {
{
{ 1, { 20, 150, 10 }, },
{ 1, { 147, 150, 10 }, },
},
{
{ 1, { 20, 150, 30 }, },
{ 1, { 147, 150, 30 }, },
},
},
.button = {
{ 1, { 0, 0, 120 } },
{ 1, { 0, 0, 120 } },
},
.boost = {
{ 1, { 20, 255, 255 } },
{ 1, { 147, 255, 255 } },
},
.steer = {
{ 1, { 80, 255, 255 } },
{ 1, { 80, 255, 255 } },
},
.aux_on = { 0, { 100, 100, 100 } },
.aux_off = { 0, { 8, 8, 8 } },
.reserved = { 0 }, .reserved = { 0 },
}, },
.sound = { .sound = {

View File

@ -19,16 +19,10 @@ typedef struct __attribute__((packed)) {
uint16_t min; uint16_t min;
uint16_t max; uint16_t max;
uint8_t invert:1; uint8_t invert:1;
uint8_t threshold:7; uint8_t reserved:7;
uint8_t analog:1; } lever;
} gimbal;
struct { struct {
rgb_hsv_t base[2][2]; rgb_hsv_t colors[12];
rgb_hsv_t button[2];
rgb_hsv_t boost[2];
rgb_hsv_t steer[2];
rgb_hsv_t aux_on;
rgb_hsv_t aux_off;
uint8_t level; uint8_t level;
uint8_t reserved[15]; uint8_t reserved[15];
} light; } light;

View File

@ -1,18 +0,0 @@
/*
* Left and Right Gimbal Inputs
* WHowe <github.com/whowechina>
*/
#ifndef GIMBAL_H
#define GIMBAL_H
#include <stdint.h>
#include <stdbool.h>
void gimbal_init();
uint8_t gimbal_read();
uint16_t gimbal_raw();
uint16_t gimbal_average();
#endif

View File

@ -6,7 +6,7 @@
#include "tusb.h" #include "tusb.h"
#include "usb_descriptors.h" #include "usb_descriptors.h"
#include "button.h" #include "button.h"
#include "gimbal.h" #include "lever.h"
#include "airkey.h" #include "airkey.h"
#include "config.h" #include "config.h"
#include "light.h" #include "light.h"
@ -30,7 +30,7 @@ struct __attribute__((packed)) {
static void gen_hid_analogs() static void gen_hid_analogs()
{ {
hid_joy.adcs[0] = gimbal_read() << 8; hid_joy.adcs[0] = lever_read() << 8;
} }
static void gen_hid_buttons() static void gen_hid_buttons()
{ {
@ -80,14 +80,14 @@ static void gen_hid_buttons()
static void gen_hid_coins() static void gen_hid_coins()
{ {
static uint8_t last_gimbal = 0; static uint8_t last_lever = 0;
uint8_t gimbal = gimbal_read(); uint8_t lever = lever_read();
static int dec_count = 0; static int dec_count = 0;
if (airkey_get(3)) { if (airkey_get(3)) {
if (gimbal < last_gimbal) { if (lever < last_lever) {
dec_count++; dec_count++;
} else if (gimbal > last_gimbal) { } else if (lever > last_lever) {
dec_count = 0; dec_count = 0;
} }
@ -97,7 +97,7 @@ static void gen_hid_coins()
} }
} }
last_gimbal = gimbal; last_lever = lever;
} }
static void report_usb_hid() static void report_usb_hid()
{ {

View File

@ -1,10 +1,10 @@
/* /*
* Left and Right Gimbal Inputs * Lever Input
* WHowe <github.com/whowechina> * WHowe <github.com/whowechina>
* *
*/ */
#include "gimbal.h" #include "lever.h"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "board_defs.h" #include "board_defs.h"
void gimbal_init() void lever_init()
{ {
gpio_init(AXIS_MUX_PIN_A); gpio_init(AXIS_MUX_PIN_A);
gpio_set_dir(AXIS_MUX_PIN_A, GPIO_OUT); gpio_set_dir(AXIS_MUX_PIN_A, GPIO_OUT);
@ -33,11 +33,11 @@ void gimbal_init()
adc_select_input(ADC_CHANNEL); adc_select_input(ADC_CHANNEL);
} }
uint8_t gimbal_read() uint8_t lever_read()
{ {
uint16_t val = gimbal_average(); uint16_t val = lever_average();
const uint16_t min = geki_cfg->gimbal.min; const uint16_t min = geki_cfg->lever.min;
const uint16_t max = geki_cfg->gimbal.max; const uint16_t max = geki_cfg->lever.max;
if (val < min) { if (val < min) {
val = min; val = min;
@ -51,14 +51,14 @@ uint8_t gimbal_read()
} }
uint8_t result = (val - min) * 255 / range; uint8_t result = (val - min) * 255 / range;
if (geki_cfg->gimbal.invert) { if (geki_cfg->lever.invert) {
result = 255 - result; result = 255 - result;
} }
return result; return result;
} }
uint16_t gimbal_raw() uint16_t lever_raw()
{ {
static uint16_t last_read = 2048; static uint16_t last_read = 2048;
const uint16_t rate_limit = 5; const uint16_t rate_limit = 5;
@ -75,18 +75,18 @@ uint16_t gimbal_raw()
return last_read; return last_read;
} }
#define GIMBAL_AVERAGE_COUNT 32 #define LEVER_AVERAGE_COUNT 32
uint16_t gimbal_average() uint16_t lever_average()
{ {
static uint16_t buf[GIMBAL_AVERAGE_COUNT] = {0}; static uint16_t buf[LEVER_AVERAGE_COUNT] = {0};
static int index = 0; static int index = 0;
index = (index + 1) % GIMBAL_AVERAGE_COUNT; index = (index + 1) % LEVER_AVERAGE_COUNT;
buf[index] = gimbal_raw(); buf[index] = lever_raw();
uint32_t sum = 0; uint32_t sum = 0;
for (int i = 0; i < GIMBAL_AVERAGE_COUNT; i++) { for (int i = 0; i < LEVER_AVERAGE_COUNT; i++) {
sum += buf[i]; sum += buf[i];
} }
return sum / GIMBAL_AVERAGE_COUNT; return sum / LEVER_AVERAGE_COUNT;
} }

18
firmware/src/lever.h Normal file
View File

@ -0,0 +1,18 @@
/*
* Lever Input
* WHowe <github.com/whowechina>
*/
#ifndef LEVER_H
#define LEVER_H
#include <stdint.h>
#include <stdbool.h>
void lever_init();
uint8_t lever_read();
uint16_t lever_raw();
uint16_t lever_average();
#endif

View File

@ -35,13 +35,13 @@
#include "light.h" #include "light.h"
#include "button.h" #include "button.h"
#include "gimbal.h" #include "lever.h"
#include "airkey.h" #include "airkey.h"
#include "sound.h" #include "sound.h"
static void run_lights() static void run_lights()
{ {
light_set_pos(255 - gimbal_read(), rgb32(0xff, 0, 0, false)); light_set_pos(255 - lever_read(), rgb32(0xff, 0, 0, false));
uint16_t button = button_read(); uint16_t button = button_read();
@ -174,7 +174,7 @@ void init()
light_init(); light_init();
button_init(); button_init();
gimbal_init(); lever_init();
airkey_init(); airkey_init();
sound_init(); sound_init();