diff --git a/.gitignore b/.gitignore index 286ccec3..8651c215 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,7 @@ __pycache__/ # Project build/ +ats-mini/build/ + +.gemini/ +gha-creds-*.json diff --git a/ats-mini/Common.h b/ats-mini/Common.h index b17f8c1c..452cfb2d 100644 --- a/ats-mini/Common.h +++ b/ats-mini/Common.h @@ -170,7 +170,13 @@ extern uint8_t currentMode; extern uint16_t currentCmd; extern uint16_t currentBrt; extern uint16_t currentSleep; +extern uint16_t currentSleepTimer; +extern uint32_t sleepTimerStart; +extern bool sleepTimerMuted; extern uint8_t sleepModeIdx; +extern bool sleepSmart; +extern uint8_t sleepDayStart; +extern uint8_t sleepNightStart; extern bool zoomMenu; extern int8_t scrollDirection; extern uint8_t utcOffsetIdx; @@ -235,6 +241,7 @@ bool ntpSyncTime(); void netRequestConnect(); void netTickTime(); +bool isSleepSmartActive(int &timeoutSeconds); // Remote.c #define REMOTE_CHANGED 1 diff --git a/ats-mini/Draw.cpp b/ats-mini/Draw.cpp index b86e4061..61f71c2e 100644 --- a/ats-mini/Draw.cpp +++ b/ats-mini/Draw.cpp @@ -46,6 +46,28 @@ void drawBleIndicator(int x, int y) } } +// +// Draw Sleep Timer indicator +// +void drawSleepTimerIndicator(int x, int y) +{ + if(currentSleepTimer > 0) + { + uint16_t color = TH.text_muted; + + // Draw Zzz + // Big Z + spr.drawLine(x, y+2, x+6, y+2, color); + spr.drawLine(x+6, y+2, x, y+8, color); + spr.drawLine(x, y+8, x+6, y+8, color); + + // Small z + spr.drawLine(x+8, y+7, x+12, y+7, color); + spr.drawLine(x+12, y+7, x+8, y+11, color); + spr.drawLine(x+8, y+11, x+12, y+11, color); + } +} + // // Draw WiFi indicator // diff --git a/ats-mini/Draw.h b/ats-mini/Draw.h index c5e76f61..e119a1ec 100644 --- a/ats-mini/Draw.h +++ b/ats-mini/Draw.h @@ -31,6 +31,8 @@ #define WIFI_OFFSET_Y 0 // WiFi y offset #define BLE_OFFSET_X 104 // BLE x offset #define BLE_OFFSET_Y 0 // BLE y offset +#define SLEEP_OFFSET_X 120 // Sleep Timer x offset +#define SLEEP_OFFSET_Y 0 // Sleep Timer y offset void drawMessage(const char *msg); void drawZoomedMenu(const char *text, bool force = false); @@ -40,6 +42,7 @@ void drawScreen(const char *statusLine1 = 0, const char *statusLine2 = 0); void drawWiFiIndicator(int x, int y); void drawSaveIndicator(int x, int y); void drawBleIndicator(int x, int y); +void drawSleepTimerIndicator(int x, int y); void drawBandAndMode(const char *band, const char *mode, int x, int y); void drawFrequency(uint32_t freq, int x, int y, int ux, int uy, uint8_t hl); void drawLongStationName(const char *name, int x, int y); diff --git a/ats-mini/Layout-Default.cpp b/ats-mini/Layout-Default.cpp index 7056a4ec..ca9d4bb7 100644 --- a/ats-mini/Layout-Default.cpp +++ b/ats-mini/Layout-Default.cpp @@ -12,6 +12,9 @@ void drawLayoutDefault(const char *statusLine1, const char *statusLine2) // Draw BLE icon drawBleIndicator(BLE_OFFSET_X, BLE_OFFSET_Y); + // Draw Sleep Timer icon + drawSleepTimerIndicator(SLEEP_OFFSET_X, SLEEP_OFFSET_Y); + // Draw battery indicator & voltage bool has_voltage = drawBattery(BATT_OFFSET_X, BATT_OFFSET_Y); diff --git a/ats-mini/Layout-SMeter.cpp b/ats-mini/Layout-SMeter.cpp index 203cd938..4b2fca24 100644 --- a/ats-mini/Layout-SMeter.cpp +++ b/ats-mini/Layout-SMeter.cpp @@ -158,6 +158,9 @@ void drawLayoutSmeter(const char *statusLine1, const char *statusLine2) // Draw BLE icon drawBleIndicator(BLE_OFFSET_X, BLE_OFFSET_Y); + // Draw Sleep Timer icon + drawSleepTimerIndicator(SLEEP_OFFSET_X, SLEEP_OFFSET_Y); + // Draw battery indicator & voltage bool has_voltage = drawBattery(BATT_OFFSET_X, BATT_OFFSET_Y); diff --git a/ats-mini/Menu.cpp b/ats-mini/Menu.cpp index d2cd5329..3298f90b 100644 --- a/ats-mini/Menu.cpp +++ b/ats-mini/Menu.cpp @@ -6,6 +6,8 @@ #include "EIBI.h" #include "BleMode.h" #include "Menu.h" +#include "Storage.h" + // // Bands Menu @@ -95,7 +97,7 @@ static const char *menu[] = "Band", "Volume", "Step", - "Seek", + "Tune", "Scan", "Memory", "Squelch", @@ -120,12 +122,14 @@ static const char *menu[] = #define MENU_ZOOM 7 #define MENU_SCROLL 8 #define MENU_SLEEP 9 -#define MENU_SLEEPMODE 10 -#define MENU_LOADEIBI 11 -#define MENU_USBMODE 12 -#define MENU_BLEMODE 13 -#define MENU_WIFIMODE 14 -#define MENU_ABOUT 15 +#define MENU_SMARTSLEEP 10 +#define MENU_SLEEPMODE 11 +#define MENU_SLEEPTIMER 12 +#define MENU_LOADEIBI 13 +#define MENU_USBMODE 14 +#define MENU_BLEMODE 15 +#define MENU_WIFIMODE 16 +#define MENU_ABOUT 17 int8_t settingsIdx = MENU_BRIGHTNESS; @@ -142,7 +146,9 @@ static const char *settings[] = "Zoom Menu", "Scroll Dir.", "Sleep", + "Smart Sleep", "Sleep Mode", + "Sleep Timer", "Load EiBi", "USB Port", "Bluetooth", @@ -544,7 +550,7 @@ static void clickSquelch(bool shortPress) static void clickSeek(bool shortPress) { - if(shortPress) seekMode(true); else currentCmd = CMD_NONE; + currentCmd = CMD_NONE; } static void clickScan(bool shortPress) @@ -622,11 +628,89 @@ static void doSleep(int16_t enc) currentSleep = clamp_range(currentSleep, 5*enc, 0, 255); } +#define SMARTSLEEP_STATE 0 +#define SMARTSLEEP_DAY 1 +#define SMARTSLEEP_NIGHT 2 +#define SMARTSLEEP_BACK 3 + +static const char *smartSleepMenu[] = +{ + "Smart Sleep", + "Day Start", + "Night Start", + "Back" +}; +int8_t smartSleepIdx = 0; + +static void doSmartSleepMenu(int16_t enc) +{ + smartSleepIdx = wrap_range(smartSleepIdx, enc, 0, LAST_ITEM(smartSleepMenu)); +} + +static void clickSmartSleepMenu(bool shortPress) +{ + if (shortPress) + { + switch(smartSleepIdx) + { + case SMARTSLEEP_STATE: + sleepSmart = !sleepSmart; + prefsRequestSave(SAVE_SETTINGS); + break; + case SMARTSLEEP_DAY: + currentCmd = CMD_DAYSTART; + break; + case SMARTSLEEP_NIGHT: + currentCmd = CMD_NIGHTSTART; + break; + case SMARTSLEEP_BACK: + currentCmd = CMD_SETTINGS; + break; + } + } + else + { + currentCmd = CMD_SETTINGS; + } +} + +static void doDayStart(int16_t enc) +{ + sleepDayStart = wrap_range(sleepDayStart, enc, 0, 23); +} + +static void doNightStart(int16_t enc) +{ + sleepNightStart = wrap_range(sleepNightStart, enc, 0, 23); +} + static void doSleepMode(int16_t enc) { sleepModeIdx = wrap_range(sleepModeIdx, enc, 0, LAST_ITEM(sleepModeDesc)); } +void doSleepTimer(int16_t enc) +{ + int16_t val = currentSleepTimer; + if (enc > 0) { + for(int i=0; i currentSleep * 1000)) + int sleepTimeout = 0; + if(isSleepSmartActive(sleepTimeout) && !sleepOn() && ((currentTime - elapsedSleep) > (uint32_t)sleepTimeout * 1000)) { sleepOn(true); // CPU sleep can take long time, renew the timestamps elapsedSleep = elapsedCommand = currentTime = millis(); } + // Audio sleep timer + if(currentSleepTimer && (currentTime - sleepTimerStart) > (currentSleepTimer * 60000UL)) + { + currentSleepTimer = 0; + prefsRequestSave(SAVE_SETTINGS); + muteOn(MUTE_MAIN, true); + sleepTimerMuted = true; + if(!sleepOn()) sleepOn(1, true); // 强制进入省电 CPU 休眠 + elapsedSleep = elapsedCommand = currentTime = millis(); + } + if((currentTime - elapsedRSSI) > MIN_ELAPSED_RSSI_TIME) { needRedraw |= processRssiSnr(); @@ -1001,3 +1044,45 @@ void loop() // Add a small default delay in the main loop delay(5); } + +bool isSleepSmartActive(int &timeoutSeconds) +{ + if (!sleepSmart || !clockAvailable()) + { + timeoutSeconds = currentSleep; + return (currentSleep > 0); + } + + uint8_t utcHours, utcMinutes; + if (clockGetHM(&utcHours, &utcMinutes)) + { + int localMinutes = (int)utcHours * 60 + utcMinutes + getCurrentUTCOffset() * 15; + localMinutes = (localMinutes < 0) ? localMinutes + 24*60 : (localMinutes % (24*60)); + int localHour = localMinutes / 60; + + bool isDaytime; + if (sleepDayStart < sleepNightStart) + { + isDaytime = (localHour >= sleepDayStart && localHour < sleepNightStart); + } + else + { + isDaytime = (localHour >= sleepDayStart || localHour < sleepNightStart); + } + + if (isDaytime) + { + timeoutSeconds = 0; + return false; + } + else + { + timeoutSeconds = (currentSleep > 0) ? currentSleep : 30; + return true; + } + } + + timeoutSeconds = currentSleep; + return (currentSleep > 0); +} +