v0.0.33 - Implement in-place mnemonic entry grid with staged prefix selection and fix stage-3 candidate rendering
This commit is contained in:
@@ -52,8 +52,7 @@ enum signer_ui_state_t {
|
||||
SIGNER_UI_MENU = 0,
|
||||
SIGNER_UI_READY = 1,
|
||||
SIGNER_UI_GENERATE_REVIEW = 2,
|
||||
SIGNER_UI_ENTER_LETTER = 3,
|
||||
SIGNER_UI_ENTER_PICK = 4,
|
||||
SIGNER_UI_ENTER_GRID = 3,
|
||||
};
|
||||
|
||||
static device_mode_t s_mode = MODE_MEDIA;
|
||||
@@ -67,12 +66,19 @@ static bool s_auto_approve = false;
|
||||
|
||||
// Signer UI state
|
||||
static uint8_t s_signer_menu_selected = 0; // 0=Generate, 1=Enter
|
||||
static uint8_t s_signer_review_page = 0; // 0..2 for 12 words at 4/page
|
||||
static uint8_t s_signer_review_page = 0; // legacy placeholder (review now renders all 12 words at once)
|
||||
static char s_generated_mnemonic[256] = "";
|
||||
static uint8_t s_enter_slot = 0; // 0..11
|
||||
static uint8_t s_enter_letter_index = 0; // 0..25 => a..z
|
||||
static uint16_t s_enter_word_index = 0; // current picker index
|
||||
static uint8_t s_enter_slot = 0; // 0..11
|
||||
static uint8_t s_enter_stage = 1; // 1=first letter, 2=second letter, 3=word select
|
||||
static uint8_t s_enter_first_letter_index = 0; // 0..25 => a..z
|
||||
static char s_enter_second_letters[26] = {0};
|
||||
static uint8_t s_enter_second_count = 0;
|
||||
static uint8_t s_enter_second_index = 0;
|
||||
static uint16_t s_enter_prefix_start = 0;
|
||||
static uint16_t s_enter_prefix_count = 0;
|
||||
static uint16_t s_enter_candidate_offset = 0;
|
||||
static uint16_t s_enter_selected_indices[12] = {0};
|
||||
static bool s_enter_committed[12] = {false};
|
||||
|
||||
static void signer_enter_ready_screen();
|
||||
|
||||
@@ -128,8 +134,9 @@ static void led_blink(int n, int on_ms, int off_ms) {
|
||||
static void send_consumer_key(uint16_t usage) {
|
||||
if (!usb_hid.ready()) return;
|
||||
usb_hid.sendReport16(1, usage);
|
||||
delay(2);
|
||||
delay(8); // restore hold for better throughput while keeping reliability
|
||||
usb_hid.sendReport16(1, 0);
|
||||
delay(4); // restore smaller inter-key gap for faster throughput
|
||||
}
|
||||
|
||||
static int8_t read_ab() {
|
||||
@@ -252,30 +259,30 @@ static void signer_apply_seed(const char *mnemonic) {
|
||||
strncpy(s_mnemonic, mnemonic, sizeof(s_mnemonic) - 1);
|
||||
s_mnemonic[sizeof(s_mnemonic) - 1] = '\0';
|
||||
s_seed_loaded = strlen(s_mnemonic) > 0;
|
||||
display_set_status(s_seed_loaded ? "Seed loaded" : "Seed cleared");
|
||||
// display_set_status(s_seed_loaded ? "Seed loaded" : "Seed cleared");
|
||||
}
|
||||
|
||||
static bool wait_for_user_approval(uint32_t timeout_ms) {
|
||||
display_show_message("APPROVAL", "PLAY=Allow", "PREV=Deny");
|
||||
display_set_status("Waiting approval");
|
||||
display_show_message("APPROVAL", "Host requests", "signature");
|
||||
// display_set_status("Waiting approval");
|
||||
|
||||
uint32_t start = millis();
|
||||
while ((millis() - start) < timeout_ms) {
|
||||
if (btn_pressed(PIN_BTN_PLAY)) {
|
||||
while (btn_pressed(PIN_BTN_PLAY)) delay(5);
|
||||
display_set_status("Approved");
|
||||
// display_set_status("Approved");
|
||||
return true;
|
||||
}
|
||||
if (btn_pressed(PIN_BTN_PREV)) {
|
||||
while (btn_pressed(PIN_BTN_PREV)) delay(5);
|
||||
display_set_status("Denied");
|
||||
// display_set_status("Denied");
|
||||
return false;
|
||||
}
|
||||
display_tick();
|
||||
delay(5);
|
||||
}
|
||||
|
||||
display_set_status("Approval timeout");
|
||||
// display_set_status("Approval timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -293,13 +300,13 @@ static void handle_rpc(const char *req_json) {
|
||||
char method[64] = {0};
|
||||
if (!json_extract_string(req_json, "method", method, sizeof(method))) {
|
||||
send_json_response("{\"error\":{\"code\":-32600,\"message\":\"invalid request\"}}");
|
||||
display_set_status("RPC invalid request");
|
||||
// display_set_status("RPC invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "ping") == 0) {
|
||||
send_json_response("{\"result\":\"pong\"}");
|
||||
display_set_status("RPC ping");
|
||||
// display_set_status("RPC ping");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,7 +318,7 @@ static void handle_rpc(const char *req_json) {
|
||||
s_seed_loaded ? "true" : "false",
|
||||
s_auto_approve ? "true" : "false");
|
||||
send_json_response(resp);
|
||||
display_set_status("RPC get_status");
|
||||
// display_set_status("RPC get_status");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -319,7 +326,7 @@ static void handle_rpc(const char *req_json) {
|
||||
char phrase[256] = {0};
|
||||
if (!json_extract_string(req_json, "mnemonic", phrase, sizeof(phrase))) {
|
||||
send_json_response("{\"error\":{\"code\":-32602,\"message\":\"missing mnemonic\"}}");
|
||||
display_set_status("Mnemonic missing");
|
||||
// display_set_status("Mnemonic missing");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -335,14 +342,14 @@ static void handle_rpc(const char *req_json) {
|
||||
if (strstr(req_json, "\"value\":true") != nullptr) {
|
||||
s_auto_approve = true;
|
||||
send_json_response("{\"result\":true}");
|
||||
display_set_status("Auto-approve ON");
|
||||
// display_set_status("Auto-approve ON");
|
||||
} else if (strstr(req_json, "\"value\":false") != nullptr) {
|
||||
s_auto_approve = false;
|
||||
send_json_response("{\"result\":false}");
|
||||
display_set_status("Auto-approve OFF");
|
||||
// display_set_status("Auto-approve OFF");
|
||||
} else {
|
||||
send_json_response("{\"error\":{\"code\":-32602,\"message\":\"missing value\"}}");
|
||||
display_set_status("Auto-approve invalid");
|
||||
// display_set_status("Auto-approve invalid");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -350,7 +357,7 @@ static void handle_rpc(const char *req_json) {
|
||||
if (strcmp(method, "get_public_key") == 0) {
|
||||
if (!s_seed_loaded) {
|
||||
send_json_response("{\"error\":{\"code\":2014,\"message\":\"seed not loaded\"}}");
|
||||
display_set_status("No seed");
|
||||
// display_set_status("No seed");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -360,20 +367,20 @@ static void handle_rpc(const char *req_json) {
|
||||
char resp[192];
|
||||
snprintf(resp, sizeof(resp), "{\"result\":{\"pubkey\":\"%s\"}}", pubhex);
|
||||
send_json_response(resp);
|
||||
display_set_status("Pubkey served");
|
||||
// display_set_status("Pubkey served");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "sign_event") == 0) {
|
||||
if (!s_seed_loaded) {
|
||||
send_json_response("{\"error\":{\"code\":2014,\"message\":\"seed not loaded\"}}");
|
||||
display_set_status("Sign blocked:no seed");
|
||||
// display_set_status("Sign blocked:no seed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_mode != MODE_SIGNER) {
|
||||
send_json_response("{\"error\":{\"code\":2015,\"message\":\"not in signer mode\"}}");
|
||||
display_set_status("Sign blocked:mode");
|
||||
// display_set_status("Sign blocked:mode");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -390,7 +397,7 @@ static void handle_rpc(const char *req_json) {
|
||||
}
|
||||
|
||||
send_json_response("{\"result\":{\"sig\":\"dev_signature_placeholder\"}}");
|
||||
display_set_status("Event signed");
|
||||
// display_set_status("Event signed");
|
||||
if (s_signer_ui_state == SIGNER_UI_MENU) {
|
||||
display_show_signer_menu(s_signer_menu_selected);
|
||||
} else if (s_signer_ui_state == SIGNER_UI_READY) {
|
||||
@@ -400,7 +407,7 @@ static void handle_rpc(const char *req_json) {
|
||||
}
|
||||
|
||||
send_json_response("{\"error\":{\"code\":-32601,\"message\":\"method not found\"}}");
|
||||
display_set_status("RPC method missing");
|
||||
// display_set_status("RPC method missing");
|
||||
}
|
||||
|
||||
static void webusb_pump_frames() {
|
||||
@@ -426,7 +433,7 @@ static void webusb_pump_frames() {
|
||||
if (body_len > (sizeof(s_rx_buf) - 4)) {
|
||||
s_rx_len = 0;
|
||||
send_json_response("{\"error\":{\"code\":-32000,\"message\":\"frame too large\"}}");
|
||||
display_set_status("Frame too large");
|
||||
// display_set_status("Frame too large");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -452,56 +459,96 @@ static void signer_enter_menu_screen() {
|
||||
s_signer_ui_state = SIGNER_UI_MENU;
|
||||
display_set_view(DISPLAY_VIEW_SIGNER);
|
||||
display_show_signer_menu(s_signer_menu_selected);
|
||||
display_set_status("ENC scroll PLAY select");
|
||||
// display_set_status("ENC scroll PLAY select");
|
||||
}
|
||||
|
||||
static void signer_enter_ready_screen() {
|
||||
s_signer_ui_state = SIGNER_UI_READY;
|
||||
display_set_view(DISPLAY_VIEW_SIGNER);
|
||||
display_show_signer_ready();
|
||||
display_set_status("Ready to sign");
|
||||
// display_set_status("Ready to sign");
|
||||
}
|
||||
|
||||
static char signer_current_letter() {
|
||||
return (char)('a' + (s_enter_letter_index % 26));
|
||||
static char signer_first_letter() {
|
||||
return (char)('a' + (s_enter_first_letter_index % 26));
|
||||
}
|
||||
|
||||
static void signer_enter_letter_pick_screen() {
|
||||
s_signer_ui_state = SIGNER_UI_ENTER_LETTER;
|
||||
|
||||
char line1[20];
|
||||
char line2[24];
|
||||
snprintf(line1, sizeof(line1), "Word %u/12", (unsigned)(s_enter_slot + 1));
|
||||
snprintf(line2, sizeof(line2), "Letter: %c", signer_current_letter());
|
||||
display_show_message("PICK FIRST LETTER", line1, line2);
|
||||
display_set_status("ENC letter PLAY confirm");
|
||||
static char signer_second_letter() {
|
||||
if (s_enter_second_count == 0 || s_enter_second_index >= s_enter_second_count) {
|
||||
return 'a';
|
||||
}
|
||||
return s_enter_second_letters[s_enter_second_index];
|
||||
}
|
||||
|
||||
static void signer_enter_word_pick_screen() {
|
||||
s_signer_ui_state = SIGNER_UI_ENTER_PICK;
|
||||
static void signer_reset_active_slot_state() {
|
||||
s_enter_stage = 1;
|
||||
s_enter_first_letter_index = 0;
|
||||
s_enter_second_count = 0;
|
||||
s_enter_second_index = 0;
|
||||
s_enter_prefix_start = 0;
|
||||
s_enter_prefix_count = 0;
|
||||
s_enter_candidate_offset = 0;
|
||||
}
|
||||
|
||||
uint16_t start = 0;
|
||||
uint16_t count = 0;
|
||||
if (!mnemonic_letter_range(signer_current_letter(), &start, &count) || count == 0) {
|
||||
start = 0;
|
||||
count = 2048;
|
||||
static bool signer_prepare_second_letters() {
|
||||
s_enter_second_count = 0;
|
||||
s_enter_second_index = 0;
|
||||
return mnemonic_second_letters(signer_first_letter(), s_enter_second_letters, &s_enter_second_count) && s_enter_second_count > 0;
|
||||
}
|
||||
|
||||
static bool signer_prepare_prefix_candidates() {
|
||||
s_enter_prefix_start = 0;
|
||||
s_enter_prefix_count = 0;
|
||||
s_enter_candidate_offset = 0;
|
||||
return mnemonic_prefix_range(signer_first_letter(), signer_second_letter(), &s_enter_prefix_start, &s_enter_prefix_count) &&
|
||||
s_enter_prefix_count > 0;
|
||||
}
|
||||
|
||||
static void signer_render_enter_grid() {
|
||||
const char *slot_words[12] = {nullptr};
|
||||
for (uint8_t i = 0; i < 12; ++i) {
|
||||
if (s_enter_committed[i]) {
|
||||
slot_words[i] = mnemonic_word_at(s_enter_selected_indices[i]);
|
||||
} else {
|
||||
slot_words[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (s_enter_word_index < start || s_enter_word_index >= (uint16_t)(start + count)) {
|
||||
s_enter_word_index = start;
|
||||
char building[16] = "";
|
||||
uint8_t cursor_pos = 0;
|
||||
|
||||
if (s_enter_stage == 1) {
|
||||
building[0] = signer_first_letter();
|
||||
building[1] = '\0';
|
||||
cursor_pos = 1;
|
||||
} else if (s_enter_stage == 2) {
|
||||
building[0] = signer_first_letter();
|
||||
building[1] = signer_second_letter();
|
||||
building[2] = '\0';
|
||||
cursor_pos = 2;
|
||||
} else {
|
||||
const uint16_t idx = (uint16_t)(s_enter_prefix_start + s_enter_candidate_offset);
|
||||
const char *word = mnemonic_word_at(idx);
|
||||
if (word) {
|
||||
strncpy(building, word, sizeof(building) - 1);
|
||||
building[sizeof(building) - 1] = '\0';
|
||||
}
|
||||
cursor_pos = (uint8_t)strlen(building);
|
||||
}
|
||||
|
||||
const char *word = mnemonic_word_at(s_enter_word_index);
|
||||
if (!word) word = "abandon";
|
||||
display_show_word_pick(s_enter_slot, 12, word, s_enter_word_index);
|
||||
display_set_status("ENC word PLAY select");
|
||||
display_show_enter_mnemonic(slot_words, s_enter_slot, s_enter_stage, building, cursor_pos);
|
||||
}
|
||||
|
||||
static void signer_enter_grid_screen() {
|
||||
s_signer_ui_state = SIGNER_UI_ENTER_GRID;
|
||||
display_set_view(DISPLAY_VIEW_SIGNER);
|
||||
signer_render_enter_grid();
|
||||
}
|
||||
|
||||
static void signer_enter_review_screen() {
|
||||
s_signer_ui_state = SIGNER_UI_GENERATE_REVIEW;
|
||||
if (s_signer_review_page > 2) s_signer_review_page = 2;
|
||||
display_show_mnemonic_page(s_generated_mnemonic, s_signer_review_page);
|
||||
display_set_status("PLAY confirm NEXT cancel");
|
||||
display_show_mnemonic_page(s_generated_mnemonic, 0);
|
||||
// display_set_status("PLAY confirm NEXT cancel");
|
||||
}
|
||||
|
||||
static void build_entered_mnemonic(char *out, size_t out_sz) {
|
||||
@@ -513,6 +560,10 @@ static void build_entered_mnemonic(char *out, size_t out_sz) {
|
||||
size_t cursor = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 12; ++i) {
|
||||
if (!s_enter_committed[i]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *w = mnemonic_word_at(s_enter_selected_indices[i]);
|
||||
if (!w) w = "abandon";
|
||||
|
||||
@@ -544,10 +595,10 @@ static void handle_mode_switch_chord() {
|
||||
if (s_mode == MODE_SIGNER) {
|
||||
display_set_view(DISPLAY_VIEW_SIGNER);
|
||||
signer_enter_menu_screen();
|
||||
display_set_status("Signer mode");
|
||||
// display_set_status("Signer mode");
|
||||
} else {
|
||||
display_set_view(DISPLAY_VIEW_VOLUME);
|
||||
display_set_status("Media mode");
|
||||
// display_set_status("Media mode");
|
||||
}
|
||||
|
||||
led_blink(s_mode == MODE_SIGNER ? 3 : 1, 80, 80);
|
||||
@@ -588,36 +639,32 @@ static void media_mode_tick() {
|
||||
const int32_t steps = encoder_take_steps();
|
||||
if (steps > 0) {
|
||||
for (int32_t i = 0; i < steps; ++i) {
|
||||
const int8_t applied = volume_change_by(+1);
|
||||
if (applied > 0) {
|
||||
send_consumer_key(HID_USAGE_CONSUMER_VOLUME_INCREMENT);
|
||||
display_set_volume(s_local_volume);
|
||||
}
|
||||
volume_change_by(+1); // keep display clamped to 0..100
|
||||
send_consumer_key(HID_USAGE_CONSUMER_VOLUME_INCREMENT); // always emit HID step
|
||||
display_set_volume(s_local_volume);
|
||||
}
|
||||
display_set_status("Volume up");
|
||||
// display_set_status("Volume up");
|
||||
} else if (steps < 0) {
|
||||
for (int32_t i = 0; i < -steps; ++i) {
|
||||
const int8_t applied = volume_change_by(-1);
|
||||
if (applied < 0) {
|
||||
send_consumer_key(HID_USAGE_CONSUMER_VOLUME_DECREMENT);
|
||||
display_set_volume(s_local_volume);
|
||||
}
|
||||
volume_change_by(-1); // keep display clamped to 0..100
|
||||
send_consumer_key(HID_USAGE_CONSUMER_VOLUME_DECREMENT); // always emit HID step
|
||||
display_set_volume(s_local_volume);
|
||||
}
|
||||
display_set_status("Volume down");
|
||||
// display_set_status("Volume down");
|
||||
}
|
||||
|
||||
if (s_evt_play_pressed) {
|
||||
send_consumer_key(HID_USAGE_CONSUMER_PLAY_PAUSE);
|
||||
display_set_status("Play/Pause");
|
||||
// display_set_status("Play/Pause");
|
||||
}
|
||||
if (s_evt_next_pressed) {
|
||||
// Preserve original hardware remap: NEXT wiring is swapped.
|
||||
send_consumer_key(HID_USAGE_CONSUMER_SCAN_PREVIOUS_TRACK);
|
||||
display_set_status("Prev track");
|
||||
// display_set_status("Prev track");
|
||||
}
|
||||
if (s_evt_prev_pressed) {
|
||||
send_consumer_key(HID_USAGE_CONSUMER_SCAN_NEXT_TRACK);
|
||||
display_set_status("Next track");
|
||||
// display_set_status("Next track");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,27 +693,22 @@ static void signer_mode_tick() {
|
||||
signer_enter_review_screen();
|
||||
} else {
|
||||
display_show_message("ERROR", "Generate failed", "Try again");
|
||||
display_set_status("Generate failed");
|
||||
// display_set_status("Generate failed");
|
||||
}
|
||||
} else {
|
||||
s_enter_slot = 0;
|
||||
s_enter_letter_index = 0;
|
||||
s_enter_word_index = s_enter_selected_indices[s_enter_slot];
|
||||
signer_enter_letter_pick_screen();
|
||||
for (uint8_t i = 0; i < 12; ++i) {
|
||||
s_enter_committed[i] = false;
|
||||
s_enter_selected_indices[i] = 0;
|
||||
}
|
||||
signer_reset_active_slot_state();
|
||||
signer_enter_grid_screen();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SIGNER_UI_GENERATE_REVIEW: {
|
||||
if (steps != 0) {
|
||||
int16_t p = (int16_t)s_signer_review_page + (steps > 0 ? 1 : -1);
|
||||
if (p < 0) p = 0;
|
||||
if (p > 2) p = 2;
|
||||
s_signer_review_page = (uint8_t)p;
|
||||
signer_enter_review_screen();
|
||||
}
|
||||
|
||||
if (s_evt_play_pressed) {
|
||||
signer_apply_seed(s_generated_mnemonic);
|
||||
signer_enter_ready_screen();
|
||||
@@ -674,7 +716,15 @@ static void signer_mode_tick() {
|
||||
|
||||
if (s_evt_next_pressed) {
|
||||
signer_enter_menu_screen();
|
||||
display_set_status("Generate canceled");
|
||||
// display_set_status("Generate canceled");
|
||||
}
|
||||
|
||||
if (s_evt_prev_pressed) {
|
||||
if (generate_mnemonic_12(s_generated_mnemonic, sizeof(s_generated_mnemonic)) == 0) {
|
||||
signer_enter_review_screen();
|
||||
} else {
|
||||
display_show_message("ERROR", "Generate failed", "Try again");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -686,85 +736,80 @@ static void signer_mode_tick() {
|
||||
break;
|
||||
}
|
||||
|
||||
case SIGNER_UI_ENTER_LETTER: {
|
||||
case SIGNER_UI_ENTER_GRID: {
|
||||
if (steps != 0) {
|
||||
int16_t idx = (int16_t)s_enter_letter_index + (steps > 0 ? 1 : -1);
|
||||
while (idx < 0) idx += 26;
|
||||
while (idx >= 26) idx -= 26;
|
||||
s_enter_letter_index = (uint8_t)idx;
|
||||
signer_enter_letter_pick_screen();
|
||||
}
|
||||
|
||||
if (s_evt_play_pressed) {
|
||||
uint16_t start = 0;
|
||||
uint16_t count = 0;
|
||||
if (mnemonic_letter_range(signer_current_letter(), &start, &count) && count > 0) {
|
||||
s_enter_word_index = start;
|
||||
} else {
|
||||
s_enter_word_index = 0;
|
||||
}
|
||||
signer_enter_word_pick_screen();
|
||||
}
|
||||
|
||||
if (s_evt_next_pressed) {
|
||||
if (s_enter_slot == 0) {
|
||||
signer_enter_menu_screen();
|
||||
display_set_status("Entry canceled");
|
||||
} else {
|
||||
s_enter_slot--;
|
||||
const char *prev_word = mnemonic_word_at(s_enter_selected_indices[s_enter_slot]);
|
||||
if (prev_word && prev_word[0] >= 'a' && prev_word[0] <= 'z') {
|
||||
s_enter_letter_index = (uint8_t)(prev_word[0] - 'a');
|
||||
if (s_enter_stage == 1) {
|
||||
int16_t idx = (int16_t)s_enter_first_letter_index + (steps > 0 ? 1 : -1);
|
||||
while (idx < 0) idx += 26;
|
||||
while (idx >= 26) idx -= 26;
|
||||
s_enter_first_letter_index = (uint8_t)idx;
|
||||
} else if (s_enter_stage == 2) {
|
||||
if (s_enter_second_count > 0) {
|
||||
int16_t idx = (int16_t)s_enter_second_index + (steps > 0 ? 1 : -1);
|
||||
while (idx < 0) idx += s_enter_second_count;
|
||||
while (idx >= s_enter_second_count) idx -= s_enter_second_count;
|
||||
s_enter_second_index = (uint8_t)idx;
|
||||
}
|
||||
s_enter_word_index = s_enter_selected_indices[s_enter_slot];
|
||||
signer_enter_word_pick_screen();
|
||||
display_set_status("Back one step");
|
||||
} else if (s_enter_prefix_count > 0) {
|
||||
int32_t rel = (int32_t)s_enter_candidate_offset + steps;
|
||||
while (rel < 0) rel += s_enter_prefix_count;
|
||||
while (rel >= s_enter_prefix_count) rel -= s_enter_prefix_count;
|
||||
s_enter_candidate_offset = (uint16_t)rel;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SIGNER_UI_ENTER_PICK: {
|
||||
uint16_t start = 0;
|
||||
uint16_t count = 0;
|
||||
if (!mnemonic_letter_range(signer_current_letter(), &start, &count) || count == 0) {
|
||||
start = 0;
|
||||
count = 2048;
|
||||
}
|
||||
|
||||
if (steps != 0) {
|
||||
int32_t rel = (int32_t)s_enter_word_index - (int32_t)start;
|
||||
rel += steps;
|
||||
while (rel < 0) rel += count;
|
||||
while (rel >= count) rel -= count;
|
||||
s_enter_word_index = (uint16_t)(start + rel);
|
||||
signer_enter_word_pick_screen();
|
||||
signer_render_enter_grid();
|
||||
}
|
||||
|
||||
if (s_evt_play_pressed) {
|
||||
s_enter_selected_indices[s_enter_slot] = s_enter_word_index;
|
||||
|
||||
if (s_enter_slot < 11) {
|
||||
s_enter_slot++;
|
||||
s_enter_letter_index = 0;
|
||||
s_enter_word_index = s_enter_selected_indices[s_enter_slot];
|
||||
signer_enter_letter_pick_screen();
|
||||
if (s_enter_stage == 1) {
|
||||
if (signer_prepare_second_letters()) {
|
||||
s_enter_stage = 2;
|
||||
signer_render_enter_grid();
|
||||
}
|
||||
} else if (s_enter_stage == 2) {
|
||||
if (signer_prepare_prefix_candidates()) {
|
||||
s_enter_stage = 3;
|
||||
signer_render_enter_grid();
|
||||
}
|
||||
} else {
|
||||
char phrase[256];
|
||||
build_entered_mnemonic(phrase, sizeof(phrase));
|
||||
if (mnemonic_validate_basic(phrase)) {
|
||||
signer_apply_seed(phrase);
|
||||
signer_enter_ready_screen();
|
||||
s_enter_selected_indices[s_enter_slot] = (uint16_t)(s_enter_prefix_start + s_enter_candidate_offset);
|
||||
s_enter_committed[s_enter_slot] = true;
|
||||
|
||||
if (s_enter_slot < 11) {
|
||||
s_enter_slot++;
|
||||
signer_reset_active_slot_state();
|
||||
signer_render_enter_grid();
|
||||
} else {
|
||||
display_show_message("INVALID", "Bad mnemonic", "NEXT to return");
|
||||
display_set_status("Validation failed");
|
||||
char phrase[256];
|
||||
build_entered_mnemonic(phrase, sizeof(phrase));
|
||||
if (mnemonic_validate_basic(phrase)) {
|
||||
signer_apply_seed(phrase);
|
||||
signer_enter_ready_screen();
|
||||
} else {
|
||||
display_show_message("INVALID", "Bad mnemonic", "Fix and retry");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s_evt_next_pressed) {
|
||||
signer_enter_letter_pick_screen();
|
||||
display_set_status("Back to letter");
|
||||
if (s_enter_stage == 3) {
|
||||
s_enter_stage = 2;
|
||||
signer_render_enter_grid();
|
||||
} else if (s_enter_stage == 2) {
|
||||
s_enter_stage = 1;
|
||||
signer_render_enter_grid();
|
||||
} else {
|
||||
if (s_enter_slot == 0) {
|
||||
signer_enter_menu_screen();
|
||||
} else {
|
||||
s_enter_slot--;
|
||||
s_enter_committed[s_enter_slot] = false;
|
||||
s_enter_selected_indices[s_enter_slot] = 0;
|
||||
signer_reset_active_slot_state();
|
||||
signer_render_enter_grid();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -808,7 +853,7 @@ void setup() {
|
||||
|
||||
display_set_mode(false);
|
||||
display_set_view(DISPLAY_VIEW_VOLUME);
|
||||
display_set_status("USB mounted");
|
||||
// display_set_status("USB mounted");
|
||||
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
led_blink(2, 60, 60);
|
||||
@@ -821,7 +866,7 @@ void loop() {
|
||||
display_set_mode(s_mode == MODE_SIGNER);
|
||||
display_set_volume(s_local_volume);
|
||||
display_set_view(s_mode == MODE_SIGNER ? DISPLAY_VIEW_SIGNER : DISPLAY_VIEW_VOLUME);
|
||||
display_set_status("Ready");
|
||||
// display_set_status("Ready");
|
||||
if (s_mode == MODE_SIGNER) {
|
||||
signer_enter_menu_screen();
|
||||
}
|
||||
@@ -860,7 +905,7 @@ void loop() {
|
||||
(unsigned long)s_diag_bytes_rx,
|
||||
(unsigned long)s_diag_frames_rx,
|
||||
(unsigned long)s_diag_responses_tx);
|
||||
display_set_status(diag);
|
||||
// display_set_status(diag);
|
||||
|
||||
// Idle LED state: ON (HIGH) when connected, OFF otherwise. The RX path
|
||||
// drives it LOW briefly on each byte, so a flicker == bytes arriving.
|
||||
|
||||
Reference in New Issue
Block a user