diff --git a/.gitignore b/.gitignore index 1aa5ca1e8..6a804ef9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +/firmware/application/fox.bmp +/firmware/application/fox_rle.bmp +/firmware/test.wav # Compiled Object files *.slo *.lo diff --git a/firmware/Makefile b/firmware/Makefile index 5bce1a9fc..0def504ce 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -65,7 +65,7 @@ modules: $(TARGET_BASEBAND).bin $(TARGET_BASEBAND_TX).bin cp $(PATH_BASEBAND_TX).bin ../sdcard/$(PATH_BASEBAND_TX).bin $(TARGET).bin: modules $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND_TX)_inc.bin $(TARGET_APPLICATION).bin - $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND)_inc.bin $(TARGET_APPLICATION).bin $(TARGET).bin + $(MAKE_SPI_IMAGE) $(TARGET_BOOTSTRAP).bin $(TARGET_HACKRF_FIRMWARE).dfu $(TARGET_BASEBAND_TX)_inc.bin $(TARGET_APPLICATION).bin $(TARGET).bin $(TARGET_BOOTSTRAP).bin: $(TARGET_BOOTSTRAP).elf $(CP) -O binary $(TARGET_BOOTSTRAP).elf $(TARGET_BOOTSTRAP).bin diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp index ac1c01086..412c74bc9 100755 --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -19,8 +19,11 @@ * Boston, MA 02110-1301, USA. */ -//BUG: No audio in about when shown second time -//BUG: Description doesn't show up first time going to system>module info (UI drawn on top) +//BUG: No audio in about when shown second time +//BUG: Description doesn't show up first time going to system>module info (UI drawn on top) +//BUG: Module load and return to systemview +//TODO: EPAR transmit +//TODO: Use progressbars //TODO: Setting: Prefered input method //TODO: LCR emergency clear all //TODO: LCR receiver diff --git a/firmware/application/ui_handwrite.cpp b/firmware/application/ui_handwrite.cpp index f5b0e9873..a6276091d 100644 --- a/firmware/application/ui_handwrite.cpp +++ b/firmware/application/ui_handwrite.cpp @@ -25,32 +25,39 @@ #include "ch.h" #include "ff.h" -#include "unistroke.hpp" #include "portapack.hpp" #include "event_m0.hpp" -#include "string_format.hpp" #include "hackrf_hal.hpp" #include "portapack_shared_memory.hpp" -#include "time.hpp" #include using namespace portapack; namespace ui { + +void HandWriteView::paint(Painter& painter) { + _painter = &painter; +} HandWriteView::HandWriteView( NavigationView& nav, char txt[], uint8_t max_len ) { + const char special_chars[5] = {'\'', '.', '?', '!', '='}; _max_len = max_len; - _lowercase = false; - txtidx = 0; + // Handwriting alphabet definition here + handwriting = &handwriting_unistroke; + //memcpy(txtinput, txt, max_len+1); - - add_child(&text_input); + + add_children({ { + &text_input, + &button_case, + &button_ok + } }); const auto button_fn = [this](Button& button) { this->on_button(button); @@ -62,35 +69,45 @@ HandWriteView::HandWriteView( button.on_select = button_fn; button.set_parent_rect({ static_cast(n * 24), - static_cast(240), - 24, 20 + static_cast(236), + 24, 28 }); const std::string label { (char)(n + 0x30) }; button.set_text(label); - button.id = n; + button.id = n + 0x30; n++; } - //set_uppercase(); - /*add_child(&button_lowercase); - button_lowercase.on_select = [this, &nav, txt, max_len](Button&) { + n = 0; + for(auto& button : special_buttons) { + add_child(&button); + button.on_select = button_fn; + button.set_parent_rect({ + static_cast(50 + n * 24), + static_cast(270), + 24, 28 + }); + const std::string label { + (char)(special_chars[n]) + }; + button.set_text(label); + button.id = special_chars[n]; + n++; + } + + button_case.on_select = [this, &nav](Button&) { if (_lowercase == true) { _lowercase = false; - button_lowercase.set_text("UC"); - set_uppercase(); + button_case.set_text("LC"); } else { _lowercase = true; - button_lowercase.set_text("LC"); - set_lowercase(); + button_case.set_text("UC"); } - };*/ + }; - add_child(&text_debug_x); - add_child(&text_debug_y); - add_child(&button_done); - button_done.on_select = [this, &nav, txt, max_len](Button&) { + button_ok.on_select = [this, &nav, txt, max_len](Button&) { //memcpy(txt, txtinput, max_len+1); //on_changed(this->value()); nav.pop(); @@ -101,8 +118,8 @@ HandWriteView::HandWriteView( bool HandWriteView::on_touch(const TouchEvent event) { if (event.type == ui::TouchEvent::Type::Start) { - move_index = 0; - move_wait = 4; + stroke_index = 0; + move_wait = 3; tracing = true; } if (event.type == ui::TouchEvent::Type::End) { @@ -117,39 +134,60 @@ bool HandWriteView::on_touch(const TouchEvent event) { return true; } +void HandWriteView::clear_zone(Color color, bool flash) { + display.fill_rectangle( + {{0, 32}, {240, 216}}, + color + ); + if (flash) { + flash_timer = 4; + } else { + _painter->draw_rectangle( + {{0, 32}, {80, 216}}, + Color::grey() + ); + _painter->draw_rectangle( + {{80, 32}, {80, 216}}, + Color::grey() + ); + _painter->draw_rectangle( + {{160, 32}, {80, 216}}, + Color::grey() + ); + _painter->draw_rectangle( + {{0, 104}, {240, 72}}, + Color::grey() + ); + } +} + void HandWriteView::guess_letter() { uint8_t symbol, match, count, stroke_idx, stroke_data; Condition cond; Direction dir; bool matched; - // Clear drawing zone - display.fill_rectangle( - {{0, 16}, {240, 240}}, - Color::black() - ); - // Letter guessing - if (move_index) { - for (symbol = 0; symbol < handwriting_unistroke.letter_count; symbol++) { - count = handwriting_unistroke.letter[symbol].count; + if (stroke_index) { + for (symbol = 0; symbol < handwriting->letter_count; symbol++) { + count = handwriting->letter[symbol].count; matched = false; if (count) { // We have a count match to do - if ((count == 1) && (move_index == 1)) matched = true; - if ((count == 2) && (move_index == 2)) matched = true; - if ((count == 3) && (move_index > 2)) matched = true; + if ((count == 1) && (stroke_index == 1)) matched = true; + if ((count == 2) && (stroke_index == 2)) matched = true; + if ((count == 3) && (stroke_index > 2)) matched = true; } else { matched = true; } if (matched) { for (match = 0; match < 3; match++) { - cond = handwriting_unistroke.letter[symbol].match[match].cond; - dir = handwriting_unistroke.letter[symbol].match[match].dir; + cond = handwriting->letter[symbol].match[match].cond; + dir = handwriting->letter[symbol].match[match].dir; if ((cond != cond_empty) && (dir != dir_empty)) { if (cond == last) { - if (move_index) - stroke_idx = move_index - 1; + if (stroke_index) + stroke_idx = stroke_index - 1; else stroke_idx = 0; } else if (cond == stroke_a) @@ -160,7 +198,8 @@ void HandWriteView::guess_letter() { stroke_idx = 2; else stroke_idx = 3; - stroke_data = move_list[stroke_idx]; + if (stroke_idx >= stroke_index) break; + stroke_data = stroke_list[stroke_idx]; if ((dir & 0xF0) == 0xF0) { if ((dir & 0x0F) != (stroke_data & 0x0F)) break; } else if ((dir & 0x0F) == 0x0F) { @@ -177,22 +216,36 @@ void HandWriteView::guess_letter() { } } if (matched) { - if (symbol) - txtinput[txtidx++] = 'A' + symbol - 1; - else - txtinput[--txtidx] = 0; // Erase + if (symbol) { + if (_lowercase) + char_add('a' + symbol - 1); + else + char_add('A' + symbol - 1); + clear_zone(Color::green(), true); // Green flash + } else { + if (txtidx) { + txtinput[--txtidx] = 0; // Erase + clear_zone(Color::yellow(), true); // Yellow flash + } else { + clear_zone(Color::red(), true); // Red flash + } + } + } else { + clear_zone(Color::red(), true); // Red flash } } else { + // Short tap is space txtinput[txtidx++] = ' '; + clear_zone(Color::green(), true); // Green flash } update_text(); - move_index = 0; + stroke_index = 0; } void HandWriteView::add_stroke(uint8_t dir) { - if (move_index < 8) { - move_list[move_index] = dir; - move_index++; + if (stroke_index < 8) { + stroke_list[stroke_index] = dir; + stroke_index++; } else { guess_letter(); } @@ -200,18 +253,18 @@ void HandWriteView::add_stroke(uint8_t dir) { void HandWriteView::sample_pen() { int16_t diff_x, diff_y; - uint8_t dir, dir_ud, dir_lr; + uint8_t dir, dir_ud, dir_lr, stroke_prev; // Blink cursor if (!(sample_skip & 15)) { Point cursor_pos; cursor_pos.x = text_input.screen_rect().pos.x + (txtidx * 8); - cursor_pos.y = text_input.screen_rect().pos.y + 17; + cursor_pos.y = text_input.screen_rect().pos.y + 16 - 4; if (cursor) { display.fill_rectangle( - {{text_input.screen_rect().pos.x, cursor_pos.y}, {text_input.screen_rect().size.w, 4}}, + {cursor_pos, {text_input.screen_rect().size.w - cursor_pos.x, 4}}, Color::black() ); } else { @@ -223,17 +276,19 @@ void HandWriteView::sample_pen() { cursor = !cursor; } + if (flash_timer) { + if (flash_timer == 1) clear_zone(Color::black(), false); + flash_timer--; + } + if (!(sample_skip & 1)) { if (tracing) { if (move_wait) { - move_wait--; // ~133ms delay + move_wait--; // ~100ms delay to get rid of jitter from touch start } else { diff_x = current_pos.x - last_pos.x; diff_y = current_pos.y - last_pos.y; - - text_debug_x.set(to_string_dec_int(diff_x)); - text_debug_y.set(to_string_dec_int(diff_y)); - + if (current_pos.y <= 240) { display.fill_rectangle( {{current_pos.x, current_pos.y}, {4, 4}}, @@ -241,7 +296,7 @@ void HandWriteView::sample_pen() { ); } - dir = 0; + dir = 0; // UL by default if (abs(diff_x) > 7) { if (diff_x > 0) dir |= 0x01; // R @@ -255,41 +310,48 @@ void HandWriteView::sample_pen() { dir |= 0x20; // ? } + // Need at least two identical directions to validate stroke if ((dir & 0x11) == (dir_prev & 0x11)) dir_cnt++; else dir_cnt = 0; dir_prev = dir; - // text_debug_d.set(to_string_dec_uint(dir)); - if (dir_cnt > 1) { dir_cnt = 0; - if (move_index) { - if ((move_list[move_index - 1] != dir) && (dir != 0x22)) { + if (stroke_index) { + if ((stroke_list[stroke_index - 1] != dir) && (dir != 0x22)) { + // Register stroke if different from last one dir_ud = (dir & 0xF0); dir_lr = (dir & 0x0F); + stroke_prev = stroke_list[stroke_index - 1]; if (dir_ud == 0x20) { - if ((move_list[move_index - 1] & 0x0F) != dir_lr) add_stroke(dir); + // LR changed + if ((stroke_prev & 0x0F) != dir_lr) add_stroke(dir); } else if (dir_lr == 0x02) { - if ((move_list[move_index - 1] & 0xF0) != dir_ud) add_stroke(dir); + // UD changed + if ((stroke_prev & 0xF0) != dir_ud) add_stroke(dir); } else { - // Replacement ? - if (((move_list[move_index - 1] & 0xF0) == 0x20) && (dir_ud != 0x20)) { - if ((move_list[move_index - 1] & 0x0F) == dir_lr) { - move_list[move_index - 1] = dir; - } else if ((dir & 0x0F) == 0x02) { - // Merge - move_list[move_index - 1] = dir_ud | (move_list[move_index - 1] & 0x0F); + // Add direction + if (((stroke_prev & 0xF0) == 0x20) && (dir_ud != 0x20)) { + // Add UD + if ((stroke_prev & 0x0F) == dir_lr) { + // Replace totally + stroke_list[stroke_index - 1] = dir; + } else if (dir_lr == 0x02) { + // Merge UD + stroke_list[stroke_index - 1] = dir_ud | (stroke_prev & 0x0F); } else { add_stroke(dir); } - } else if (((move_list[move_index - 1] & 0x0F) == 0x02) && (dir_lr != 0x02)) { - if ((move_list[move_index - 1] & 0xF0) == dir_ud) { - move_list[move_index - 1] = dir; + } else if (((stroke_prev & 0x0F) == 0x02) && (dir_lr != 0x02)) { + // Add LR + if ((stroke_prev & 0xF0) == dir_ud) { + // Replace totally + stroke_list[stroke_index - 1] = dir; } else if (dir_ud == 0x20) { - // Merge - move_list[move_index - 1] = dir_lr | (move_list[move_index - 1] & 0xF0); + // Merge LR + stroke_list[stroke_index - 1] = dir_lr | (stroke_prev & 0xF0); } else { add_stroke(dir); } @@ -299,6 +361,7 @@ void HandWriteView::sample_pen() { } } } else { + // Register first stroke if (dir != 0x22) add_stroke(dir); } } @@ -319,6 +382,7 @@ void HandWriteView::on_show() { sample_pen(); } ); + clear_zone(Color::black(), false); } char * HandWriteView::value() { @@ -326,7 +390,7 @@ char * HandWriteView::value() { } void HandWriteView::on_button(Button& button) { - char_add(button.id + 0x30); + char_add(button.id); update_text(); } diff --git a/firmware/application/ui_handwrite.hpp b/firmware/application/ui_handwrite.hpp index 46e9b0365..29add26c3 100644 --- a/firmware/application/ui_handwrite.hpp +++ b/firmware/application/ui_handwrite.hpp @@ -25,10 +25,8 @@ #include "ui_painter.hpp" #include "ui_menu.hpp" #include "ui_navigation.hpp" -#include "ui_font_fixed_8x16.hpp" -#include "clock_manager.hpp" +#include "unistroke.hpp" #include "message.hpp" -#include "signal.hpp" namespace ui { @@ -38,6 +36,7 @@ public: HandWriteView(NavigationView& nav, char txt[], uint8_t max_len); + void paint(Painter& painter) override; void on_show() override; bool on_touch(const TouchEvent event) override; @@ -46,44 +45,41 @@ public: void char_add(const char c); private: + const HandWriting * handwriting; + Painter * _painter; uint8_t _max_len; uint8_t dir_cnt = 0; uint8_t dir_prev; - uint8_t txtidx; + uint8_t flash_timer = 0; + uint8_t txtidx = 0; bool cursor = false; bool tracing = false; - uint8_t move_index; + uint8_t stroke_index; uint8_t sample_skip, move_wait; - uint8_t move_list[8]; + uint8_t stroke_list[8]; Point start_pos, current_pos, last_pos; - bool _lowercase = false; - static constexpr size_t button_w = 240 / 5; - static constexpr size_t button_h = 28; + bool _lowercase = true; char txtinput[25] = {0}; void sample_pen(); void add_stroke(uint8_t dir); void guess_letter(); + void clear_zone(Color color, bool flash); Text text_input { { 8, 0, 224, 16 } }; - Text text_debug_x { - { 0, 16, 32, 16 } - }; - Text text_debug_y { - { 0, 32, 32, 16 } - }; std::array num_buttons; + std::array special_buttons; Button button_case { - { 88+64+16, 270, 32, 24 }, + { 8, 270, 32, 28 }, "UC" }; - Button button_done { - { 88, 270, 64, 24 }, - "Done" + Button button_ok { + { 190, 270, 40, 28 }, + "OK" }; void on_button(Button& button); diff --git a/firmware/application/ui_loadmodule.cpp b/firmware/application/ui_loadmodule.cpp index b045bee26..c6525ed69 100644 --- a/firmware/application/ui_loadmodule.cpp +++ b/firmware/application/ui_loadmodule.cpp @@ -172,6 +172,7 @@ LoadModuleView::LoadModuleView( if (ViewID == 1) nav.push(); if (ViewID == 2) nav.push(); if (ViewID == 3) nav.push(); + if (ViewID == 10) nav.push(); } else { nav.pop(); diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 0a7133e49..f0712098f 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -174,8 +174,6 @@ TranspondersMenuView::TranspondersMenuView(NavigationView& nav) { ReceiverMenuView::ReceiverMenuView(NavigationView& nav) { add_items<2>({ { { "Audio", ui::Color::white(), [&nav](){ nav.push(md5_baseband, 10, true); } }, - - //{ "Audio", ui::Color::white(), [&nav](){ nav.push(); } }, { "Transponders", ui::Color::white(), [&nav](){ nav.push(); } }, } }); on_left = [&nav](){ nav.pop(); }; @@ -199,9 +197,8 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { { "HackRF", ui::Color::white(), [&nav](){ nav.push(); } }, } }); -/* //{ "Nordic/BTLE RX", ui::Color::cyan(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, - { "Jammer", ui::Color::white(), [&nav](){ nav.push(md5_baseband, new JammerView(nav)); } }, + //{ "Jammer", ui::Color::white(), [&nav](){ nav.push(md5_baseband, new JammerView(nav)); } }, //{ "Audio file TX", ui::Color::white(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, //{ "Encoder TX", ui::Color::green(), [&nav](){ nav.push(new NotImplementedView { nav }); } }, //{ "Whistle", ui::Color::purple(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new WhistleView { nav, transmitter_model }}); } }, @@ -209,7 +206,7 @@ SystemMenuView::SystemMenuView(NavigationView& nav) { //{ "Xylos RX", ui::Color::green(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new XylosRXView { nav, receiver_model }}); } }, //{ "AFSK RX", ui::Color::cyan(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband, new AFSKRXView { nav, receiver_model }}); } }, //{ "Numbers station", ui::Color::purple(), [&nav](){ nav.push(new LoadModuleView { nav, md5_baseband_tx, new NumbersStationView { nav, transmitter_model }}); } }, -*/ + } /* SystemView ************************************************************/ @@ -227,6 +224,8 @@ SystemView::SystemView( context_(context) { set_style(&style_default); + + char debugtxt[21]; // DEBUG constexpr ui::Dim status_view_height = 16; diff --git a/firmware/application/unistroke.hpp b/firmware/application/unistroke.hpp index 03eb61619..a654f541d 100644 --- a/firmware/application/unistroke.hpp +++ b/firmware/application/unistroke.hpp @@ -31,15 +31,15 @@ enum Condition { enum Direction { dir_empty = -1, - Uw = 0x0F, // 0x - Dw = 0x1F, // 1x - Lw = 0xF0, // x0 - Rw = 0xF1, // x1 - U = 0x02, + Uw = 0x0F, // Wildcards + Dw = 0x1F, + Lw = 0xF0, + Rw = 0xF1, + U = 0x02, // Orthos D = 0x12, L = 0x20, R = 0x21, - UL = 0x00, + UL = 0x00, // Diagonals DL = 0x10, UR = 0x01, DR = 0x11 diff --git a/firmware/portapack-h1-firmware.bin b/firmware/portapack-h1-firmware.bin index d131f1db6..adaf61ac2 100644 Binary files a/firmware/portapack-h1-firmware.bin and b/firmware/portapack-h1-firmware.bin differ