mirror of
https://github.com/pelgraine/Meck.git
synced 2026-10-30 19:52:01 +01:00
Max: combined ble wifi initial build test
This commit is contained in:
1 parent
355cd594e6
commit
3fc6e73014
7 files changed
+502
-7
No files matched your search
@@ -73,6 +73,12 @@
|
||||
#define CMD_SEND_CHANNEL_DATA 62
|
||||
#define CMD_SET_DEFAULT_FLOOD_SCOPE 63 // v1.15+ (device-wide default scope name+key)
|
||||
#define CMD_GET_DEFAULT_FLOOD_SCOPE 64 // v1.15+ (query current default scope)
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
#define CMD_RUN_CLI_COMMAND 66 // v14+ (upstream app command line)
|
||||
// Combined BLE + WiFi companion (meck_max_ble_wifi): defined in main.cpp
|
||||
extern bool meckCompanionCommand(const char* command, char* reply);
|
||||
extern void meckCompanionPoll();
|
||||
#endif
|
||||
|
||||
// Stats sub-types for CMD_GET_STATS
|
||||
#define STATS_TYPE_CORE 0
|
||||
@@ -108,6 +114,9 @@
|
||||
#define RESP_ALLOWED_REPEAT_FREQ 26
|
||||
#define RESP_CODE_CHANNEL_DATA_RECV 27
|
||||
#define RESP_CODE_DEFAULT_FLOOD_SCOPE 28 // v1.15+
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
#define RESP_CODE_CLI_REPLY 29 // v14+, a reply to CMD_RUN_CLI_COMMAND
|
||||
#endif
|
||||
|
||||
#define SEND_TIMEOUT_BASE_MILLIS 500
|
||||
#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f
|
||||
@@ -2934,6 +2943,31 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
out_frame[i++] = RESP_CODE_AUTOADD_CONFIG;
|
||||
out_frame[i++] = _prefs.autoadd_config;
|
||||
_serial->writeFrame(out_frame, i);
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
} else if (cmd_frame[0] == CMD_RUN_CLI_COMMAND && len >= 3) {
|
||||
// App command line (upstream MeshCore, v14+). This build answers
|
||||
// upstream's wifi.* commands; anything else gets "Unknown command",
|
||||
// as upstream replies to a command it does not have.
|
||||
char *text = (char *)&cmd_frame[1];
|
||||
text[len - 1] = 0; // ensure null
|
||||
while (*text == ' ') text++; // skip leading spaces
|
||||
char reply_buf[166];
|
||||
char *reply = reply_buf;
|
||||
reply_buf[0] = 0;
|
||||
if (strlen(text) > 4 && text[2] == '|') { // optional prefix: reflect it back
|
||||
memcpy(reply, text, 3);
|
||||
reply += 3;
|
||||
*reply = 0;
|
||||
text += 3;
|
||||
}
|
||||
if (!meckCompanionCommand(text, reply)) {
|
||||
strcat(reply_buf, "Unknown command");
|
||||
}
|
||||
out_frame[0] = RESP_CODE_CLI_REPLY;
|
||||
int rlen = strlen(reply_buf);
|
||||
memcpy(&out_frame[1], reply_buf, rlen);
|
||||
_serial->writeFrame(out_frame, 1 + rlen);
|
||||
#endif
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
|
||||
MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]);
|
||||
@@ -4141,6 +4175,9 @@ void MyMesh::loop() {
|
||||
if (_ui) _ui->setHasConnection(false);
|
||||
#endif
|
||||
#endif
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
meckCompanionPoll(); // app's "set wifi.enabled": switch once its reply has gone
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MyMesh::advert() {
|
||||
|
||||
@@ -815,6 +815,20 @@ static uint32_t _atoi(const char* sp) {
|
||||
#ifndef TCP_PORT
|
||||
#define TCP_PORT 5000
|
||||
#endif
|
||||
#elif defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
// Combined BLE + WiFi companion (meck_max_ble_wifi test build): both
|
||||
// connections built in, both off at boot, one on at a time.
|
||||
#include <WiFi.h>
|
||||
#include <helpers/esp32/SerialBLEInterface.h>
|
||||
#undef FRAME_QUEUE_SIZE // each connection header defines its own queue size
|
||||
#include <helpers/esp32/SerialWifiInterface.h>
|
||||
#include "DualCompanionInterface.h"
|
||||
SerialBLEInterface ble_companion;
|
||||
SerialWifiInterface wifi_companion;
|
||||
DualCompanionInterface serial_interface(&ble_companion, &wifi_companion);
|
||||
#ifndef TCP_PORT
|
||||
#define TCP_PORT 5000
|
||||
#endif
|
||||
#elif defined(MECK_WIFI_COMPANION)
|
||||
#include <WiFi.h>
|
||||
#include <helpers/esp32/SerialWifiInterface.h>
|
||||
@@ -882,6 +896,235 @@ MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store
|
||||
|
||||
/* END GLOBAL OBJECTS */
|
||||
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
// ---------------------------------------------------------------------------
|
||||
// Combined BLE + WiFi companion (meck_max_ble_wifi test build)
|
||||
// Both connections are off at boot; turning one on turns the other off.
|
||||
// Free memory is logged on serial ("MEM ...") at boot, after each switch and
|
||||
// when the Web Reader starts, for the feasibility measurements.
|
||||
// ---------------------------------------------------------------------------
|
||||
static bool meckBtReleased = false; // Web Reader has freed Bluetooth's memory
|
||||
static bool meckWifiServerStarted = false; // app server (TCP_PORT) started once
|
||||
static int8_t meckPendingWifi = -1; // app's "set wifi.enabled": -1 none, 0 off, 1 on
|
||||
static unsigned long meckPendingWifiAt = 0;
|
||||
|
||||
static void meckLogMemory(const char* when) {
|
||||
Serial.printf("MEM %s: heap free=%u largest=%u, PSRAM free=%u\n", when,
|
||||
(unsigned)ESP.getFreeHeap(), (unsigned)ESP.getMaxAllocHeap(),
|
||||
(unsigned)ESP.getFreePsram());
|
||||
}
|
||||
|
||||
bool meckCompanionIsBLE() {
|
||||
return serial_interface.getMode() == DualCompanionInterface::MODE_BLE;
|
||||
}
|
||||
|
||||
bool meckCompanionIsWiFi() {
|
||||
return serial_interface.getMode() == DualCompanionInterface::MODE_WIFI;
|
||||
}
|
||||
|
||||
// Read /web/wifi.cfg (line 1 network name, line 2 password), as Settings
|
||||
// writes it. Values are cut to upstream's sizes (32 and 63 characters).
|
||||
static bool meckWifiCfgRead(char* ssid, size_t ssidLen, char* pass, size_t passLen) {
|
||||
ssid[0] = 0;
|
||||
pass[0] = 0;
|
||||
if (!sdCardReady) return false;
|
||||
if (!SD.exists("/web/wifi.cfg")) {
|
||||
digitalWrite(SDCARD_CS, HIGH);
|
||||
return false;
|
||||
}
|
||||
File f = SD.open("/web/wifi.cfg", FILE_READ);
|
||||
if (!f) {
|
||||
digitalWrite(SDCARD_CS, HIGH);
|
||||
return false;
|
||||
}
|
||||
String s = f.readStringUntil('\n'); s.trim();
|
||||
String p = f.readStringUntil('\n'); p.trim();
|
||||
f.close();
|
||||
digitalWrite(SDCARD_CS, HIGH);
|
||||
snprintf(ssid, ssidLen, "%s", s.c_str());
|
||||
snprintf(pass, passLen, "%s", p.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write /web/wifi.cfg the same way the Settings WiFi setup does.
|
||||
static bool meckWifiCfgWrite(const char* ssid, const char* pass) {
|
||||
if (!sdCardReady) return false;
|
||||
bool ok = false;
|
||||
if (SD.exists("/web") || SD.mkdir("/web")) {
|
||||
File f = SD.open("/web/wifi.cfg", FILE_WRITE);
|
||||
if (f) {
|
||||
f.println(ssid);
|
||||
f.println(pass);
|
||||
f.close();
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
digitalWrite(SDCARD_CS, HIGH);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void meckWifiOff() {
|
||||
wifi_companion.disable();
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
}
|
||||
|
||||
void meckCompanionUseNone() {
|
||||
if (meckCompanionIsBLE()) ble_companion.disable();
|
||||
if (meckCompanionIsWiFi()) meckWifiOff();
|
||||
serial_interface.setMode(DualCompanionInterface::MODE_NONE);
|
||||
Serial.println("Companion: Bluetooth and WiFi off");
|
||||
meckLogMemory("both off");
|
||||
}
|
||||
|
||||
// Bluetooth on, WiFi off. Fails once the Web Reader has freed Bluetooth's
|
||||
// memory: as in the BLE build, Bluetooth then needs a reboot.
|
||||
bool meckCompanionUseBLE() {
|
||||
if (meckCompanionIsBLE()) return true;
|
||||
if (meckBtReleased) {
|
||||
Serial.println("Companion: Bluetooth unavailable until reboot (freed for the Web Reader)");
|
||||
return false;
|
||||
}
|
||||
if (meckCompanionIsWiFi()) meckWifiOff();
|
||||
serial_interface.setMode(DualCompanionInterface::MODE_BLE);
|
||||
ble_companion.enable();
|
||||
Serial.println("Companion: Bluetooth on");
|
||||
meckLogMemory("Bluetooth on");
|
||||
return true;
|
||||
}
|
||||
|
||||
// WiFi on, Bluetooth off. connectSaved joins the network in /web/wifi.cfg,
|
||||
// waiting up to 8 s as the Settings WiFi toggle does; WiFi setup passes
|
||||
// false because it scans and joins by itself.
|
||||
bool meckCompanionUseWiFi(bool connectSaved) {
|
||||
if (meckCompanionIsWiFi()) return true;
|
||||
if (meckCompanionIsBLE()) ble_companion.disable();
|
||||
serial_interface.setMode(DualCompanionInterface::MODE_NONE);
|
||||
meckLogMemory("before WiFi on");
|
||||
if (!WiFi.mode(WIFI_STA)) {
|
||||
Serial.println("Companion: WiFi STA init FAILED");
|
||||
WiFi.mode(WIFI_OFF);
|
||||
meckLogMemory("WiFi init failed");
|
||||
return false;
|
||||
}
|
||||
if (!meckWifiServerStarted) {
|
||||
wifi_companion.begin(TCP_PORT);
|
||||
meckWifiServerStarted = true;
|
||||
}
|
||||
serial_interface.setMode(DualCompanionInterface::MODE_WIFI);
|
||||
wifi_companion.enable();
|
||||
if (connectSaved) {
|
||||
char ssid[33], pass[64];
|
||||
if (meckWifiCfgRead(ssid, sizeof(ssid), pass, sizeof(pass)) && ssid[0]) {
|
||||
WiFi.begin(ssid, pass);
|
||||
unsigned long timeout = millis() + 8000;
|
||||
while (WiFi.status() != WL_CONNECTED && millis() < timeout) {
|
||||
delay(100);
|
||||
}
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Serial.printf("Companion: WiFi on, connected to %s, IP: %s\n",
|
||||
ssid, WiFi.localIP().toString().c_str());
|
||||
} else {
|
||||
Serial.println("Companion: WiFi on, but connection failed");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Companion: WiFi on, no saved network (set one in Settings)");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Companion: WiFi on");
|
||||
}
|
||||
meckLogMemory("WiFi on");
|
||||
return true;
|
||||
}
|
||||
|
||||
// App command line (message 66): upstream MeshCore's wifi.* commands, with
|
||||
// the network kept in /web/wifi.cfg as Settings keeps it. Replies are worded
|
||||
// as upstream's. Returns false for any other command (the caller then
|
||||
// replies "Unknown command", as upstream does).
|
||||
bool meckCompanionCommand(const char* command, char* reply) {
|
||||
char ssid[33], pass[64]; // upstream's wifi_ssid / wifi_pwd sizes
|
||||
if (memcmp(command, "set wifi.ssid ", 14) == 0) {
|
||||
meckWifiCfgRead(ssid, sizeof(ssid), pass, sizeof(pass));
|
||||
snprintf(ssid, sizeof(ssid), "%s", &command[14]);
|
||||
if (!meckWifiCfgWrite(ssid, pass)) {
|
||||
strcpy(reply, "Error, can't save to SD card");
|
||||
return true;
|
||||
}
|
||||
sprintf(reply, "> wifi.ssid is now %s (set wifi.pwd too, then reboot)", ssid);
|
||||
return true;
|
||||
}
|
||||
if (memcmp(command, "set wifi.pwd ", 13) == 0) {
|
||||
meckWifiCfgRead(ssid, sizeof(ssid), pass, sizeof(pass));
|
||||
snprintf(pass, sizeof(pass), "%s", &command[13]);
|
||||
if (!meckWifiCfgWrite(ssid, pass)) {
|
||||
strcpy(reply, "Error, can't save to SD card");
|
||||
return true;
|
||||
}
|
||||
strcpy(reply, "> wifi.pwd updated (reboot to apply)");
|
||||
return true;
|
||||
}
|
||||
if (strcmp(command, "get wifi.pwd") == 0) {
|
||||
meckWifiCfgRead(ssid, sizeof(ssid), pass, sizeof(pass));
|
||||
sprintf(reply, "> %s", pass);
|
||||
return true;
|
||||
}
|
||||
if (strcmp(command, "set wifi.clear") == 0) {
|
||||
if (!meckWifiCfgWrite("", "")) {
|
||||
strcpy(reply, "Error, can't save to SD card");
|
||||
return true;
|
||||
}
|
||||
strcpy(reply, "> wifi config cleared (reboot to apply)");
|
||||
return true;
|
||||
}
|
||||
if (strcmp(command, "get wifi.ssid") == 0) {
|
||||
meckWifiCfgRead(ssid, sizeof(ssid), pass, sizeof(pass));
|
||||
sprintf(reply, "> %s", ssid[0] ? ssid : "(not set)");
|
||||
return true;
|
||||
}
|
||||
if (memcmp(command, "set wifi.enabled ", 17) == 0) {
|
||||
int en = atoi(&command[17]) ? 1 : 0;
|
||||
// Both are off at boot in this build, so this switches WiFi now: one
|
||||
// second after the reply, so the reply still reaches the app. WiFi on
|
||||
// turns Bluetooth off.
|
||||
meckPendingWifi = en;
|
||||
meckPendingWifiAt = millis() + 1000;
|
||||
sprintf(reply, "> wifi.enabled is now %d (reboot to apply)", en);
|
||||
return true;
|
||||
}
|
||||
if (strcmp(command, "get wifi.enabled") == 0) {
|
||||
sprintf(reply, "> %d", meckCompanionIsWiFi() ? 1 : 0);
|
||||
return true;
|
||||
}
|
||||
if (strcmp(command, "get wifi.status") == 0) {
|
||||
strcpy(reply, WiFi.status() == WL_CONNECTED ? "> connected" : "> disconnected");
|
||||
return true;
|
||||
}
|
||||
if (strcmp(command, "get wifi.ip") == 0) {
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
sprintf(reply, "> %s", WiFi.localIP().toString().c_str());
|
||||
} else {
|
||||
strcpy(reply, "> (not connected)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called from MyMesh::loop(): runs the app's "set wifi.enabled" switch once
|
||||
// its reply has had time to go out.
|
||||
void meckCompanionPoll() {
|
||||
if (meckPendingWifi < 0) return;
|
||||
if ((long)(millis() - meckPendingWifiAt) < 0) return;
|
||||
int8_t want = meckPendingWifi;
|
||||
meckPendingWifi = -1;
|
||||
if (want == 1 && !meckCompanionIsWiFi()) {
|
||||
meckCompanionUseWiFi(true);
|
||||
} else if (want == 0 && meckCompanionIsWiFi()) {
|
||||
meckCompanionUseNone();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Voice-over-LoRa: incoming raw packet handler (dz0ny VE3 protocol)
|
||||
// Registered with the_mesh.setVoiceHandler() when voice screen is created.
|
||||
@@ -2039,6 +2282,12 @@ void setup() {
|
||||
MESH_DEBUG_PRINTLN("setup() - WiFi mode (compile-time credentials)");
|
||||
WiFi.begin(WIFI_SSID, WIFI_PWD);
|
||||
serial_interface.begin(TCP_PORT);
|
||||
#elif defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
// Combined BLE + WiFi companion: both off at boot. Bluetooth is only
|
||||
// prepared here (its controller starts on first use); WiFi and the app
|
||||
// server start when the user turns WiFi on.
|
||||
MESH_DEBUG_PRINTLN("setup() - combined BLE + WiFi companion, both off at boot");
|
||||
ble_companion.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin());
|
||||
#elif defined(MECK_WIFI_COMPANION)
|
||||
{
|
||||
// WiFi companion: load credentials from SD at runtime.
|
||||
@@ -2366,6 +2615,9 @@ void setup() {
|
||||
#ifdef ESP32
|
||||
Serial.printf("setup() complete - free heap: %d, largest block: %d\n",
|
||||
ESP.getFreeHeap(), ESP.getMaxAllocHeap());
|
||||
#endif
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
meckLogMemory("boot, both off");
|
||||
#endif
|
||||
{
|
||||
void* p25 = malloc(25000); void* p10 = malloc(10000); void* p4 = malloc(4000);
|
||||
@@ -4554,6 +4806,32 @@ void handleKeyboardInput() {
|
||||
Serial.println("Opening web reader");
|
||||
{
|
||||
static bool webReaderWifiReady = false;
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
// Combined build: with the WiFi companion on, WiFi is already up and
|
||||
// Bluetooth is off, so nothing needs freeing. Otherwise do as the BLE
|
||||
// build does, once per boot: switch the Bluetooth companion off, free
|
||||
// Bluetooth's memory (it then needs a reboot) and start WiFi.
|
||||
if (!meckCompanionIsWiFi() && !webReaderWifiReady) {
|
||||
if (meckCompanionIsBLE()) meckCompanionUseNone();
|
||||
Serial.printf("WebReader: heap BEFORE BT release: free=%d, largest=%d\n",
|
||||
ESP.getFreeHeap(), ESP.getMaxAllocHeap());
|
||||
btStop();
|
||||
delay(50);
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_BTDM);
|
||||
delay(50);
|
||||
meckBtReleased = true;
|
||||
Serial.printf("WebReader: heap AFTER BT release: free=%d, largest=%d\n",
|
||||
ESP.getFreeHeap(), ESP.getMaxAllocHeap());
|
||||
if (WiFi.mode(WIFI_STA)) {
|
||||
Serial.println("WebReader: WiFi STA init OK");
|
||||
webReaderWifiReady = true;
|
||||
} else {
|
||||
Serial.println("WebReader: WiFi STA init FAILED");
|
||||
WiFi.mode(WIFI_OFF);
|
||||
}
|
||||
}
|
||||
meckLogMemory("Web Reader start");
|
||||
#else
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
// WiFi companion: WiFi is already up from boot, no BLE to tear down
|
||||
webReaderWifiReady = true;
|
||||
@@ -4592,6 +4870,7 @@ void handleKeyboardInput() {
|
||||
Serial.printf("WebReader: heap after WiFi init: free=%d, largest=%d\n",
|
||||
ESP.getFreeHeap(), ESP.getMaxAllocHeap());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ui_task.gotoWebReader();
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
// Combined BLE + WiFi companion (meck_max_ble_wifi test build).
|
||||
//
|
||||
// Holds the Bluetooth and the WiFi companion connections and passes every
|
||||
// call to whichever one is selected. Only one is selected at a time; with
|
||||
// neither selected it behaves as a switched-off connection. Selecting a
|
||||
// connection and switching the radios on and off is done in main.cpp
|
||||
// (meckCompanionUseBLE / meckCompanionUseWiFi / meckCompanionUseNone).
|
||||
|
||||
#include <helpers/BaseSerialInterface.h>
|
||||
|
||||
class DualCompanionInterface : public BaseSerialInterface {
|
||||
public:
|
||||
enum Mode : uint8_t { MODE_NONE = 0, MODE_BLE = 1, MODE_WIFI = 2 };
|
||||
|
||||
private:
|
||||
BaseSerialInterface* _ble;
|
||||
BaseSerialInterface* _wifi;
|
||||
Mode _mode;
|
||||
|
||||
BaseSerialInterface* active() const {
|
||||
if (_mode == MODE_BLE) return _ble;
|
||||
if (_mode == MODE_WIFI) return _wifi;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
DualCompanionInterface(BaseSerialInterface* ble, BaseSerialInterface* wifi)
|
||||
: _ble(ble), _wifi(wifi), _mode(MODE_NONE) { }
|
||||
|
||||
Mode getMode() const { return _mode; }
|
||||
void setMode(Mode m) { _mode = m; }
|
||||
|
||||
// BaseSerialInterface methods, passed to the selected connection
|
||||
void enable() override { if (active()) active()->enable(); }
|
||||
void disable() override { if (active()) active()->disable(); }
|
||||
bool isEnabled() const override { return active() ? active()->isEnabled() : false; }
|
||||
bool isConnected() const override { return active() ? active()->isConnected() : false; }
|
||||
bool isWriteBusy() const override { return active() ? active()->isWriteBusy() : false; }
|
||||
bool hasPendingData() const override { return active() ? active()->hasPendingData() : false; }
|
||||
size_t writeFrame(const uint8_t src[], size_t len) override {
|
||||
return active() ? active()->writeFrame(src, len) : 0;
|
||||
}
|
||||
size_t checkRecvFrame(uint8_t dest[]) override {
|
||||
return active() ? active()->checkRecvFrame(dest) : 0;
|
||||
}
|
||||
};
|
||||
@@ -1048,7 +1048,16 @@ public:
|
||||
extern void otaResumeRadio();
|
||||
otaResumeRadio();
|
||||
// Try to restore STA WiFi from saved credentials
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
{
|
||||
// Combined build: only if WiFi was the companion connection
|
||||
extern bool meckCompanionIsWiFi();
|
||||
if (meckCompanionIsWiFi()) {
|
||||
WiFi.mode(WIFI_STA);
|
||||
wifiReconnectSaved();
|
||||
}
|
||||
}
|
||||
#elif defined(MECK_WIFI_COMPANION)
|
||||
WiFi.mode(WIFI_STA);
|
||||
wifiReconnectSaved();
|
||||
#endif
|
||||
@@ -1474,7 +1483,16 @@ public:
|
||||
_editMode = EDIT_NONE;
|
||||
extern void otaResumeRadio();
|
||||
otaResumeRadio();
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
{
|
||||
// Combined build: only if WiFi was the companion connection
|
||||
extern bool meckCompanionIsWiFi();
|
||||
if (meckCompanionIsWiFi()) {
|
||||
WiFi.mode(WIFI_STA);
|
||||
wifiReconnectSaved();
|
||||
}
|
||||
}
|
||||
#elif defined(MECK_WIFI_COMPANION)
|
||||
WiFi.mode(WIFI_STA);
|
||||
wifiReconnectSaved();
|
||||
#endif
|
||||
@@ -3529,11 +3547,33 @@ public:
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
case ROW_WIFI_SETUP: {
|
||||
// Launch WiFi scan → select → password → connect flow
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
{
|
||||
// Combined build: WiFi setup makes WiFi the companion connection
|
||||
// (Bluetooth goes off), as one connection is on at a time
|
||||
extern bool meckCompanionUseWiFi(bool connectSaved);
|
||||
meckCompanionUseWiFi(false);
|
||||
}
|
||||
#endif
|
||||
_editMode = EDIT_WIFI;
|
||||
performWifiScan();
|
||||
break;
|
||||
}
|
||||
case ROW_WIFI_TOGGLE:
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
{
|
||||
// Combined build: WiFi on turns Bluetooth off; WiFi off leaves
|
||||
// neither on
|
||||
extern bool meckCompanionIsWiFi();
|
||||
extern bool meckCompanionUseWiFi(bool connectSaved);
|
||||
extern void meckCompanionUseNone();
|
||||
if (meckCompanionIsWiFi()) {
|
||||
meckCompanionUseNone();
|
||||
} else {
|
||||
meckCompanionUseWiFi(true);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (WiFi.getMode() != WIFI_OFF) {
|
||||
// Turn WiFi OFF
|
||||
WiFi.disconnect(true);
|
||||
@@ -3567,6 +3607,7 @@ public:
|
||||
}
|
||||
Serial.println("Settings: WiFi radio ON");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_4G_MODEM
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
#if defined(WIFI_SSID) || defined(MECK_WIFI_COMPANION)
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
// Combined BLE + WiFi companion (meck_max_ble_wifi): defined in main.cpp
|
||||
extern bool meckCompanionIsBLE();
|
||||
extern bool meckCompanionUseBLE();
|
||||
extern void meckCompanionUseNone();
|
||||
#endif
|
||||
|
||||
#ifndef AUTO_OFF_MILLIS
|
||||
#define AUTO_OFF_MILLIS 15000 // 15 seconds
|
||||
@@ -147,7 +153,8 @@ class HomeScreen : public UIScreen {
|
||||
RADIO,
|
||||
#ifdef BLE_PIN_CODE
|
||||
BLUETOOTH,
|
||||
#elif defined(MECK_WIFI_COMPANION)
|
||||
#endif
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
WIFI_STATUS,
|
||||
#endif
|
||||
ADVERT,
|
||||
@@ -697,7 +704,12 @@ public:
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef BLE_PIN_CODE
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
// Combined build: show the PIN only while Bluetooth is the connection
|
||||
if (rightBuf[0] == 0 && meckCompanionIsBLE() && _task->isSerialEnabled() && the_mesh.getBLEPin() != 0) {
|
||||
sprintf(rightBuf, "Pin:%d", the_mesh.getBLEPin());
|
||||
}
|
||||
#elif defined(BLE_PIN_CODE)
|
||||
if (rightBuf[0] == 0 && _task->isSerialEnabled() && the_mesh.getBLEPin() != 0) {
|
||||
sprintf(rightBuf, "Pin:%d", the_mesh.getBLEPin());
|
||||
}
|
||||
@@ -946,7 +958,30 @@ public:
|
||||
display.setCursor(0, 64);
|
||||
sprintf(tmp, "RX packets: %u", (unsigned)the_mesh.getRxPacketCount());
|
||||
display.print(tmp);
|
||||
#ifdef BLE_PIN_CODE
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
} else if (_page == HomePage::BLUETOOTH) {
|
||||
// Combined build: Bluetooth counts as on only while it is the
|
||||
// connection, not while WiFi is
|
||||
bool btOn = meckCompanionIsBLE() && _task->isSerialEnabled();
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.drawXbm((display.width() - 32) / 2, 18,
|
||||
btOn ? bluetooth_on : bluetooth_off,
|
||||
32, 32);
|
||||
if (btOn && _task->hasConnection()) {
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.setTextSize(1);
|
||||
display.drawTextCentered(display.width() / 2, 53, "< Connected >");
|
||||
} else if (btOn && the_mesh.getBLEPin() != 0) {
|
||||
display.setColor(DisplayDriver::RED);
|
||||
display.setTextSize(2);
|
||||
sprintf(tmp, "Pin:%d", the_mesh.getBLEPin());
|
||||
display.drawTextCentered(display.width() / 2, 53, tmp);
|
||||
}
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.setTextSize(1);
|
||||
display.drawTextCentered(display.width() / 2, 68, "toggle: " PRESS_LABEL);
|
||||
display.drawTextCentered(display.width() / 2, 78, "or press Enter key");
|
||||
#elif defined(BLE_PIN_CODE)
|
||||
} else if (_page == HomePage::BLUETOOTH) {
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.drawXbm((display.width() - 32) / 2, 18,
|
||||
@@ -1356,7 +1391,18 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#ifdef BLE_PIN_CODE
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
if (c == KEY_ENTER && _page == HomePage::BLUETOOTH) {
|
||||
// Combined build: Bluetooth on turns WiFi off; Bluetooth off leaves
|
||||
// neither on. Once the Web Reader has freed Bluetooth, it needs a reboot.
|
||||
if (meckCompanionIsBLE()) {
|
||||
meckCompanionUseNone();
|
||||
} else if (!meckCompanionUseBLE()) {
|
||||
_task->showAlert("Reboot for Bluetooth", 1500);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#elif defined(BLE_PIN_CODE)
|
||||
if (c == KEY_ENTER && _page == HomePage::BLUETOOTH) {
|
||||
if (_task->isSerialEnabled()) { // toggle Bluetooth on/off
|
||||
_task->disableSerial();
|
||||
|
||||
@@ -5141,7 +5141,17 @@ public:
|
||||
if (_tlsClient) { delete _tlsClient; _tlsClient = nullptr; }
|
||||
_tlsHost = String();
|
||||
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
#if defined(BLE_PIN_CODE) && defined(MECK_WIFI_COMPANION)
|
||||
// Combined build: keep WiFi up only if it is the companion connection
|
||||
extern bool meckCompanionIsWiFi();
|
||||
if (meckCompanionIsWiFi()) {
|
||||
_wifiState = WIFI_CONNECTED; // WiFi is still up
|
||||
} else {
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
_wifiState = WIFI_IDLE;
|
||||
}
|
||||
#elif defined(MECK_WIFI_COMPANION)
|
||||
// WiFi companion: keep WiFi alive for the companion TCP server.
|
||||
// Don't disconnect or change mode — just reset our internal state.
|
||||
_wifiState = WIFI_CONNECTED; // WiFi is still up
|
||||
|
||||
@@ -295,6 +295,40 @@ lib_deps =
|
||||
bitbank2/JPEGDEC
|
||||
bitbank2/PNGdec
|
||||
|
||||
; MAX combined BLE + WiFi companion: TEST BUILD. Both connections built in,
|
||||
; both off at boot; turning one on turns the other off. Answers the app's
|
||||
; command-line message (66) for upstream's wifi.* commands. Free memory is
|
||||
; logged on serial ("MEM ...") at boot, after each switch and when the Web
|
||||
; Reader starts. Flags are meck_max_ble's plus meck_max_wifi's.
|
||||
[env:meck_max_ble_wifi]
|
||||
extends = LilyGo_TDeck_Pro_Max
|
||||
build_flags =
|
||||
${LilyGo_TDeck_Pro_Max.build_flags}
|
||||
-I examples/companion_radio/ui-new
|
||||
-D MAX_CONTACTS=2000
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D BLE_PIN_CODE=123456
|
||||
-D MECK_BLE_TX_POWER=ESP_PWR_LVL_P15
|
||||
-D MECK_WIFI_COMPANION=1
|
||||
-D TCP_PORT=5000
|
||||
-D WIFI_DEBUG_LOGGING=1
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D MECK_WEB_READER=1
|
||||
-D MECK_OTA_UPDATE=1
|
||||
-D HAS_4G_MODEM=1
|
||||
-D FIRMWARE_VERSION='"Meck v1.14.MAX.BLE-WiFi"'
|
||||
build_src_filter = ${LilyGo_TDeck_Pro_Max.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
+<../examples/companion_radio/ui-new/*.cpp>
|
||||
+<helpers/ui/GxEPDDisplay.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_TDeck_Pro_Max.lib_deps}
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
bitbank2/JPEGDEC
|
||||
bitbank2/PNGdec
|
||||
|
||||
; MAX standalone (no BLE/WiFi — maximum battery life, LoRa mesh only)
|
||||
; Contacts in PSRAM (2000 capacity). OTA enabled (WiFi AP on demand).
|
||||
[env:meck_max_standalone]
|
||||
|
||||
Reference in new issue
Block a user