-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwifiAdapter.cpp
More file actions
270 lines (251 loc) · 11 KB
/
Copy pathwifiAdapter.cpp
File metadata and controls
270 lines (251 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#include "wifiAdapter.h"
#include <WiFi.h>
#include <HTTPClient.h>
#define WIFI_TASK_SLEEP 5000 // Let wifi task sleep for 5 seconds before attempting to reconnect
#define VIN_LEN 18
// Semaphores and task handlers
TaskHandle_t wifiAdapter::connectToWifiTaskHandle = NULL;
SemaphoreHandle_t wifiAdapter::connectionSemaphore;
SemaphoreHandle_t wifiAdapter::APIVarsSemaphore;
StaticSemaphore_t wifiAdapter::connectionSemaphoreBuffer;
StaticSemaphore_t wifiAdapter::APIVarsSemaphoreBuffer;
// Initial var declarations
unsigned long wifiAdapter::wifiConnectionstartTime;
char* wifiAdapter::serverAddress = nullptr;
char* wifiAdapter::VIN = nullptr;
bool wifiAdapter::isConnected = false;
bool wifiAdapter::connectionInProgress = false;
char wifiAdapter::writeBuffer[MAX_WRITE_BUFF_SIZE] = {'\0'}; // Initialize writeBuffer to empty string
std::queue<std::string> wifiAdapter::commandsQueue;
// Helper thread to connect to WiFi without blocking
void wifiAdapter::connectToWifiTask(void* param) {
// Tasks must be in an infinite loop, otherwise it will crash per RTOS docs:
while (true) {
// Update the state of WIFI connection
xSemaphoreTake(connectionSemaphore, portMAX_DELAY);
wifiAdapter::isConnected = (WiFi.status() == WL_CONNECTED);
// Method loops until wifi gets connected. Will autoreconnect to the passed in network till stopped
if (!wifiAdapter::isConnected) {
//Reset deviceConnected flag to false
wifiAdapter::isConnected = false;
WifiCredentials* credentials = (WifiCredentials*)param;
// Verify that credentials isn't null
if (credentials != nullptr && credentials->ssid != nullptr && credentials->password != nullptr) {
// Attempt to connect
wifiAdapter::connectionInProgress = true;
Serial.println("DEBUG: WIFI SSID: " + String(credentials->password));
WiFi.begin(credentials->ssid, credentials->password);
// Continue trying to connect for a maximum of 15 seconds
const unsigned long connectionTimeout = 15000;
while ( (!wifiAdapter::isConnected && millis() - wifiAdapter::wifiConnectionstartTime < connectionTimeout))
{
xSemaphoreGive(connectionSemaphore);
vTaskDelay(pdMS_TO_TICKS(WIFI_TASK_SLEEP)); // Let other threads run
xSemaphoreTake(connectionSemaphore, portMAX_DELAY);
}
// Update connection result
wifiAdapter::isConnected = (WiFi.status() == WL_CONNECTED);
wifiAdapter::connectionInProgress = false;
wifiConnectionstartTime = millis();
Serial.println("DEBUG: FINISHED ATTEMPT TO CONNECT TO WIFI: RESULT: " + String(isConnected));
} else {
// Credentias param was corrupted. Exit this thread
wifiAdapter::connectionInProgress = false;
Serial.println("DEBUG: EXIT CONNECT TO WIFI TASK, CORRUPTED Params ");
xSemaphoreGive(connectionSemaphore);
// Free the memory of the Credentials struct
delete credentials;
connectToWifiTaskHandle = NULL;
vTaskDelete(NULL);
}
}
xSemaphoreGive(connectionSemaphore);
vTaskDelay(pdMS_TO_TICKS(WIFI_TASK_SLEEP)); // Let other threads run
}
}
// Helper thread to fetch from car over WiFi in the background
void wifiAdapter::fetchCommand(void* params) {
const int refreshInterval = 400; // Refresh from internet every 400ms
while (true) {
String payload = "";
xSemaphoreTake(APIVarsSemaphore, portMAX_DELAY);
if (wifiAdapter::isConnected == true && VIN != nullptr && serverAddress != nullptr) {
if (strlen(VIN) > 0 && strlen(serverAddress) > 0) {
// Set up HTTP request
WiFiClient client;
HTTPClient http;
String fetchCommand = String(wifiAdapter::serverAddress) + "/getCommand";
http.begin(client, fetchCommand);
http.addHeader("Content-Type", "application/json");
http.addHeader("set-vin", wifiAdapter::VIN);
int httpResponseCode = http.GET();
// If successful, write payload
if (httpResponseCode>0) {
//HTTP OK
payload = http.getString();
payload.replace("\"", "");
// Ensure that response is not empty
if (payload.length() > 0) {
wifiAdapter::commandsQueue.push(std::string(payload.c_str()));
}
}
// Free resources
http.end();
}
}
xSemaphoreGive(APIVarsSemaphore);
vTaskDelay(refreshInterval / portTICK_PERIOD_MS);
}
}
// Helper thread to send status to server in the background over WiFi
void wifiAdapter::sendStatus(void* params) {
const int refreshInterval = 900; // Refresh from car every 900ms
while (true) {
xSemaphoreTake(APIVarsSemaphore, portMAX_DELAY);
if (wifiAdapter::isConnected && strlen(writeBuffer) > 0 && VIN != nullptr && serverAddress != nullptr) {
if (strlen(VIN) > 0 && strlen(serverAddress) > 0) {
WiFiClient client;
HTTPClient http;
String putCommand = String(wifiAdapter::serverAddress) + "/putStatus";
http.begin(client, putCommand);
http.addHeader("Content-Type", "application/json");
http.addHeader("set-vin", wifiAdapter::VIN);
int httpResponseCode = http.PUT((uint8_t*)writeBuffer, strlen(writeBuffer));
if (httpResponseCode>0) {
//HTTP OK
// Take any actions needed after sending
}
// Free resources
http.end();
}
}
xSemaphoreGive(APIVarsSemaphore);
vTaskDelay(refreshInterval / portTICK_PERIOD_MS);
}
}
// Constructor + Destructor
wifiAdapter::wifiAdapter(const char* serverAddress) {
connectionSemaphore = xSemaphoreCreateBinaryStatic(&connectionSemaphoreBuffer);
APIVarsSemaphore = xSemaphoreCreateBinaryStatic(&APIVarsSemaphoreBuffer);
// Initialize the semaphore to the "not taken" state
xSemaphoreGive(connectionSemaphore);
xSemaphoreGive(APIVarsSemaphore);
// Save the serverAddress
this->serverAddress = new char[strlen(serverAddress) + 1]; // Allocate new char in memory to hold serverAddress
strcpy(this->serverAddress, serverAddress); // Copy string to memory
this->VIN = new char[VIN_LEN]; // Allocate memory for the new variable
// Construct private vars
isConnected = false;
connectionInProgress = false;
wifiConnectionstartTime = 0;
// Create task to fetch data from car every 2 seconds once connected
xTaskCreate(
fetchCommand,
"fetchCommand",
4000, // Stack size in Bytes
NULL, // No pointer to pass
1, // Task priority
&fetchCommandHandle // Task handle
);
xTaskCreate(
sendStatus,
"sendStatus",
9000, // Stack size in Bytes, made bigger to handle largest payload
NULL, // No pointer to pass
2, // Task priority
&sendStatusHandle // Task handle
);
}
wifiAdapter::~wifiAdapter() {
disconnectFromNetwork();
// Kill the running tasks and set their handels to NULL
if (fetchCommandHandle != NULL){
vTaskDelete(fetchCommandHandle);
fetchCommandHandle = NULL;
}
if (sendStatusHandle != NULL) {
vTaskDelete(sendStatusHandle);
sendStatusHandle = NULL;
}
if (connectToWifiTaskHandle != NULL) {
vTaskDelete(connectToWifiTaskHandle);
connectToWifiTaskHandle = NULL;
}
// Deallocate memory
delete[] this->serverAddress;
delete[] this->VIN;
}
// Implement public methods:
// This method will connect to the passed in wifi network. Calling code should call this only when wanting to change network!
void wifiAdapter::connectToNetwork(const char* ssid, const char* password) {
// Ensure that a conncetion isn't already in progress
if (!connectionInProgress) {
// Record start time
wifiConnectionstartTime = millis();
// Delete the old connectToWifiTask if it exists
if (connectToWifiTaskHandle != NULL) {
vTaskDelete(connectToWifiTaskHandle);
connectToWifiTaskHandle = NULL;
// Attempt to disconnect from WIFI
disconnectFromNetwork();
}
// Allocate new credentials
WifiCredentials* credentials = new WifiCredentials;
strncpy(credentials->ssid, ssid, MAX_SSID_LENGTH);
strncpy(credentials->password, password, MAX_PASSWORD_LENGTH);
xTaskCreate(
connectToWifiTask,
"ConnectToWifi",
2500, // Stack size in Bytes
(void*)credentials, // Pass a pointer to credentials struct
3, // Task priority
&connectToWifiTaskHandle // Task handle
);
}
}
String wifiAdapter::getCommandWifi() {
xSemaphoreTake(APIVarsSemaphore, portMAX_DELAY);
if (!commandsQueue.empty()) {
std::string command = commandsQueue.front();
commandsQueue.pop();
xSemaphoreGive(APIVarsSemaphore);
return String(command.c_str());
}
xSemaphoreGive(APIVarsSemaphore);
return "";
}
void wifiAdapter::updateState(const char* state) {
// Ensure that passed in state is less than MAX buffer size and that strings arent equal
if (strlen(state) < MAX_WRITE_BUFF_SIZE && strcmp(state, writeBuffer) != 0) {
xSemaphoreTake(APIVarsSemaphore, portMAX_DELAY);
strcpy(writeBuffer, state); // Copy state into the write buffer
xSemaphoreGive(APIVarsSemaphore);
}
}
void wifiAdapter::disconnectFromNetwork() {
if (isDeviceConnected()) {
WiFi.disconnect();
xSemaphoreTake(connectionSemaphore, portMAX_DELAY);
connectionInProgress = false;
// Update connection result
isConnected = (WiFi.status() == WL_CONNECTED);
xSemaphoreGive(connectionSemaphore);
}
}
bool wifiAdapter::isDeviceConnected() {
bool connected = false;
xSemaphoreTake(connectionSemaphore, portMAX_DELAY);
connected = isConnected;
xSemaphoreGive(connectionSemaphore);
return connected;
}
// Method to set VIN
void wifiAdapter::setVIN(char* VIN) {
// update the VIN only if it's different
if((this->VIN == nullptr) || (strcmp(VIN, this->VIN) != 0)) {
xSemaphoreTake(APIVarsSemaphore, portMAX_DELAY);
strcpy(this->VIN, VIN); // Copy in the new VIN to memory
xSemaphoreGive(APIVarsSemaphore);
Serial.println("VIN SET");
}
}