Skip to content

Commit f915ee0

Browse files
committed
Implement clean WiFi/BT transitions to reduce heap size.
1 parent c94e6de commit f915ee0

File tree

5 files changed

+181
-165
lines changed

5 files changed

+181
-165
lines changed

Firmware/RTK_Surveyor/RTK_Surveyor.ino

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
A settings file is accessed on microSD if available otherwise settings are pulled from
1919
ESP32's emulated EEPROM.
2020
21+
As of v1.2, the heap is approximately 94072 during Rover Fix, 142260 during WiFi Casting. This is
22+
important to maintain as unit will begin to have stability issues at ~30k.
23+
2124
The main loop handles lower priority updates such as:
2225
Fuel gauge checking and power LED color update
2326
Setup switch monitoring (module configure between Rover and Base)
@@ -34,7 +37,7 @@
3437
Enable various debug outputs sent over BT
3538
3639
TODO
37-
Solve caster port not closing issue
40+
Indicate successful casting
3841
*/
3942

4043
const int FIRMWARE_VERSION_MAJOR = 1;
@@ -110,6 +113,8 @@ const int fatSemaphore_maxWait = 5; //TickType_t
110113
//Connection settings to NTRIP Caster
111114
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
112115
#include <WiFi.h>
116+
#include "esp_wifi.h" //Needed for init/deinit of resources to free up RAM
117+
113118
WiFiClient caster;
114119
const char * ntrip_server_name = "SparkFun_RTK_Surveyor";
115120

@@ -135,7 +140,7 @@ SFE_UBLOX_GNSS i2cGNSS;
135140
#define MAX_PAYLOAD_SIZE 384 // Override MAX_PAYLOAD_SIZE for getModuleInfo which can return up to 348 bytes
136141
uint8_t settingPayload[MAX_PAYLOAD_SIZE];
137142

138-
#define gnssFileBufferSize 32768 // Allocate 16KBytes of RAM for UBX message storage
143+
#define gnssFileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
139144

140145
TaskHandle_t F9PI2CTaskHandle = NULL; //Task for regularly checking I2C
141146
const int i2cTaskStackSize = 2000;
@@ -227,6 +232,7 @@ uint32_t lastBaseLEDupdate = 0; //Controls the blinking of the Base LED
227232

228233
uint32_t lastFileReport = 0; //When logging, print file record stats every few seconds
229234
long lastStackReport = 0; //Controls the report rate of stack highwater mark within a task
235+
uint32_t lastHeapReport = 0;
230236

231237
uint32_t lastSatelliteDishIconUpdate = 0;
232238
bool satelliteDishIconDisplayed = false; //Toggles as lastSatelliteDishIconUpdate goes above 1000ms
@@ -309,6 +315,12 @@ void loop()
309315
//Convert current system time to minutes. This is used in F9PSerialReadTask()/updateLogs() to see if we are within max log window.
310316
systemTime_minutes = millis() / 1000L / 60;
311317

318+
if (millis() - lastHeapReport > 1000)
319+
{
320+
lastHeapReport = millis();
321+
Serial.printf("freeHeap: %d\n\r", ESP.getFreeHeap());
322+
}
323+
312324
delay(10); //A small delay prevents panic if no other I2C or functions are called
313325
}
314326

Firmware/RTK_Surveyor/States.ino

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ void updateSystemState()
2626
displayRoverFail(1000);
2727
return;
2828
}
29-
30-
beginBluetooth(); //Restart Bluetooth with 'Rover' name
29+
30+
stopWiFi(); //Turn off WiFi and release all resources
31+
startBluetooth(); //Turn on Bluetooth with 'Rover' name
3132

3233
digitalWrite(baseStatusLED, LOW);
3334
displayRoverSuccess(500);
@@ -91,7 +92,8 @@ void updateSystemState()
9192

9293
//Restart Bluetooth with 'Base' name
9394
//We start BT regardless of Ntrip Server in case user wants to transmit survey-in stats over BT
94-
beginBluetooth();
95+
stopWiFi();
96+
startBluetooth();
9597

9698
if (configureUbloxModuleBase() == true)
9799
{
@@ -192,11 +194,8 @@ void updateSystemState()
192194
{
193195
//Turn off Bluetooth and turn on WiFi
194196
endBluetooth();
197+
startWiFi();
195198

196-
Serial.printf("Connecting to local WiFi: %s\n\r", settings.wifiSSID);
197-
WiFi.begin(settings.wifiSSID, settings.wifiPW);
198-
199-
radioState = WIFI_ON_NOCONNECTION;
200199
changeState(STATE_BASE_TEMP_WIFI_STARTED);
201200
}
202201
}
@@ -216,9 +215,11 @@ void updateSystemState()
216215
{
217216
Serial.print(F("WiFi Status: "));
218217
switch (wifiStatus) {
218+
case WL_NO_SSID_AVAIL:
219+
Serial.printf("SSID '%s' not detected\n\r", settings.wifiSSID);
220+
break;
219221
case WL_NO_SHIELD: Serial.println(F("WL_NO_SHIELD")); break;
220222
case WL_IDLE_STATUS: Serial.println(F("WL_IDLE_STATUS")); break;
221-
case WL_NO_SSID_AVAIL: Serial.println(F("WL_NO_SSID_AVAIL")); break;
222223
case WL_SCAN_COMPLETED: Serial.println(F("WL_SCAN_COMPLETED")); break;
223224
case WL_CONNECTED: Serial.println(F("WL_CONNECTED")); break;
224225
case WL_CONNECT_FAILED: Serial.println(F("WL_CONNECT_FAILED")); break;
@@ -348,11 +349,7 @@ void updateSystemState()
348349
{
349350
//Turn off Bluetooth and turn on WiFi
350351
endBluetooth();
351-
352-
Serial.printf("Connecting to local WiFi: %s\n\r", settings.wifiSSID);
353-
WiFi.begin(settings.wifiSSID, settings.wifiPW);
354-
355-
radioState = WIFI_ON_NOCONNECTION;
352+
startWiFi();
356353

357354
rtcmPacketsSent = 0; //Reset any previous number
358355

@@ -375,9 +372,11 @@ void updateSystemState()
375372
{
376373
Serial.print(F("WiFi Status: "));
377374
switch (wifiStatus) {
375+
case WL_NO_SSID_AVAIL:
376+
Serial.printf("SSID '%s' not detected\n\r", settings.wifiSSID);
377+
break;
378378
case WL_NO_SHIELD: Serial.println(F("WL_NO_SHIELD")); break;
379379
case WL_IDLE_STATUS: Serial.println(F("WL_IDLE_STATUS")); break;
380-
case WL_NO_SSID_AVAIL: Serial.println(F("WL_NO_SSID_AVAIL")); break;
381380
case WL_SCAN_COMPLETED: Serial.println(F("WL_SCAN_COMPLETED")); break;
382381
case WL_CONNECTED: Serial.println(F("WL_CONNECTED")); break;
383382
case WL_CONNECT_FAILED: Serial.println(F("WL_CONNECT_FAILED")); break;

Firmware/RTK_Surveyor/System.ino

Lines changed: 154 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,161 @@
1+
//Get MAC, start radio
2+
//Tack device's MAC address to end of friendly broadcast name
3+
//This allows multiple units to be on at same time
4+
bool startBluetooth()
5+
{
6+
//Get unit MAC address
7+
esp_read_mac(unitMACAddress, ESP_MAC_WIFI_STA);
8+
unitMACAddress[5] += 2; //Convert MAC address to Bluetooth MAC (add 2): https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system.html#mac-address
9+
10+
if (digitalRead(baseSwitch) == HIGH)
11+
sprintf(deviceName, "Surveyor Rover-%02X%02X", unitMACAddress[4], unitMACAddress[5]); //Rover mode
12+
else
13+
sprintf(deviceName, "Surveyor Base-%02X%02X", unitMACAddress[4], unitMACAddress[5]); //Base mode
14+
15+
if (SerialBT.begin(deviceName) == false)
16+
{
17+
Serial.println(F("An error occurred initializing Bluetooth"));
18+
radioState = RADIO_OFF;
19+
digitalWrite(bluetoothStatusLED, LOW);
20+
return (false);
21+
}
22+
23+
//Set PIN to 1234 so we can connect to older BT devices, but not require a PIN for modern device pairing
24+
//See issue: https://github.com/sparkfun/SparkFun_RTK_Surveyor/issues/5
25+
//https://github.com/espressif/esp-idf/issues/1541
26+
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
27+
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
28+
29+
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_NONE; //Requires pin 1234 on old BT dongle, No prompt on new BT dongle
30+
//esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_OUT; //Works but prompts for either pin (old) or 'Does this 6 pin appear on the device?' (new)
31+
32+
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
33+
34+
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
35+
esp_bt_pin_code_t pin_code;
36+
pin_code[0] = '1';
37+
pin_code[1] = '2';
38+
pin_code[2] = '3';
39+
pin_code[3] = '4';
40+
esp_bt_gap_set_pin(pin_type, 4, pin_code);
41+
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
42+
43+
SerialBT.register_callback(btCallback);
44+
SerialBT.setTimeout(250);
45+
46+
Serial.print(F("Bluetooth broadcasting as: "));
47+
Serial.println(deviceName);
48+
49+
radioState = BT_ON_NOCONNECTION;
50+
digitalWrite(bluetoothStatusLED, HIGH);
51+
52+
//Start the tasks for handling incoming and outgoing BT bytes to/from ZED-F9P
53+
if (F9PSerialReadTaskHandle == NULL)
54+
xTaskCreate(
55+
F9PSerialReadTask,
56+
"F9Read", //Just for humans
57+
readTaskStackSize, //Stack Size
58+
NULL, //Task input parameter
59+
0, //Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
60+
&F9PSerialReadTaskHandle); //Task handle
61+
62+
if (F9PSerialWriteTaskHandle == NULL)
63+
xTaskCreate(
64+
F9PSerialWriteTask,
65+
"F9Write", //Just for humans
66+
writeTaskStackSize, //Stack Size
67+
NULL, //Task input parameter
68+
0, //Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
69+
&F9PSerialWriteTaskHandle); //Task handle
70+
71+
//Start task for controlling Bluetooth pair LED
72+
btLEDTask.attach(btLEDTaskPace, updateBTled); //Rate in seconds, callback
73+
74+
return (true);
75+
}
76+
77+
//This function stops BT so that it can be restarted later
78+
//It also releases as much system resources as possible so that WiFi/caster is more stable
79+
void endBluetooth()
80+
{
81+
//Delete tasks if running
82+
if (F9PSerialReadTaskHandle != NULL)
83+
{
84+
vTaskDelete(F9PSerialReadTaskHandle);
85+
F9PSerialReadTaskHandle = NULL;
86+
}
87+
if (F9PSerialWriteTaskHandle != NULL)
88+
{
89+
vTaskDelete(F9PSerialWriteTaskHandle);
90+
F9PSerialWriteTaskHandle = NULL;
91+
}
92+
93+
SerialBT.flush(); //Complete any transfers
94+
SerialBT.disconnect(); //Drop any clients
95+
SerialBT.end(); //SerialBT.end() will release significant RAM (~100k!) but a SerialBT.start will crash.
96+
97+
//The following code releases the BT hardware so that it can be restarted with a SerialBT.begin
98+
customBTstop();
99+
Serial.println(F("Bluetooth turned off"));
100+
101+
radioState = RADIO_OFF;
102+
}
103+
1104
//Starting and restarting BT is a problem. See issue: https://github.com/espressif/arduino-esp32/issues/2718
2105
//To work around the bug without modifying the core we create our own btStop() function with
3106
//the patch from github
4-
//bool customBTstop() {
5-
// if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
6-
// return true;
7-
// }
8-
// if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
9-
// if (esp_bt_controller_disable()) {
10-
// log_e("BT Disable failed");
11-
// return false;
12-
// }
13-
// while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED);
14-
// }
15-
// if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED)
16-
// {
17-
// log_i("inited");
18-
// if (esp_bt_controller_deinit())
19-
// {
20-
// log_e("BT deint failed");
21-
// return false;
22-
// }
23-
// while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED)
24-
// ;
25-
// return true;
26-
// }
27-
// log_e("BT Stop failed");
28-
// return false;
29-
//}
107+
bool customBTstop() {
108+
109+
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
110+
return true;
111+
}
112+
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
113+
if (esp_bt_controller_disable()) {
114+
log_e("BT Disable failed");
115+
return false;
116+
}
117+
while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED);
118+
}
119+
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED)
120+
{
121+
log_i("inited");
122+
if (esp_bt_controller_deinit())
123+
{
124+
log_e("BT deint failed");
125+
return false;
126+
}
127+
while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED)
128+
;
129+
return true;
130+
}
131+
log_e("BT Stop failed");
132+
return false;
133+
}
134+
135+
//Start WiFi assuming it was previously fully released
136+
//See WiFiBluetoothSwitch sketch for more info
137+
void startWiFi()
138+
{
139+
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
140+
esp_wifi_init(&wifi_init_config); //Restart WiFi resources
30141

142+
Serial.printf("Connecting to local WiFi: %s\n\r", settings.wifiSSID);
143+
WiFi.begin(settings.wifiSSID, settings.wifiPW);
144+
145+
radioState = WIFI_ON_NOCONNECTION;
146+
}
147+
148+
//Stop WiFi and release all resources
149+
//See WiFiBluetoothSwitch sketch for more info
150+
void stopWiFi()
151+
{
152+
caster.stop();
153+
WiFi.mode(WIFI_OFF);
154+
esp_wifi_deinit(); //Free all resources
155+
Serial.println("WiFi Stopped");
156+
157+
radioState = RADIO_OFF;
158+
}
31159

32160
//Setup the u-blox module for any setup (base or rover)
33161
//In general we check if the setting is incorrect before writing it. Otherwise, the set commands have, on rare occasion, become

0 commit comments

Comments
 (0)