Skip to content

Commit b7d193b

Browse files
Merge pull request #83 from DCSBIOSKit/esp32-wifi
Esp32 wifi
2 parents 0356cd8 + 25ecd42 commit b7d193b

File tree

8 files changed

+518
-0
lines changed

8 files changed

+518
-0
lines changed

.DS_Store

6 KB
Binary file not shown.

src/.DS_Store

8 KB
Binary file not shown.

src/DcsBios.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ do not come with their own build system, we are just putting everything into the
4848
#include "internal/DcsBiosNgRS485Slave.h"
4949
#include "internal/DcsBiosNgRS485Slave.cpp.inc"
5050
#endif
51+
#ifdef DCSBIOS_ESP32_WIFI
52+
#include "internal/ESP32WiFi/DcsBiosESP32WiFiSlave.h"
53+
#include "internal/ESP32WiFi/DcsBiosESP32WiFiSlave.cpp.inc"
54+
#endif
5155
#ifdef DCSBIOS_IRQ_SERIAL
5256

5357
namespace DcsBios {
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#ifdef DCSBIOS_ESP32_WIFI
2+
3+
namespace DcsBios {
4+
void ESP32WiFiSlave::begin() {
5+
beginNeopixel();
6+
Serial.begin(115200);
7+
WiFi.begin(ssid, password);
8+
setNeopixel(OFFLINE);
9+
10+
while (WiFi.status() != WL_CONNECTED) {
11+
delay(500);
12+
Serial.println("Connecting to WiFi...");
13+
}
14+
15+
Serial.println("Connected to " + WiFi.SSID() + " with IP " + WiFi.localIP().toString());
16+
17+
#ifndef DCSBIOS_ESP32_WIFI_MULTICAST
18+
if (!MDNS.begin("esp32_consumer")) {
19+
Serial.println("Error starting mDNS");
20+
return;
21+
}
22+
23+
Serial.println("mDNS started");
24+
#endif
25+
26+
setNeopixel(ASSOCIATED);
27+
}
28+
29+
bool ESP32WiFiSlave::connected() {
30+
#ifdef DCSBIOS_ESP32_WIFI_TCP
31+
return client.connected();
32+
#else
33+
return udp_ready;
34+
#endif
35+
}
36+
37+
void ESP32WiFiSlave::loop() {
38+
#ifdef DCSBIOS_ESP32_WIFI_INSTRUMENTATION
39+
lastLoopDuration = micros() - lastLoopTime;
40+
lastLoopTime = micros();
41+
#endif
42+
43+
if (!connected()) {
44+
#ifdef DCSBIOS_ESP32_WIFI_MULTICAST
45+
int n = 1; // No discovery required in multicast mode
46+
#else
47+
int n = MDNS.queryService(DCSBIOS_ESP32_WIFI_SERVICE);
48+
#endif
49+
50+
if (n > 0) {
51+
#ifndef DCSBIOS_ESP32_WIFI_MULTICAST
52+
master_ip = MDNS.IP(0);
53+
master_port = MDNS.port(0);
54+
#endif
55+
56+
#ifdef DCSBIOS_ESP32_WIFI_TCP
57+
int tries = 0;
58+
while (!connected() && tries < 5) {
59+
Serial.println("Connecting to " + master_ip.toString() + ":" + master_port);
60+
client.connect(master_ip, master_port, 100);
61+
tries++;
62+
}
63+
Serial.println("Socket is connected");
64+
send("register");
65+
#elif defined(DCSBIOS_ESP32_WIFI_UDP)
66+
client.begin(DCSBIOS_ESP32_WIFI_LOCAL_PORT);
67+
udp_ready = true;
68+
send("register");
69+
#else
70+
if (client.beginMulticast(DCSBIOS_ESP32_WIFI_MULTICAST_GROUP, DCSBIOS_ESP32_WIFI_LOCAL_PORT)) {
71+
Serial.println("UDP Multicast listener started on group " + DCSBIOS_ESP32_WIFI_MULTICAST_GROUP.toString() + " and port " + String(DCSBIOS_ESP32_WIFI_LOCAL_PORT));
72+
udp_ready = true;
73+
} else {
74+
Serial.println("UDP Multicast listener failed to start");
75+
udp_ready = false;
76+
}
77+
#endif
78+
79+
lastReceivedTime = millis(); // Update last received time when connected
80+
lastKeepAliveTime = millis();
81+
setNeopixel(CONNECTED);
82+
} else {
83+
Serial.println("No services found");
84+
delay(100);
85+
}
86+
} else {
87+
#ifdef DCSBIOS_ESP32_WIFI_TCP
88+
// TCP mode, only check for incoming data
89+
int packetSize = client.available();
90+
#else
91+
// UDP mode, check for incoming data and set master IP and port if required
92+
int packetSize = client.parsePacket();
93+
94+
if (master_port == 0 && packetSize > 0) {
95+
master_ip = client.remoteIP();
96+
master_port = client.remotePort();
97+
98+
#ifdef DCSBIOS_ESP32_WIFI_MULTICAST
99+
// Delayed registration in multicast mode, discovery is based on the first incoming packet
100+
send("register");
101+
#endif
102+
}
103+
#endif
104+
105+
if (packetSize > 0) {
106+
lastReceivedTime = millis();
107+
uint8_t incomingPacket[packetSize];
108+
int len = client.read(incomingPacket, packetSize);
109+
110+
DynamicJsonDocument incomingJson(packetSize*2);
111+
DeserializationError error = deserializeJson(incomingJson, incomingPacket);
112+
113+
if (error) {
114+
Serial.print(F("deserializeJson() failed: "));
115+
Serial.println(error.c_str());
116+
}
117+
118+
String type = incomingJson["type"].as<String>();
119+
String data = incomingJson["data"].as<String>();
120+
121+
if (type == "message") {
122+
String decodedMessage = base64_decode(data);
123+
124+
for (unsigned int i = 0; i < decodedMessage.length(); ++i) {
125+
char byte = decodedMessage[i];
126+
parser.processChar(byte);
127+
}
128+
} else if (type == "check-in") {
129+
Serial.println("Received check-in");
130+
} else if (type == "ack") {
131+
String id = incomingJson["id"].as<String>();
132+
unsigned int seq = incomingJson["seq"].as<unsigned int>();
133+
134+
if (id == DCSBIOS_ESP32_WIFI) {
135+
for (auto message = messages.begin(); message != messages.end(); /* empty */) {
136+
if (message->id == seq) {
137+
// Serial.println("Received ack for message " + String(seq) + " after " + String(millis() - message->lastSentTime) + "ms");
138+
message = messages.erase(message);
139+
//Serial.println("Removed message with seq: " + String(seq));
140+
break; // Exit the loop as the message has been found and removed
141+
} else {
142+
++message;
143+
}
144+
}
145+
}
146+
} else if (type == "restart") {
147+
String id = incomingJson["id"].as<String>();
148+
149+
if (id == DCSBIOS_ESP32_WIFI) {
150+
Serial.println("Kthxbai!");
151+
ESP.restart();
152+
}
153+
} else if (type == "restart-all") {
154+
Serial.println("Kthxbai!");
155+
ESP.restart();
156+
} else {
157+
Serial.println("Unknown message type: " + type);
158+
}
159+
} else {
160+
// Check for timeout
161+
if (millis() - lastReceivedTime > timeoutDuration) {
162+
#ifdef DCSBIOS_ESP32_WIFI_TCP
163+
client.stop();
164+
#else
165+
udp_ready = false;
166+
#endif
167+
setNeopixel(ASSOCIATED);
168+
Serial.println("Connection timed out");
169+
}
170+
}
171+
172+
// Check if it's time to send a keep-alive message
173+
if (connected() && (millis() - lastKeepAliveTime >= keepAliveTimeout)) {
174+
send("check-in");
175+
176+
lastKeepAliveTime = millis();
177+
}
178+
179+
// Send enqueued messages
180+
for (auto message = messages.begin(); message != messages.end(); /* empty */) {
181+
if (message->retries > DCSBIOS_ESP32_WIFI_MAX_RETRIES) {
182+
message = messages.erase(message);
183+
// Serial.println("Giving up on message " + String(message->id));
184+
} else if (millis() - message->lastSentTime > 250) {
185+
// Serial.println("Sending message with id " + String(message->id) + " and type " + String(message->type) + " retry: " + String(message->retries));
186+
send(message->type, message->data, message->id);
187+
message->retries++;
188+
message->lastSentTime = millis();
189+
++message;
190+
} else {
191+
++message;
192+
}
193+
}
194+
}
195+
}
196+
197+
void ESP32WiFiSlave::enqueue(const char* type) {
198+
enqueue(type, "");
199+
}
200+
201+
void ESP32WiFiSlave::enqueue(const char* type, String data) {
202+
Message message;
203+
message.id = last_message_id++;
204+
message.type = type;
205+
message.data = data;
206+
messages.push_back(message);
207+
Serial.println("Enqueued " + String(type) + " with id " + String(message.id));
208+
}
209+
210+
void ESP32WiFiSlave::send(const char* type) {
211+
send(type, "", 0);
212+
}
213+
214+
void ESP32WiFiSlave::send(const char* type, String data, unsigned int seq) {
215+
if (master_port == 0) {
216+
return;
217+
}
218+
219+
DynamicJsonDocument jsonDoc(1024);
220+
jsonDoc["type"] = type;
221+
jsonDoc["data"] = base64_encode(data);
222+
jsonDoc["seq"] = seq;
223+
224+
JsonObject slave = jsonDoc.createNestedObject("slave");
225+
slave["id"] = DCSBIOS_ESP32_WIFI;
226+
slave["mac"] = WiFi.macAddress();
227+
slave["rssi"] = WiFi.RSSI();
228+
slave["free_heap"] = ESP.getFreeHeap();
229+
#ifdef DCSBIOS_ESP32_WIFI_INSTRUMENTATION
230+
slave["loop_duration"] = lastLoopDuration;
231+
#endif
232+
233+
if (type == "register") {
234+
slave["cpu_freq"] = ESP.getCpuFreqMHz();
235+
slave["flash_size"] = ESP.getFlashChipSize();
236+
}
237+
238+
String output;
239+
serializeJson(jsonDoc, output);
240+
241+
#ifndef DCSBIOS_ESP32_WIFI_TCP
242+
client.beginPacket(master_ip, master_port);
243+
#endif
244+
245+
client.write((uint8_t *)output.c_str(), output.length());
246+
247+
#ifndef DCSBIOS_ESP32_WIFI_TCP
248+
client.endPacket();
249+
#endif
250+
}
251+
252+
void setup() {
253+
wifiSlave.begin();
254+
}
255+
256+
void loop() {
257+
wifiSlave.loop();
258+
PollingInput::pollInputs();
259+
ExportStreamListener::loopAll();
260+
}
261+
262+
bool tryToSendDcsBiosMessage(const char* msg, const char* arg) {
263+
String data = msg + String(' ') + arg + String('\n');
264+
wifiSlave.enqueue("message", data);
265+
266+
DcsBios::PollingInput::setMessageSentOrQueued();
267+
return true;
268+
}
269+
270+
void resetAllStates() {
271+
PollingInput::resetAllStates();
272+
}
273+
}
274+
#endif
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#ifndef _DCSBIOS_ESP32_WIFI_H_
2+
#define _DCSBIOS_ESP32_WIFI_H_
3+
#ifdef DCSBIOS_ESP32_WIFI
4+
5+
#ifndef ARDUINO_ARCH_ESP32
6+
#error "This code is designed to run on ESP32! Please check your build settings."
7+
#endif
8+
9+
#ifndef DCSBIOS_ESP32_WIFI_LOCAL_PORT
10+
#define DCSBIOS_ESP32_WIFI_LOCAL_PORT 7779
11+
#endif
12+
13+
#ifndef DCSBIOS_ESP32_WIFI_MULTICAST_GROUP
14+
#define DCSBIOS_ESP32_WIFI_MULTICAST_GROUP IPAddress(232, 0, 1, 3)
15+
#endif
16+
17+
#ifdef DCSBIOS_ESP32_WIFI_TCP
18+
#define DCSBIOS_ESP32_WIFI_SERVICE "_dcs-bios", "_tcp"
19+
#else
20+
#define DCSBIOS_ESP32_WIFI_SERVICE "_dcs-bios", "_udp"
21+
#endif
22+
23+
#ifndef DCSBIOS_ESP32_WIFI_MAX_RETRIES
24+
#define DCSBIOS_ESP32_WIFI_MAX_RETRIES 3
25+
#endif
26+
27+
#include <Arduino.h>
28+
#include <ArduinoJson.h>
29+
#include <WiFi.h>
30+
#include <ESPmDNS.h>
31+
#include <WiFiClient.h>
32+
#include <WiFiServer.h>
33+
#include <WiFiUDP.h>
34+
35+
#include "Utils.h"
36+
#include "Utils.cpp.inc"
37+
#include <deque>
38+
39+
namespace DcsBios {
40+
ProtocolParser parser;
41+
42+
class Message {
43+
public:
44+
unsigned int id;
45+
unsigned int retries = 0;
46+
const char* type;
47+
String data;
48+
unsigned long lastSentTime = 0;
49+
};
50+
51+
class ESP32WiFiSlave {
52+
public:
53+
void begin();
54+
void loop();
55+
void enqueue(const char* type);
56+
void enqueue(const char* type, String data);
57+
58+
#ifdef DCSBIOS_ESP32_WIFI_TCP
59+
WiFiClient client;
60+
#else
61+
WiFiUDP client;
62+
#endif
63+
private:
64+
IPAddress master_ip = IPAddress(0, 0, 0, 0);
65+
unsigned int master_port = 0;
66+
67+
void send(const char* type);
68+
void send(const char* type, String data, unsigned int seq);
69+
70+
unsigned long lastReceivedTime = 0;
71+
const unsigned long timeoutDuration = 3000;
72+
unsigned long lastKeepAliveTime = 0;
73+
const unsigned long keepAliveTimeout = 1000;
74+
75+
const char* ssid = DCSBIOS_ESP32_WIFI_SSID;
76+
const char* password = DCSBIOS_ESP32_WIFI_PASSWORD;
77+
78+
unsigned int last_message_id = 0;
79+
std::deque<Message> messages;
80+
81+
bool udp_ready;
82+
bool connected();
83+
84+
#ifdef DCSBIOS_ESP32_WIFI_MULTICAST
85+
bool registered = false;
86+
#endif
87+
88+
// Performance Instrumentation
89+
#ifdef DCSBIOS_ESP32_WIFI_INSTRUMENTATION
90+
unsigned long lastLoopTime = 0;
91+
unsigned long lastLoopDuration = 0;
92+
#endif
93+
};
94+
95+
ESP32WiFiSlave wifiSlave;
96+
}
97+
98+
#endif // DCSBIOS_ESP32_WIFI
99+
#endif // _DCSBIOS_ESP32_WIFI_H_

0 commit comments

Comments
 (0)