mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
The WiFi companion firmware previously had no reconnection handling after the initial WiFi.begin() call. On ESP32 Arduino core 2.x, the built-in auto-reconnect is unreliable, so if WiFi drops it never comes back. This adds a periodic health check (every 60s) in checkRecvFrame() that detects WiFi disconnection and calls WiFi.reconnect(). The check only activates after WiFi has successfully connected at least once, so it won't interfere with the initial connection attempt on startup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
181 lines
No EOL
5.1 KiB
C++
181 lines
No EOL
5.1 KiB
C++
#include "SerialWifiInterface.h"
|
|
#include <WiFi.h>
|
|
|
|
void SerialWifiInterface::begin(int port) {
|
|
// wifi setup is handled outside of this class, only starts the server
|
|
server.begin(port);
|
|
}
|
|
|
|
// ---------- public methods
|
|
void SerialWifiInterface::enable() {
|
|
if (_isEnabled) return;
|
|
|
|
_isEnabled = true;
|
|
clearBuffers();
|
|
}
|
|
|
|
void SerialWifiInterface::disable() {
|
|
_isEnabled = false;
|
|
}
|
|
|
|
size_t SerialWifiInterface::writeFrame(const uint8_t src[], size_t len) {
|
|
if (len > MAX_FRAME_SIZE) {
|
|
WIFI_DEBUG_PRINTLN("writeFrame(), frame too big, len=%d\n", len);
|
|
return 0;
|
|
}
|
|
|
|
if (deviceConnected && len > 0) {
|
|
if (send_queue_len >= FRAME_QUEUE_SIZE) {
|
|
WIFI_DEBUG_PRINTLN("writeFrame(), send_queue is full!");
|
|
return 0;
|
|
}
|
|
|
|
send_queue[send_queue_len].len = len; // add to send queue
|
|
memcpy(send_queue[send_queue_len].buf, src, len);
|
|
send_queue_len++;
|
|
|
|
return len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool SerialWifiInterface::isWriteBusy() const {
|
|
return false;
|
|
}
|
|
|
|
bool SerialWifiInterface::hasReceivedFrameHeader() {
|
|
return received_frame_header.type != 0 && received_frame_header.length != 0;
|
|
}
|
|
|
|
void SerialWifiInterface::resetReceivedFrameHeader() {
|
|
received_frame_header.type = 0;
|
|
received_frame_header.length = 0;
|
|
}
|
|
|
|
size_t SerialWifiInterface::checkRecvFrame(uint8_t dest[]) {
|
|
// periodic WiFi health check (every 60s, only after first successful connection)
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
_wifi_was_connected = true;
|
|
} else if (_wifi_was_connected && millis() >= _wifi_check_time) {
|
|
WIFI_DEBUG_PRINTLN("WiFi disconnected, attempting reconnect...");
|
|
WiFi.reconnect();
|
|
_wifi_check_time = millis() + 60000;
|
|
}
|
|
|
|
// check if new client connected
|
|
auto newClient = server.available();
|
|
if (newClient) {
|
|
|
|
// disconnect existing client
|
|
deviceConnected = false;
|
|
client.stop();
|
|
|
|
// switch active connection to new client
|
|
client = newClient;
|
|
|
|
// forget received frame header
|
|
resetReceivedFrameHeader();
|
|
|
|
}
|
|
|
|
if (client.connected()) {
|
|
if (!deviceConnected) {
|
|
WIFI_DEBUG_PRINTLN("Got connection");
|
|
deviceConnected = true;
|
|
}
|
|
} else {
|
|
if (deviceConnected) {
|
|
deviceConnected = false;
|
|
WIFI_DEBUG_PRINTLN("Disconnected");
|
|
}
|
|
}
|
|
|
|
if (deviceConnected) {
|
|
if (send_queue_len > 0) { // first, check send queue
|
|
|
|
_last_write = millis();
|
|
int len = send_queue[0].len;
|
|
|
|
uint8_t pkt[3+len]; // use same header as serial interface so client can delimit frames
|
|
pkt[0] = '>';
|
|
pkt[1] = (len & 0xFF); // LSB
|
|
pkt[2] = (len >> 8); // MSB
|
|
memcpy(&pkt[3], send_queue[0].buf, send_queue[0].len);
|
|
client.write(pkt, 3 + len);
|
|
send_queue_len--;
|
|
for (int i = 0; i < send_queue_len; i++) { // delete top item from queue
|
|
send_queue[i] = send_queue[i + 1];
|
|
}
|
|
} else {
|
|
|
|
// check if we are waiting for a frame header
|
|
if(!hasReceivedFrameHeader()){
|
|
|
|
// make sure we have received enough bytes for a frame header
|
|
// 3 bytes frame header = (1 byte frame type) + (2 bytes frame length as unsigned 16-bit little endian)
|
|
int frame_header_length = 3;
|
|
if(client.available() >= frame_header_length){
|
|
|
|
// read frame header
|
|
client.readBytes(&received_frame_header.type, 1);
|
|
client.readBytes((uint8_t*)&received_frame_header.length, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// check if we have received a frame header
|
|
if(hasReceivedFrameHeader()){
|
|
|
|
// make sure we have received enough bytes for the required frame length
|
|
int available = client.available();
|
|
int frame_type = received_frame_header.type;
|
|
int frame_length = received_frame_header.length;
|
|
if(frame_length > available){
|
|
WIFI_DEBUG_PRINTLN("Waiting for %d more bytes", frame_length - available);
|
|
return 0;
|
|
}
|
|
|
|
// skip frames that are larger than MAX_FRAME_SIZE
|
|
if(frame_length > MAX_FRAME_SIZE){
|
|
WIFI_DEBUG_PRINTLN("Skipping frame: length=%d is larger than MAX_FRAME_SIZE=%d", frame_length, MAX_FRAME_SIZE);
|
|
while(frame_length > 0){
|
|
uint8_t skip[1];
|
|
int skipped = client.read(skip, 1);
|
|
frame_length -= skipped;
|
|
}
|
|
resetReceivedFrameHeader();
|
|
return 0;
|
|
}
|
|
|
|
// skip frames that are not expected type
|
|
// '<' is 0x3c which indicates a frame sent from app to radio
|
|
if(frame_type != '<'){
|
|
WIFI_DEBUG_PRINTLN("Skipping frame: type=0x%x is unexpected", frame_type);
|
|
while(frame_length > 0){
|
|
uint8_t skip[1];
|
|
int skipped = client.read(skip, 1);
|
|
frame_length -= skipped;
|
|
}
|
|
resetReceivedFrameHeader();
|
|
return 0;
|
|
}
|
|
|
|
// read frame data to provided buffer
|
|
client.readBytes(dest, frame_length);
|
|
|
|
// ready for next frame
|
|
resetReceivedFrameHeader();
|
|
return frame_length;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool SerialWifiInterface::isConnected() const {
|
|
return deviceConnected; //pServer != NULL && pServer->getConnectedCount() > 0;
|
|
} |