Skip to content

Commit c25aabc

Browse files
MitchBradleymathieucarboupre-commit-ci-lite[bot]
authored
Support hosted builds against Arduino-Emulator (#420)
* Support hosted builds against Arduino-Emulator * Factors the locking into one place * Adds "|| defined(HOST)" as needed elsewhere * Adds "override" in a few places where it was missing * Changed comments to address Copilot nitpicking * Changed cpp macros to c++ possibly-null classes, thanks willmmiles * locks in asyncsrv namespace, guarded by ASYNCSRV_USE_MUTEX * HOST versions of logging. * __unused -> __asyncws_unused * More explicit formulation of ASYNCWEBSERVER_USE_MUTEX define * ci(pre-commit): Apply automatic fixes * Apply suggestion from @mathieucarbou * Fix compile sisue * Add CI for Arduino-Emulator * Fix compilation issue where tcp_state enum type was not found project must be compiled with lwip when using arduino emulator * Add CI for Arduino-Emulator * ci(pre-commit): Apply automatic fixes * Fix Arduino Elumator CI * Move FPSTR in cpp * Try fix CI on linux (works on mac) * Project Structure Reorg: regrouping all examples under examples folder * Move arduino_emulator to examples folder --------- Co-authored-by: Mathieu Carbou <mathieu.carbou@gmail.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent ac11f71 commit c25aabc

19 files changed

Lines changed: 258 additions & 141 deletions
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2+
3+
name: Build (Arduino Emulator)
4+
5+
on:
6+
workflow_dispatch:
7+
push:
8+
branches:
9+
- main
10+
- release/*
11+
paths-ignore:
12+
- "docs/**"
13+
- "mkdocs.yml"
14+
- "README.md"
15+
pull_request:
16+
paths-ignore:
17+
- "docs/**"
18+
- "mkdocs.yml"
19+
- "README.md"
20+
21+
concurrency:
22+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
23+
cancel-in-progress: true
24+
25+
jobs:
26+
arduino-emulator:
27+
name: Arduino Emulator (cmake, HOST)
28+
runs-on: ubuntu-latest
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@v6
32+
33+
- name: Install build tools
34+
run: |
35+
sudo apt-get update
36+
sudo apt-get install -y cmake ninja-build build-essential git
37+
38+
- name: Clone Arduino-Emulator
39+
run: |
40+
git clone --depth 1 --recurse-submodules https://github.com/pschatzmann/Arduino-Emulator.git .ci/arduino-emulator
41+
42+
- name: Clone AsyncTCP, Arduino FS headers, lwIP and lwIP contrib
43+
run: |
44+
git clone --depth 1 https://github.com/ESP32Async/AsyncTCP .ci/asynctcp
45+
git clone --depth 1 https://github.com/espressif/arduino-esp32.git .ci/arduino-esp32
46+
git clone --depth 1 https://github.com/lwip-tcpip/lwip.git .ci/lwip
47+
git clone --depth 1 https://git.savannah.nongnu.org/git/lwip/lwip-contrib.git .ci/lwip-contrib
48+
49+
- name: Build with Arduino-Emulator
50+
run: |
51+
cmake -S examples/arduino_emulator -B .ci/arduino-emulator-build/out -G Ninja
52+
cmake --build .ci/arduino-emulator-build/out --target espasyncwebserver --parallel

examples/arduino/CaptivePortal/CaptivePortal.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ static AsyncWebServer server(80);
1919

2020
class CaptiveRequestHandler : public AsyncWebHandler {
2121
public:
22-
bool canHandle(__unused AsyncWebServerRequest *request) const override {
22+
bool canHandle(__asyncws_unused AsyncWebServerRequest *request) const override {
2323
return true;
2424
}
2525

examples/arduino/Filters/Filters.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ static AsyncWebServer server(80);
2323

2424
class CaptiveRequestHandler : public AsyncWebHandler {
2525
public:
26-
bool canHandle(__unused AsyncWebServerRequest *request) const override {
26+
bool canHandle(__asyncws_unused AsyncWebServerRequest *request) const override {
2727
return true;
2828
}
2929

examples/arduino/HTTPMethodsWithArduino/HTTPMethodsWithArduino.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static WebRequestMethodComposite allowed = AsyncWebRequestMethod::HTTP_HEAD | As
5858

5959
class MyRequestHandler : public AsyncWebHandler {
6060
public:
61-
bool canHandle(__unused AsyncWebServerRequest *request) const override {
61+
bool canHandle(__asyncws_unused AsyncWebServerRequest *request) const override {
6262
// Test backward compatibility with previous way of checking if a method is allowed in a composite using a bit operator
6363
return allowed & request->method();
6464
}

examples/arduino/HTTPMethodsWithESPIDF/HTTPMethodsWithESPIDF.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static WebRequestMethodComposite allowed = AsyncWebRequestMethod::HTTP_HEAD | As
5757

5858
class MyRequestHandler : public AsyncWebHandler {
5959
public:
60-
bool canHandle(__unused AsyncWebServerRequest *request) const override {
60+
bool canHandle(__asyncws_unused AsyncWebServerRequest *request) const override {
6161
// Test backward compatibility with previous way of checking if a method is allowed in a composite using a bit operator
6262
return allowed & request->method();
6363
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
cmake_minimum_required(VERSION 3.11)
2+
project(espasyncwebserver_host_compile LANGUAGES C CXX)
3+
4+
add_subdirectory(${CMAKE_SOURCE_DIR}/../../.ci/arduino-emulator ${CMAKE_BINARY_DIR}/arduino-emulator)
5+
file(GLOB WEB_SRC "${CMAKE_SOURCE_DIR}/../../src/*.cpp")
6+
add_library(espasyncwebserver STATIC ${WEB_SRC})
7+
8+
target_compile_definitions(espasyncwebserver PUBLIC HOST ARDUINO=10813)
9+
target_include_directories(espasyncwebserver PUBLIC
10+
${CMAKE_SOURCE_DIR}/../../src
11+
${CMAKE_SOURCE_DIR}/../../.ci/asynctcp/src
12+
${CMAKE_SOURCE_DIR}/../../.ci/arduino-esp32/libraries/FS/src
13+
${CMAKE_SOURCE_DIR}/../../.ci/lwip/src/include
14+
${CMAKE_SOURCE_DIR}/../../.ci/lwip-contrib/ports/unix/port/include
15+
${CMAKE_SOURCE_DIR}/host_config
16+
)
17+
target_link_libraries(espasyncwebserver PUBLIC arduino_emulator)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
typedef void *SemaphoreHandle_t;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
#define NO_SYS 1
4+
#define LWIP_SOCKET 0
5+
#define LWIP_NETCONN 0
6+
#define LWIP_TCP 1
7+
#define LWIP_IPV6 1
8+
9+
#if defined(__linux__) && !defined(LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS)
10+
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS 1
11+
#endif
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#pragma once
2+
3+
#define LWIP_IPV6 1

src/AsyncEventSource.cpp

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -191,19 +191,15 @@ AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, A
191191
}
192192

193193
AsyncEventSourceClient::~AsyncEventSourceClient() {
194-
#ifdef ESP32
195194
// Protect message queue access (size checks and modifications) which is not thread-safe.
196-
std::lock_guard<std::recursive_mutex> lock(_lockmq);
197-
#endif
195+
asyncsrv::lock_guard_type lock(_lockmq);
198196
_messageQueue.clear();
199197
close();
200198
}
201199

202200
bool AsyncEventSourceClient::_queueMessage(const char *message, size_t len) {
203-
#ifdef ESP32
204201
// Protect message queue access (size checks and modifications) which is not thread-safe.
205-
std::lock_guard<std::recursive_mutex> lock(_lockmq);
206-
#endif
202+
asyncsrv::lock_guard_type lock(_lockmq);
207203

208204
if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
209205
async_ws_log_w("Event message queue overflow: discard message");
@@ -231,10 +227,8 @@ bool AsyncEventSourceClient::_queueMessage(const char *message, size_t len) {
231227
}
232228

233229
bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
234-
#ifdef ESP32
235230
// Protect message queue access (size checks and modifications) which is not thread-safe.
236-
std::lock_guard<std::recursive_mutex> lock(_lockmq);
237-
#endif
231+
asyncsrv::lock_guard_type lock(_lockmq);
238232

239233
if (_messageQueue.size() >= SSE_MAX_QUEUED_MESSAGES) {
240234
async_ws_log_w("Event message queue overflow: discard message");
@@ -261,10 +255,8 @@ bool AsyncEventSourceClient::_queueMessage(AsyncEvent_SharedData_t &&msg) {
261255
}
262256

263257
void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))) {
264-
#ifdef ESP32
265258
// Protect message queue access (size checks and modifications) which is not thread-safe.
266-
std::lock_guard<std::recursive_mutex> lock(_lockmq);
267-
#endif
259+
asyncsrv::lock_guard_type lock(_lockmq);
268260

269261
// adjust in-flight len
270262
if (len < _inflight) {
@@ -289,10 +281,8 @@ void AsyncEventSourceClient::_onAck(size_t len __attribute__((unused)), uint32_t
289281
}
290282

291283
void AsyncEventSourceClient::_onPoll() {
292-
#ifdef ESP32
293284
// Protect message queue access (size checks and modifications) which is not thread-safe.
294-
std::lock_guard<std::recursive_mutex> lock(_lockmq);
295-
#endif
285+
asyncsrv::lock_guard_type lock(_lockmq);
296286
if (_messageQueue.size()) {
297287
_runQueue();
298288
}
@@ -373,10 +363,7 @@ void AsyncEventSource::_addClient(AsyncEventSourceClient *client) {
373363
_connectcb(client);
374364
}
375365

376-
#ifdef ESP32
377-
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
378-
#endif
379-
366+
asyncsrv::lock_guard_type lock(_client_queue_lock);
380367
_clients.emplace_back(client);
381368

382369
_adjust_inflight_window();
@@ -386,9 +373,7 @@ void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient *client) {
386373
if (_disconnectcb) {
387374
_disconnectcb(client);
388375
}
389-
#ifdef ESP32
390-
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
391-
#endif
376+
asyncsrv::lock_guard_type lock(_client_queue_lock);
392377
for (auto i = _clients.begin(); i != _clients.end(); ++i) {
393378
if (i->get() == client) {
394379
_clients.erase(i);
@@ -402,9 +387,7 @@ void AsyncEventSource::close() {
402387
// While the whole loop is not done, the linked list is locked and so the
403388
// iterator should remain valid even when AsyncEventSource::_handleDisconnect()
404389
// is called very early
405-
#ifdef ESP32
406-
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
407-
#endif
390+
asyncsrv::lock_guard_type lock(_client_queue_lock);
408391
for (const auto &c : _clients) {
409392
if (c->connected()) {
410393
/**
@@ -421,9 +404,7 @@ void AsyncEventSource::close() {
421404
size_t AsyncEventSource::avgPacketsWaiting() const {
422405
size_t aql = 0;
423406
uint32_t nConnectedClients = 0;
424-
#ifdef ESP32
425-
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
426-
#endif
407+
asyncsrv::lock_guard_type lock(_client_queue_lock);
427408
for (const auto &c : _clients) {
428409
if (c->connected()) {
429410
aql += c->packetsWaiting();
@@ -435,9 +416,7 @@ size_t AsyncEventSource::avgPacketsWaiting() const {
435416

436417
AsyncEventSource::SendStatus AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect) {
437418
AsyncEvent_SharedData_t shared_msg = std::make_shared<String>(generateEventMessage(message, event, id, reconnect));
438-
#ifdef ESP32
439-
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
440-
#endif
419+
asyncsrv::lock_guard_type lock(_client_queue_lock);
441420
size_t hits = 0;
442421
size_t miss = 0;
443422
for (const auto &c : _clients) {
@@ -453,9 +432,7 @@ AsyncEventSource::SendStatus AsyncEventSource::send(const char *message, const c
453432
}
454433

455434
size_t AsyncEventSource::count() const {
456-
#ifdef ESP32
457-
std::lock_guard<std::recursive_mutex> lock(_client_queue_lock);
458-
#endif
435+
asyncsrv::lock_guard_type lock(_client_queue_lock);
459436
size_t n_clients{0};
460437
for (const auto &i : _clients) {
461438
if (i->connected()) {

0 commit comments

Comments
 (0)