diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 8c4281ba..12283d3a 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -82,7 +82,7 @@ // Audiobook player — Audio object is heap-allocated on first use to avoid // consuming ~40KB of DMA/decode buffers at boot (starves BLE stack). // Not available on 4G variant (I2S pins conflict with modem control lines). - #ifndef HAS_4G_MODEM + #if !defined(HAS_4G_MODEM) || defined(MECK_AUDIO_VARIANT) #include "AudiobookPlayerScreen.h" #include "Audio.h" Audio* audio = nullptr; @@ -2444,8 +2444,12 @@ void setup() { MESH_DEBUG_PRINTLN("setup() - 4G modem manager started"); } else { // Ensure modem power is off (kills red LED too) +#if defined(LilyGo_TDeck_Pro_Max) + board.modemPowerOff(); // XL9555 6609_EN LOW +#else pinMode(MODEM_POWER_EN, OUTPUT); digitalWrite(MODEM_POWER_EN, LOW); +#endif MESH_DEBUG_PRINTLN("setup() - 4G modem disabled by config"); } } @@ -2720,7 +2724,7 @@ void loop() { #endif // Audiobook: service audio decode regardless of which screen is active - #if defined(LilyGo_TDeck_Pro) && !defined(HAS_4G_MODEM) + #if defined(LilyGo_TDeck_Pro) && (!defined(HAS_4G_MODEM) || defined(MECK_AUDIO_VARIANT)) { AudiobookPlayerScreen* abPlayer = (AudiobookPlayerScreen*)ui_task.getAudiobookScreen(); @@ -4392,7 +4396,7 @@ void handleKeyboardInput() { } // *** AUDIOBOOK MODE *** - #ifndef HAS_4G_MODEM + #if !defined(HAS_4G_MODEM) || defined(MECK_AUDIO_VARIANT) if (audiobookMode) { AudiobookPlayerScreen* abPlayer = (AudiobookPlayerScreen*)ui_task.getAudiobookScreen(); @@ -5070,7 +5074,7 @@ void handleKeyboardInput() { } break; } - #ifndef HAS_4G_MODEM + #if !defined(HAS_4G_MODEM) || defined(MECK_AUDIO_VARIANT) // Otherwise: open audiobook player - lazy-init Audio + screen on first use Serial.println("Opening audiobook player"); if (!ui_task.getAudiobookScreen()) { @@ -5955,7 +5959,7 @@ void sendComposedMessage() { // The audio library calls these global functions - must be defined at file scope. // Not available on 4G variant (no audio hardware). -#ifndef HAS_4G_MODEM +#if !defined(HAS_4G_MODEM) || defined(MECK_AUDIO_VARIANT) void audio_info(const char *info) { Serial.printf("Audio: %s\n", info); } diff --git a/examples/companion_radio/ui-new/ModemManager.cpp b/examples/companion_radio/ui-new/ModemManager.cpp index 56bba4b2..a60dc3bb 100644 --- a/examples/companion_radio/ui-new/ModemManager.cpp +++ b/examples/companion_radio/ui-new/ModemManager.cpp @@ -6,6 +6,11 @@ #include #include +#if defined(LilyGo_TDeck_Pro_Max) + #include // MAX: XL9555-routed modem power/PWRKEY + extern TDeckProMaxBoard board; // defined in target.cpp +#endif + // Global singleton ModemManager modemManager; @@ -93,7 +98,11 @@ void ModemManager::shutdown() { } // Cut modem power +#if defined(LilyGo_TDeck_Pro_Max) + board.modemPowerOff(); // XL9555 6609_EN LOW +#else digitalWrite(MODEM_POWER_EN, LOW); +#endif // Delete task vTaskDelete(_taskHandle); @@ -511,6 +520,11 @@ void ModemManager::processURCLine(const char* line) { // --- VOICE CALL: BEGIN -- A76xx-specific: audio path established --- if (strncmp(line, "VOICE CALL: BEGIN", 17) == 0) { MESH_DEBUG_PRINTLN("[Modem] URC: VOICE CALL: BEGIN"); +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: route the shared speaker mux to the modem and enable the amplifier + board.selectAudioModem(); + board.amplifierEnable(); +#endif if (_state == ModemState::DIALING) { _state = ModemState::IN_CALL; _callStartTime = millis(); @@ -543,6 +557,11 @@ void ModemManager::processURCLine(const char* line) { _state = ModemState::READY; _callPhone[0] = '\0'; _callStartTime = 0; +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: call audio path closed -- return the speaker mux to ES8311, amp off + board.selectAudioES8311(); + board.amplifierDisable(); +#endif return; } @@ -638,6 +657,11 @@ bool ModemManager::doHangup() { _state = ModemState::READY; _callPhone[0] = '\0'; _callStartTime = 0; +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: hung up -- return the speaker mux to ES8311, amp off + board.selectAudioES8311(); + board.amplifierDisable(); +#endif MESH_DEBUG_PRINTLN("[Modem] Hangup OK"); return true; } @@ -679,6 +703,11 @@ void ModemManager::handleRingtone() { _ringing = true; _nextRingTone = 0; // Play first burst immediately _toneActive = false; +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: route the shared speaker to the modem for the ringtone bursts + board.selectAudioModem(); + board.amplifierEnable(); +#endif } else if (!nowRinging && _ringing) { // Ringing stopped (answered, rejected, missed) _ringing = false; @@ -686,6 +715,14 @@ void ModemManager::handleRingtone() { sendAT("AT+SIMTONE=0", "OK", 500); _toneActive = false; } +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: if the call was NOT answered (not now in-call), return audio to + // ES8311. If it WAS answered, leave the mux on the modem for call audio. + if (_state != ModemState::IN_CALL) { + board.selectAudioES8311(); + board.amplifierDisable(); + } +#endif return; } @@ -841,6 +878,11 @@ bool ModemManager::playModemTone(const char* filename) { // param 2: 0 = no repeat char cmd[64]; snprintf(cmd, sizeof(cmd), "AT+CCMXPLAY=\"C:/%s\",0,0", filename); +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: route the shared speaker to the modem for tone playback + board.selectAudioModem(); + board.amplifierEnable(); +#endif bool ok = sendAT(cmd, "OK", 2000); if (ok) { _notifTonePlaying = true; @@ -856,6 +898,11 @@ bool ModemManager::stopModemTone() { if (!_notifTonePlaying) return true; bool ok = sendAT("AT+CCMXSTOP", "OK", 1000); _notifTonePlaying = false; +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: tone finished -- return the speaker mux to ES8311, amp off + board.selectAudioES8311(); + board.amplifierDisable(); +#endif MESH_DEBUG_PRINTLN("[Modem] Tone stop %s", ok ? "OK" : "FAIL"); return ok; } @@ -1249,6 +1296,23 @@ restart: bool ModemManager::modemPowerOn() { MESH_DEBUG_PRINTLN("[Modem] powering on..."); +#if defined(LilyGo_TDeck_Pro_Max) + // MAX: 6609_EN and PWRKEY are XL9555-routed, and there is NO modem reset + // line (IO9 is the e-ink reset on MAX). Drive power/PWRKEY via the board + // helpers and skip the reset pulse entirely. + board.modemPowerOn(); // XL9555 6609_EN HIGH (SGM6609 boost) + vTaskDelay(pdMS_TO_TICKS(500)); + MESH_DEBUG_PRINTLN("[Modem] power supply enabled (XL9555 6609_EN)"); + + board.modemPwrkeyPulse(); // XL9555 PWRKEY HIGH/LOW(1200ms)/HIGH + MESH_DEBUG_PRINTLN("[Modem] PWRKEY pulsed, waiting for boot..."); + vTaskDelay(pdMS_TO_TICKS(5000)); + + // DTR is a direct GPIO on MAX (IO8) + pinMode(MODEM_DTR, OUTPUT); + digitalWrite(MODEM_DTR, LOW); + MESH_DEBUG_PRINTLN("[Modem] DTR asserted LOW (GPIO %d)", MODEM_DTR); +#else // Enable modem power supply (BOARD_6609_EN) pinMode(MODEM_POWER_EN, OUTPUT); digitalWrite(MODEM_POWER_EN, HIGH); @@ -1278,6 +1342,7 @@ bool ModemManager::modemPowerOn() { pinMode(MODEM_DTR, OUTPUT); digitalWrite(MODEM_DTR, LOW); MESH_DEBUG_PRINTLN("[Modem] DTR asserted LOW (GPIO %d)", MODEM_DTR); +#endif // Configure UART MODEM_SERIAL.begin(MODEM_BAUD, SERIAL_8N1, MODEM_TX, MODEM_RX); diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 38f731b3..6317918c 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -467,6 +467,8 @@ public: display.drawTextCentered(display.width() / 2, y, tmp); #if defined(LILYGO_TECHO_LITE) y += 12; // Compact +#elif defined(LilyGo_TDeck_Pro_Max) + y += 10; // MAX: pull < Connected > up under MSG to make room for [T] Phone #else y += 14; // Reduced from 18 #endif @@ -627,7 +629,19 @@ public: display.setCursor(col1, y); display.print("[E] Reader"); #endif y += menuLH; -#if defined(HAS_4G_MODEM) && defined(MECK_WEB_READER) +#if defined(HAS_4G_MODEM) && defined(MECK_AUDIO_VARIANT) + display.setCursor(col1, y); display.print("[P] Audio"); + display.setCursor(col2, y); display.print("[K] Alarm"); + y += menuLH; + #ifdef MECK_WEB_READER + display.setCursor(col1, y); display.print("[B] Browser"); + display.setCursor(col2, y); display.print("[F] Discover"); + #else + display.setCursor(col1, y); display.print("[F] Discover"); + #endif + y += menuLH; + display.setCursor(col1, y); display.print("[T] Phone"); +#elif defined(HAS_4G_MODEM) && defined(MECK_WEB_READER) display.setCursor(col1, y); display.print("[T] Phone"); display.setCursor(col2, y); display.print("[B] Browser"); #elif defined(HAS_4G_MODEM) @@ -657,7 +671,11 @@ public: y += 2; } else { // Monospaced built-in font (Classic): centered space-padded strings +#if defined(LilyGo_TDeck_Pro_Max) + y += 2; // MAX: Press sits closer under < Connected > +#else y += 6; +#endif display.drawTextCentered(display.width() / 2, y, "Press:"); y += 12; display.drawTextCentered(display.width() / 2, y, "[M] Messages [C] Contacts "); @@ -670,7 +688,15 @@ public: display.drawTextCentered(display.width() / 2, y, "[E] Reader "); #endif y += 10; -#if defined(HAS_4G_MODEM) && defined(MECK_WEB_READER) +#if defined(HAS_4G_MODEM) && defined(MECK_AUDIO_VARIANT) + display.drawTextCentered(display.width() / 2, y, "[P] Audiobooks [K] Alarm "); + y += 10; + #ifdef MECK_WEB_READER + display.drawTextCentered(display.width() / 2, y, "[B] Browser [F] Discover "); + #else + display.drawTextCentered(display.width() / 2, y, "[F] Discover "); + #endif +#elif defined(HAS_4G_MODEM) && defined(MECK_WEB_READER) display.drawTextCentered(display.width() / 2, y, "[T] Phone [B] Browser "); #elif defined(HAS_4G_MODEM) display.drawTextCentered(display.width() / 2, y, "[T] Phone [F] Discover "); @@ -692,6 +718,11 @@ public: display.drawTextCentered(display.width() / 2, y, "[R] Trace [J] Games "); display.setColor(DisplayDriver::LIGHT); y += 14; +#if defined(HAS_4G_MODEM) && defined(MECK_AUDIO_VARIANT) + // Phone on its own line below Trace/Games, centered like the "Press:" header + display.drawTextCentered(display.width() / 2, y, "[T] Phone"); + y += 14; +#endif } // Nav hint (only if room) diff --git a/variants/lilygo_tdeck_max/platformio.ini b/variants/lilygo_tdeck_max/platformio.ini index 247c50c1..e9031d8f 100644 --- a/variants/lilygo_tdeck_max/platformio.ini +++ b/variants/lilygo_tdeck_max/platformio.ini @@ -172,6 +172,7 @@ build_flags = -D BLE_PIN_CODE=123456 -D OFFLINE_QUEUE_SIZE=256 -D MECK_WEB_READER=1 + -D HAS_4G_MODEM=1 -D MECK_OTA_UPDATE=1 -D FIRMWARE_VERSION='"Meck v1.11.MAX"' build_src_filter = ${LilyGo_TDeck_Pro_Max.build_src_filter}