From f89d602c057c174531f817e87326da84303c113d Mon Sep 17 00:00:00 2001 From: Timothy Yin Date: Mon, 20 Apr 2026 01:22:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(firmware):=20=E4=BC=98=E5=8C=96=E5=88=B7?= =?UTF-8?q?=E5=8D=A1=E7=8A=B6=E6=80=81=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hardware/firmware/src/main.cpp | 121 ++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/hardware/firmware/src/main.cpp b/hardware/firmware/src/main.cpp index fabe211..1f49a57 100644 --- a/hardware/firmware/src/main.cpp +++ b/hardware/firmware/src/main.cpp @@ -119,6 +119,15 @@ static IM1281CAData s_meter_a; static IM1281CBData s_meter_b; static bool s_meter_data_ready = false; static bool s_oled_ready = false; +static String s_oled_card_id; +static unsigned long s_oled_card_started_at_ms = 0; +static unsigned long s_oled_card_duration_ms = 0; +static String s_oled_msg_title; +static String s_oled_msg_line1; +static String s_oled_msg_line2; +static unsigned long s_oled_msg_started_at_ms = 0; +static unsigned long s_oled_msg_duration_ms = 0; +static bool s_oled_msg_alert = false; static const char *ledStageText(LEDState state) { @@ -203,6 +212,33 @@ static unsigned int getWaitHintConnectorId() return 0; } +static void showOledCard(const String &idTag, unsigned long durationMs = CARD_ID_DISPLAY_MS) +{ + s_oled_card_id = idTag; + s_oled_card_started_at_ms = millis(); + s_oled_card_duration_ms = durationMs; +} + +static bool isOledCardVisible() +{ + return s_oled_card_id.length() > 0 && (millis() - s_oled_card_started_at_ms) <= s_oled_card_duration_ms; +} + +static void showOledMessage(const String &title, const String &line1 = String(), const String &line2 = String(), unsigned long durationMs = 2500, bool alert = false) +{ + s_oled_msg_title = title; + s_oled_msg_line1 = line1; + s_oled_msg_line2 = line2; + s_oled_msg_started_at_ms = millis(); + s_oled_msg_duration_ms = durationMs; + s_oled_msg_alert = alert; +} + +static bool isOledMessageVisible() +{ + return s_oled_msg_title.length() > 0 && (millis() - s_oled_msg_started_at_ms) <= s_oled_msg_duration_ms; +} + static int energyKwhToWh(float energyKwh) { if (energyKwh <= 0.0f) @@ -257,14 +293,78 @@ static void refreshOled() const bool c2_chg = ocppPermitsCharge(2); const ChargePointStatus st1 = getChargePointStatus(1); const ChargePointStatus st2 = getChargePointStatus(2); - const bool show_card = s_last_swipe_id.length() > 0 && (now - s_last_swipe_at_ms) <= CARD_ID_DISPLAY_MS; + const bool show_message = isOledMessageVisible(); + const bool show_card = !show_message && isOledCardVisible(); display.clearDisplay(); display.setTextColor(SSD1306_WHITE); + display.setTextWrap(false); + + if (show_message) + { + String title = s_oled_msg_title; + String line1 = s_oled_msg_line1; + String line2 = s_oled_msg_line2; + + if (s_oled_msg_alert) + { + const uint8_t alertTitleSize = (title.length() <= 10) ? 2 : 1; + const int16_t alertTitleY = (alertTitleSize == 2) ? 6 : 10; + if (title.length() > 21) + { + title = title.substring(0, 21); + } + if (line1.length() > 14) + { + line1 = line1.substring(0, 14); + } + if (line2.length() > 14) + { + line2 = line2.substring(0, 14); + } + + drawCenteredText(title, alertTitleY, alertTitleSize); + if (line1.length() > 0) + { + drawCenteredText(line1, 30, 1); + } + if (line2.length() > 0) + { + drawCenteredText(line2, 44, 1); + } + display.display(); + return; + } + + if (title.length() > 14) + { + title = title.substring(0, 14); + } + if (line1.length() > 16) + { + line1 = line1.substring(0, 16); + } + if (line2.length() > 16) + { + line2 = line2.substring(0, 16); + } + + drawCenteredText(title, 6, 2); + if (line1.length() > 0) + { + drawCenteredText(line1, 30, 1); + } + if (line2.length() > 0) + { + drawCenteredText(line2, 44, 1); + } + display.display(); + return; + } if (show_card) { - String shownId = s_last_swipe_id; + String shownId = s_oled_card_id; if (shownId.length() > 12) { shownId = shownId.substring(shownId.length() - 12); @@ -508,6 +608,7 @@ static void requestAuthorizeByCard(const String &idTag) } clearAuthWait("new card swiped"); + showOledCard(idTag); s_auth_in_progress = true; Serial.printf("[main] Authorize idTag: %s\n", idTag.c_str()); @@ -523,6 +624,7 @@ static void requestAuthorizeByCard(const String &idTag) s_auth_ok_at_ms = millis(); s_auth_id_tag = idTag; Serial.printf("[main] Authorize accepted for idTag %s\n", idTag.c_str()); + showOledMessage("AUTH OK", "Swipe ready", String("ID ") + idTag.substring(max(0, (int)idTag.length() - 10)), 2200, false); // Check if there's already a connector plugged in; if so, start immediately unsigned int targetConnector = 0; @@ -543,6 +645,11 @@ static void requestAuthorizeByCard(const String &idTag) if (tx != nullptr) { clearAuthWait("transaction started"); + showOledMessage("START OK", String("C") + String(targetConnector), "Charging", 2200, false); + } + else + { + showOledMessage("START FAIL", String("C") + String(targetConnector), "Busy/Not Ready", 2500, true); } } // Otherwise, wait for a connector to be plugged in @@ -551,6 +658,7 @@ static void requestAuthorizeByCard(const String &idTag) { clearAuthWait("authorize rejected"); Serial.printf("[main] Authorize rejected, status=%s\n", status); + showOledMessage("AUTH FAIL", status, "Try again", 2500, true); } }, []() @@ -558,6 +666,7 @@ static void requestAuthorizeByCard(const String &idTag) s_auth_in_progress = false; clearAuthWait("authorize aborted"); Serial.println("[main] Authorize aborted"); + showOledMessage("AUTH ABORT", "Swipe again", String(), 1800, true); }); } @@ -863,12 +972,14 @@ void setup() h1, h2, + showOledMessage("STOP", "C1 unplugged", "EVDisconnected", 2500, true); h3, h4 { color: #111827; margin-top: 0; text-align: center; } + showOledMessage("STOP", "C2 unplugged", "EVDisconnected", 2500, true); label { display: block; @@ -1130,6 +1241,7 @@ void setup() if (targetConnector == 0) { + showOledMessage("REMOTE REJ", "No idle plug", "or not ready", 2500, true); return; } @@ -1138,6 +1250,11 @@ void setup() if (s_remote_start_accepted) { Serial.printf("[main] Remote start accepted on connector %u\n", targetConnector); + showOledMessage("REMOTE OK", String("C") + String(targetConnector), "Charging", 2200, false); + } + else + { + showOledMessage("REMOTE REJ", String("C") + String(targetConnector), "Busy/Not Ready", 2500, true); } }, []() -> std::unique_ptr