From 2e1fc5da9113fc97fd07656c2be6b9fde8086c4e Mon Sep 17 00:00:00 2001 From: Mau Abata Date: Thu, 2 Sep 2021 18:37:32 -0500 Subject: [PATCH] Finalize Home UI, start support for menu. --- include/pressure_manager.hpp | 3 + include/ui.hpp | 8 +- include/ui/menu.hpp | 45 +++++++++ lib/m1k-hal-dist | 2 +- src/main.cpp | 9 +- src/pages/home.cpp | 180 +++++++++++++++++++++++------------ src/pressure_manager.cpp | 39 ++++++-- src/tscode_manager.cpp | 11 ++- src/ui.cpp | 26 ++++- src/ui/page.cpp | 2 + src/version.cpp | 2 +- 11 files changed, 242 insertions(+), 85 deletions(-) create mode 100644 include/ui/menu.hpp diff --git a/include/pressure_manager.hpp b/include/pressure_manager.hpp index 45aba01..da33924 100644 --- a/include/pressure_manager.hpp +++ b/include/pressure_manager.hpp @@ -22,5 +22,8 @@ double pressure_manager_get_mean(void); void pressure_manager_set_target_mean(double mean); double pressure_manager_get_target_mean(void); pressure_manager_seek_status_t pressure_manager_get_seek_status(void); +void pressure_manager_request_stop(void); +void pressure_manager_cancel_stop_request(void); +bool pressure_manager_is_stop_requested(void); #endif \ No newline at end of file diff --git a/include/ui.hpp b/include/ui.hpp index 974d563..6ceaaf9 100644 --- a/include/ui.hpp +++ b/include/ui.hpp @@ -2,16 +2,18 @@ #define __ui_manager_hpp #include "ui/page.hpp" +#include "ui/menu.hpp" #include "pages.hpp" void ui_init(void); void ui_open_page(UI::Page *page); -//void ui_open_menu(UI::Menu *menu); -//void ui_close_menu(void); -//void ui_toast(const char *msg); +void ui_open_menu(UI::Menu *menu); +void ui_close_menu(void); +void ui_toast(const char *msg); void ui_tick(void); void ui_handle_click(m1k_hal_button_t button, m1k_hal_button_evt_t evt); void ui_handle_encoder(int difference); +void ui_render_static(m1k_hal_display_t* display); #endif \ No newline at end of file diff --git a/include/ui/menu.hpp b/include/ui/menu.hpp new file mode 100644 index 0000000..747e9f6 --- /dev/null +++ b/include/ui/menu.hpp @@ -0,0 +1,45 @@ +#ifndef __ui_menu_hpp +#define __ui_menu_hpp + +#include "m1k-hal.hpp" + +namespace UI { + class Menu; + + typedef void (*menu_event_cb)(Menu *p); + typedef void (*menu_render_cb)(m1k_hal_display_t *display, Menu *p); + typedef void (*menu_encoder_cb)(int difference, Menu *p); + typedef void (*menu_button_cb)(m1k_hal_button_t button, m1k_hal_button_evt_t evt, Menu *p); + + struct menu_config { + menu_event_cb enter_cb; + menu_render_cb render_cb; + menu_event_cb loop_cb; + menu_event_cb exit_cb; + menu_button_cb button_cb; + menu_encoder_cb encoder_cb; + }; + + typedef struct menu_config menu_config_t; + + /** + * This literally just delegates calls to the struct. I could almost certainly just + * remove this whole thing and use a struct directly. I'm searching for syntax sugar. + */ + class Menu { + public: + Menu(menu_config_t *cfg) : config(cfg) {}; + + void enter(void); + void render(void); + void loop(void); + void exit(void); + void on_click(m1k_hal_button_t button, m1k_hal_button_evt_t evt); + void on_encoder(int); + + private: + menu_config_t *config; + }; +} + +#endif \ No newline at end of file diff --git a/lib/m1k-hal-dist b/lib/m1k-hal-dist index f7c5cf5..f528d78 160000 --- a/lib/m1k-hal-dist +++ b/lib/m1k-hal-dist @@ -1 +1 @@ -Subproject commit f7c5cf5c9662ec1ac02649cb6650a7fd64e5f338 +Subproject commit f528d78eec5828e03d34da7ec317695506dd4ab4 diff --git a/src/main.cpp b/src/main.cpp index 2b0a01f..ce49da1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,8 +11,6 @@ TaskHandle_t PressureMgrTask; void pressure_mgr_task(void *param); void setup() { - Serial.begin(115200); - m1k_hal_init(); ui_init(); tscode_manager_init(); @@ -27,10 +25,9 @@ void setup() { 0 ); - Serial.println("Maus-Tec Electronics Presents:"); - Serial.println("Mercury 1000"); - Serial.print("m1k-hal version: "); - Serial.println(m1k_hal_get_version()); + printf("Maus-Tec Electronics Presents:\n"); + printf("Mercury 1000\n"); + printf("m1k-hal version: %s\n", m1k_hal_get_version()); ui_open_page(&Pages::Splash); } diff --git a/src/pages/home.cpp b/src/pages/home.cpp index a46201f..3d90390 100644 --- a/src/pages/home.cpp +++ b/src/pages/home.cpp @@ -30,16 +30,22 @@ static struct { double frequency = 0; double peak_max = 0; double peak_min = 0; + bool stop_requested = false; current_control_item_t ctrl_item = HOME_CONTROL_ITEM_SPEED; + m1k_hal_air_direction_t air_direction = M1K_HAL_AIR_CLOSED; + long last_icon_ms = 0; + long icon_step_ms = 0; } state; static int _speed_count = 20; -static graphics_image_t* MILKER_ICONS[4] = { +static graphics_image_t* MILKER_ICONS[6] = { &MILKER_ICON_0, &MILKER_ICON_1, &MILKER_ICON_2, &MILKER_ICON_3, + &MILKER_ICON_2, + &MILKER_ICON_1, }; // label top = 0, bototm = 4 @@ -57,6 +63,18 @@ static void draw_pressure_graph(m1k_hal_display_t* display, int min, int max, in value = max; } + if (lmark < min) { + lmark = min; + } else if (lmark > max) { + lmark = max; + } + + if (rmark < min) { + rmark = min; + } else if (rmark > max) { + rmark = max; + } + // Down Arrow display->drawVLine(left + 2, top, 4); display->drawTriangle(left, top + 4, left + 5, top + 4, left + 2, top + 7); @@ -78,6 +96,23 @@ static void draw_pressure_graph(m1k_hal_display_t* display, int min, int max, in display->drawBox(bar_center_x, top + 2, fill_width + 1, 3); } + if (lmark < 0) { + double fill_width = floor(abs((double) lmark / min) * fill_space); + display->drawBox(bar_center_x - fill_width, top + 1, 1, 5); + } else { + double fill_width = floor(abs((double) lmark / max) * fill_space); + display->drawBox(bar_center_x + (fill_width - 1), top + 1, 1, 5); + } + + if (rmark < 0) { + double fill_width = floor(abs((double) rmark / min) * fill_space); + display->drawBox(bar_center_x - fill_width, top + 1, 1, 5); + } else { + double fill_width = floor(abs((double) rmark / max) * fill_space); + display->drawBox(bar_center_x + (fill_width - 1), top + 1, 1, 5); + } + + // Up Arrow auto rtri_left = left + width - 7; display->drawVLine(rtri_left + 2, top + 3, 4); @@ -106,21 +141,40 @@ static void draw_speed(m1k_hal_display_t* display, int speed, bool selected) { auto center = left + width / 2; display->setFont(u8g2_font_4x6_mf); - const char* label = "SPEED"; + char* label = "SPEED"; auto label_width = display->getStrWidth(label); display->drawStr(center - floor(label_width / 2), 5, label); - display->setFont(u8g2_font_7x14B_tn); + display->setFont(u8g2_font_7x14B_tf); + + if (speed > _speed_count && !state.stop_requested) { + speed = _speed_count; + display->drawStr(center + 9, 15, "+"); + } + char value[4] = ""; - snprintf(value, 4, "%d", speed); + + if (state.stop_requested) { + value[0] = 'S'; + value[1] = '\0'; + } else { + snprintf(value, 4, "%d", state.stop_requested ? 0 : speed); + } + auto value_width = display->getStrWidth(value); display->drawStr(center - floor(value_width / 2) - 1, 17, value); if (selected) { int triangle_top = 9; int triangle_tip = 10; - display->drawTriangle(center - triangle_tip, triangle_top, center - triangle_tip, triangle_top + 6, center - (triangle_tip + 3), triangle_top + 3); - display->drawTriangle(center + triangle_tip - 1, triangle_top, center + triangle_tip - 1, triangle_top + 6, center + (triangle_tip + 2), triangle_top + 3); + + if (speed > 0 && !state.stop_requested) { + display->drawTriangle(center - triangle_tip, triangle_top, center - triangle_tip, triangle_top + 6, center - (triangle_tip + 3), triangle_top + 3); + } + + if (speed < _speed_count) { + display->drawTriangle(center + triangle_tip - 1, triangle_top, center + triangle_tip - 1, triangle_top + 6, center + (triangle_tip + 2), triangle_top + 3); + } } } @@ -132,15 +186,25 @@ static void draw_depth(m1k_hal_display_t* display, int pressure_delta, bool sele auto label_width = display->getStrWidth(label); display->drawStr(left + 5, 5, label); - const int plus_minus_top = 10; - display->drawLine(left + 1, plus_minus_top, left + 1, plus_minus_top + 2); - display->drawLine(left, plus_minus_top + 1, left + 2, plus_minus_top + 1); - display->drawLine(left, plus_minus_top + 5, left + 2, plus_minus_top + 5); + if (state.air_direction == M1K_HAL_AIR_CLOSED) { + const int plus_minus_top = 10; + display->drawLine(left + 1, plus_minus_top, left + 1, plus_minus_top + 2); + display->drawLine(left, plus_minus_top + 1, left + 2, plus_minus_top + 1); + display->drawLine(left, plus_minus_top + 5, left + 2, plus_minus_top + 5); + } - display->setFont(u8g2_font_7x14B_tn); + display->setFont(u8g2_font_7x14B_tf); const int value_center = left + (label_width / 2) + 5; char value[4] = ""; - snprintf(value, 4, "%d", pressure_delta); + + if (state.air_direction == M1K_HAL_AIR_CLOSED) { + snprintf(value, 4, "%d", pressure_delta); + } else if (state.air_direction == M1K_HAL_AIR_OUT) { + strncpy(value, "OUT", 4); + } else { + strncpy(value, "IN", 4); + } + int value_width = display->getStrWidth(value); display->drawStr(value_center - floor(value_width / 2) - 1, 17, value); } @@ -179,6 +243,22 @@ static void render(m1k_hal_display_t* display, Page* page) { draw_frequency(display, state.frequency); } +static int get_speed(void) { + return sqrt(m1k_hal_get_milker_speed()) / 0.6; +} + +static void set_speed(int speed) { + if (speed == 0) { + pressure_manager_request_stop(); + state.stop_requested = true; + } else { + state.stop_requested = false; + pressure_manager_cancel_stop_request(); + m1k_hal_set_milker_speed(speed); + m1k_hal_hv_power_on(); + } +} + static void loop(Page* page) { long ms = esp_timer_get_time() / 1000; @@ -188,60 +268,38 @@ static void loop(Page* page) { state.frequency = pressure_manager_get_frequency(); state.peak_max = pressure_manager_get_max_peak(); state.peak_min = pressure_manager_get_min_peak(); + state.icon_step = fmin(4.0, fmax(0.0, (m1k_hal_get_pressure_reading() + 25.0) / 10.0)); + state.stop_requested = pressure_manager_is_stop_requested(); + state.speed = get_speed(); + state.air_direction = m1k_hal_air_get_direction(); page->render(); } } static void exit(Page* page) { - state.speed = 0; - ESP_LOGD(TAG, "HOME EXIT"); + set_speed(0x00); } static void enter(Page* page) { - state.speed = 0; - ESP_LOGD(TAG, "HOME ENTER"); -} - -static void set_speed(int speed) { - if (speed == 0) { - // pressure_manager_soft_stop(); - m1k_hal_set_milker_speed(speed); - m1k_hal_hv_power_off(); - } else { - m1k_hal_set_milker_speed(speed); - m1k_hal_hv_power_on(); - } + state.speed = m1k_hal_get_milker_speed(); } static void encoder_change(int difference, Page* page) { switch (state.ctrl_item) { - case HOME_CONTROL_ITEM_PRESSURE: - { - auto direction = m1k_hal_air_get_direction(); - if (difference < 0) { - if (direction == M1K_HAL_AIR_IN || direction == M1K_HAL_AIR_CHAOS) { - m1k_hal_air_stop(); - } else { - m1k_hal_air_out(); - } - } else { - if (direction == M1K_HAL_AIR_OUT || direction == M1K_HAL_AIR_CHAOS) { - m1k_hal_air_stop(); - } else { - m1k_hal_air_in(); - } - } - } break; case HOME_CONTROL_ITEM_SPEED: - default: - state.speed += difference; - if (state.speed < 1) state.speed = 0; - if (state.speed > _speed_count) state.speed = _speed_count; - - int speed = ceil(pow(state.speed * 0.6, 2)); - set_speed(speed); + default: { + if (!state.stop_requested || difference >= 0) { + state.speed += difference; + if (state.speed < 1) state.speed = 0; + if (state.speed > _speed_count) state.speed = _speed_count; + + int speed = ceil(pow(state.speed * 0.6, 2)); + ESP_LOGE(TAG, "Set speed: %d", speed); + set_speed(speed); + } break; + } } page->render(); @@ -258,33 +316,37 @@ static void on_button(m1k_hal_button_t button, m1k_hal_button_evt_t evt, Page *p } else { state.last_click_ms = ms; - switch (state.ctrl_item) { - case HOME_CONTROL_ITEM_PRESSURE: - state.ctrl_item = HOME_CONTROL_ITEM_SPEED; - break; - case HOME_CONTROL_ITEM_SPEED: - default: - state.ctrl_item = HOME_CONTROL_ITEM_PRESSURE; - } + // switch (state.ctrl_item) { + // case HOME_CONTROL_ITEM_PRESSURE: + // state.ctrl_item = HOME_CONTROL_ITEM_SPEED; + // break; + // case HOME_CONTROL_ITEM_SPEED: + // default: + // state.ctrl_item = HOME_CONTROL_ITEM_PRESSURE; + // } } } if (button == M1K_HAL_BUTTON_AIRIN) { if (evt == M1K_HAL_BUTTON_EVT_DOWN) { + ESP_LOGE(TAG, "AIR IN"); m1k_hal_air_in(); } if (evt == M1K_HAL_BUTTON_EVT_UP) { + ESP_LOGE(TAG, "AIR STOP"); m1k_hal_air_stop(); } } if (button == M1K_HAL_BUTTON_AIROUT) { if (evt == M1K_HAL_BUTTON_EVT_DOWN) { + ESP_LOGE(TAG, "AIR OUT"); m1k_hal_air_out(); } if (evt == M1K_HAL_BUTTON_EVT_UP) { + ESP_LOGE(TAG, "AIR STOP"); m1k_hal_air_stop(); } } diff --git a/src/pressure_manager.cpp b/src/pressure_manager.cpp index d9fff60..7564755 100644 --- a/src/pressure_manager.cpp +++ b/src/pressure_manager.cpp @@ -2,11 +2,14 @@ #include "m1k-hal.hpp" #include "esp_log.h" #include "average.hpp" +#include "esp_log.h" #define UPDATE_FREQUENCY_MS 10 #define LAST_VALUE_COUNT (2 * (1000 / UPDATE_FREQUENCY_MS)) #define PEAK_AVERAGE_COUNT 3 +#define IDLE_SPEED 0x0A + static const char* TAG = "PRESSURE_MANAGER"; static const double pk_threshold = 1.5; static const long pk_expiry_ms = 3000L; @@ -23,6 +26,8 @@ static long _low_peak_ms = 0; static long _high_peak_ms = 0; static long _pk_pk_ms = 0; +static bool _stop_requested = false; + void pressure_manager_tick(void) { long ms = esp_timer_get_time() / 1000; if (ms - _last_update_ms < UPDATE_FREQUENCY_MS) { @@ -51,6 +56,13 @@ void pressure_manager_tick(void) { _rising = true; _low_peak_ms = ms; min_peak.insert(_local_peak, ms); + + if (_stop_requested) { + ESP_LOGE(TAG, "Finalizing stop request."); + _stop_requested = false; + m1k_hal_set_milker_speed(0x00); + m1k_hal_hv_power_off(); + } } else { // possibly in a peak } @@ -63,19 +75,11 @@ void pressure_manager_tick(void) { _high_peak_ms = 0; _local_peak = 1000; _rising = false; + _stop_requested = false; _pk_pk_ms = 0; min_peak.clear(); max_peak.clear(); } - - if (true) { - Serial.printf("%.2f,%.1f,%.1f,%.1f\n", - pressure, - pressure_manager_get_frequency(), - pressure_manager_get_min_peak(), - pressure_manager_get_max_peak() - ); - } } double pressure_manager_get_min_peak(void) { @@ -97,4 +101,21 @@ double pressure_manager_get_frequency(void) { double pressure_manager_get_mean(void) { return min_peak.avg() + (pressure_manager_get_amplitude() / 2); +} + +void pressure_manager_request_stop(void) { + ESP_LOGE(TAG, "Stop requested!"); + if (m1k_hal_hv_is_on()) { + ESP_LOGE(TAG, "Stop requested (Confirm.)"); + _stop_requested = true; + m1k_hal_set_milker_speed(IDLE_SPEED); + } +} + +void pressure_manager_cancel_stop_request(void) { + _stop_requested = false; +} + +bool pressure_manager_is_stop_requested(void) { + return _stop_requested; } \ No newline at end of file diff --git a/src/tscode_manager.cpp b/src/tscode_manager.cpp index a656430..085d246 100644 --- a/src/tscode_manager.cpp +++ b/src/tscode_manager.cpp @@ -1,5 +1,6 @@ #include "tscode_manager.h" #include "tscode_capabilities.h" +#include "pressure_manager.hpp" #include "version.h" #include "m1k-hal.hpp" @@ -57,16 +58,16 @@ tscode_command_response_t tscode_callback(tscode_command_t* cmd, char* response, case TSCODE_RECIPROCATING_MOVE: { uint8_t speed; - if (cmd->speed->unit == TSCODE_UNIT_PERCENTAGE) { + if (cmd->speed == NULL) { + speed = 0; + } else if (cmd->speed->unit == TSCODE_UNIT_PERCENTAGE) { speed = 255.0 * cmd->speed->value; } else { speed = cmd->speed->value; } if (speed == 0) { - // pressure_manager_soft_stop(); - m1k_hal_set_milker_speed(speed); - m1k_hal_hv_power_off(); + pressure_manager_request_stop(); } else { m1k_hal_set_milker_speed(speed); m1k_hal_hv_power_on(); @@ -75,7 +76,7 @@ tscode_command_response_t tscode_callback(tscode_command_t* cmd, char* response, } case TSCODE_CONDITIONAL_STOP: - // pressure_manager_soft_stop(); + pressure_manager_request_stop(); break; case TSCODE_HALT_IMMEDIATE: diff --git a/src/ui.cpp b/src/ui.cpp index 0bfb577..5d549ed 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -2,14 +2,23 @@ #include "m1k-hal.hpp" #include "m1k-hal-strings.hpp" +#include "images/bt_icon_0.h" +#include "images/bt_icon_1.h" +#include "images/rj_icon_0.h" +#include "images/rj_icon_1.h" + static const char* TAG = "UI:MANAGER"; static UI::Page* current_page = nullptr; -// static UI::Menu *current_menu = nullptr; +static UI::Menu *current_menu = nullptr; + +static char* _toast[40]; void ui_init(void) { M1K_HAL_ERRCHK(m1k_hal_register_button_cb(M1K_HAL_BUTTON_ANY, ui_handle_click)); M1K_HAL_ERRCHK(m1k_hal_register_encoder_change(ui_handle_encoder)); + + _toast[0] = '\0'; } void ui_open_page(UI::Page* page) { @@ -21,6 +30,15 @@ void ui_open_page(UI::Page* page) { current_page->enter(); } +void ui_open_menu(UI::Menu* menu) { + if (current_menu != nullptr) { + current_menu->exit(); + } + + current_menu = menu; + current_menu->enter(); +} + void ui_tick(void) { if (current_page != nullptr) { current_page->loop(); @@ -38,3 +56,9 @@ void ui_handle_encoder(int difference) { current_page->on_encoder(difference); } } + +void ui_render_static(m1k_hal_display_t* display) { + int width = m1k_hal_get_display_width(); + graphics_draw_image(width - 8, 0, &RJ_ICON_0); + graphics_draw_image(width - 18, 0, &BT_ICON_1); +} \ No newline at end of file diff --git a/src/ui/page.cpp b/src/ui/page.cpp index 9681904..84e5841 100644 --- a/src/ui/page.cpp +++ b/src/ui/page.cpp @@ -1,5 +1,6 @@ #include "ui/page.hpp" #include "m1k-hal.hpp" +#include "ui.hpp" namespace UI { void Page::enter(void) { @@ -12,6 +13,7 @@ namespace UI { auto display = m1k_hal_get_display_ptr(); display->clearBuffer(); config->render_cb(display, this); + ui_render_static(display); display->sendBuffer(); } } diff --git a/src/version.cpp b/src/version.cpp index c973e1e..d8a7f5b 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -1,2 +1,2 @@ #include "version.h" -const char *VERSION = "v0.1.0+00abcdef"; \ No newline at end of file +const char *VERSION = "v0.0.0"; \ No newline at end of file