From 89e8f8dc2ab460bf6982352778a14c25998dd0d6 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Fri, 24 May 2019 07:49:41 +0100 Subject: [PATCH 01/19] Remove duplicate debug statement from `HttpServerConnection::onHeadersComplete` --- Sming/Core/Network/Http/HttpServerConnection.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sming/Core/Network/Http/HttpServerConnection.cpp b/Sming/Core/Network/Http/HttpServerConnection.cpp index f50a487acd..46e20bedd9 100644 --- a/Sming/Core/Network/Http/HttpServerConnection.cpp +++ b/Sming/Core/Network/Http/HttpServerConnection.cpp @@ -79,8 +79,6 @@ int HttpServerConnection::onMessageComplete(http_parser* parser) int HttpServerConnection::onHeadersComplete(const HttpHeaders& headers) { - debug_d("The headers are complete"); - /* Callbacks should return non-zero to indicate an error. The parser will * then halt execution. * From 7d376683e9439a11cc6e9fe994cac72c5ec244a7 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Fri, 24 May 2019 07:54:57 +0100 Subject: [PATCH 02/19] (char*)getRemoteIp() output garbled, replace with getRemoteIp().toString().c_str() Unsafe to return pointer to temporary --- Sming/Wiring/IPAddress.h | 1 - samples/HttpClient/app/application.cpp | 2 +- samples/HttpServer_ConfigNetwork/app/application.cpp | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Sming/Wiring/IPAddress.h b/Sming/Wiring/IPAddress.h index e6ff7602a4..9ae48d5135 100644 --- a/Sming/Wiring/IPAddress.h +++ b/Sming/Wiring/IPAddress.h @@ -84,7 +84,6 @@ class IPAddress : public Printable operator ip_addr() const { return address; } operator ip_addr*() { return &address; } - operator char*() { return toString().begin(); } #if LWIP_VERSION_MAJOR == 2 operator ip_addr_t*() { return &address; } #endif diff --git a/samples/HttpClient/app/application.cpp b/samples/HttpClient/app/application.cpp index f5814c5982..729055d159 100644 --- a/samples/HttpClient/app/application.cpp +++ b/samples/HttpClient/app/application.cpp @@ -70,7 +70,7 @@ void displayCipher(SSL* ssl) int onDownload(HttpConnection& connection, bool success) { debugf("\n=========[ URL: %s ]============", connection.getRequest()->uri.toString().c_str()); - debugf("RemoteIP: %s", (char*)connection.getRemoteIp()); + debugf("RemoteIP: %s", connection.getRemoteIp().toString().c_str()); debugf("Got response code: %d", connection.getResponse()->code); debugf("Success: %d", success); if(connection.getRequest()->method != HTTP_HEAD) { diff --git a/samples/HttpServer_ConfigNetwork/app/application.cpp b/samples/HttpServer_ConfigNetwork/app/application.cpp index e0f5735fae..3927d2ee81 100644 --- a/samples/HttpServer_ConfigNetwork/app/application.cpp +++ b/samples/HttpServer_ConfigNetwork/app/application.cpp @@ -24,7 +24,7 @@ void onIndex(HttpRequest& request, HttpResponse& response) int onIpConfig(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response) { if(request.method == HTTP_POST) { - debugf("Request coming from IP: %s", (char*)connection.getRemoteIp()); + debugf("Request coming from IP: %s", connection.getRemoteIp().toString().c_str()); // If desired you can also limit the access based on remote IP. Example below: // if(!(IPAddress("192.168.4.23") == connection.getRemoteIp())) { // return 1; // error From c75137280dbe1ffd5340d1ac95ec3373e29170b2 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Wed, 15 May 2019 12:06:24 +0100 Subject: [PATCH 03/19] Move `pwm.h` into `Components/drivers`, consistent with ESP-IDF --- .../Esp8266/Components/driver/include/driver/pwm.h | 11 +++++++++++ Sming/Core/HardwarePWM.h | 9 +-------- 2 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h diff --git a/Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h b/Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h new file mode 100644 index 0000000000..01aa4cf96a --- /dev/null +++ b/Sming/Arch/Esp8266/Components/driver/include/driver/pwm.h @@ -0,0 +1,11 @@ +#pragma once + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#if defined(__cplusplus) +} +#endif diff --git a/Sming/Core/HardwarePWM.h b/Sming/Core/HardwarePWM.h index cd1cede0d0..564aa03c19 100644 --- a/Sming/Core/HardwarePWM.h +++ b/Sming/Core/HardwarePWM.h @@ -28,14 +28,7 @@ #pragma once #include "WiringFrameworkDependencies.h" - -#ifdef __cplusplus -extern "C" { -#endif -#include -#ifdef __cplusplus -} -#endif +#include #define PWM_BAD_CHANNEL 0xff ///< Invalid PWM channel From d434850688edbd7801619ee67b89b43884b396ba Mon Sep 17 00:00:00 2001 From: mikee47 Date: Wed, 15 May 2019 12:47:14 +0100 Subject: [PATCH 04/19] Add `esp_wifi` component --- .../Components/esp_wifi/include/esp_smartconfig.h | 12 ++++++++++++ .../Esp8266/Components/esp_wifi/include/esp_wifi.h | 11 +++++++++++ Sming/Platform/Station.h | 11 ++++++----- Sming/Platform/WifiEvents.h | 2 ++ 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 Sming/Arch/Esp8266/Components/esp_wifi/include/esp_smartconfig.h create mode 100644 Sming/Arch/Esp8266/Components/esp_wifi/include/esp_wifi.h diff --git a/Sming/Arch/Esp8266/Components/esp_wifi/include/esp_smartconfig.h b/Sming/Arch/Esp8266/Components/esp_wifi/include/esp_smartconfig.h new file mode 100644 index 0000000000..d98549b680 --- /dev/null +++ b/Sming/Arch/Esp8266/Components/esp_wifi/include/esp_smartconfig.h @@ -0,0 +1,12 @@ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + +#include + +#if defined (__cplusplus) +} +#endif + diff --git a/Sming/Arch/Esp8266/Components/esp_wifi/include/esp_wifi.h b/Sming/Arch/Esp8266/Components/esp_wifi/include/esp_wifi.h new file mode 100644 index 0000000000..6f261b6399 --- /dev/null +++ b/Sming/Arch/Esp8266/Components/esp_wifi/include/esp_wifi.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Platform/Station.h b/Sming/Platform/Station.h index 1329ce8b8d..c4aa6779b5 100644 --- a/Sming/Platform/Station.h +++ b/Sming/Platform/Station.h @@ -24,9 +24,8 @@ #include "WVector.h" #include "IPAddress.h" -extern "C" { -#include -} +#include +#include /** @ingroup constants * @{ @@ -262,8 +261,6 @@ class StationClass : protected ISystemReadyHandler class BssInfo { public: - BssInfo(bss_info* info); - /** @brief Get BSS open status * @retval bool True if BSS open */ @@ -289,6 +286,10 @@ class BssInfo uint8_t channel; ///< Channel number int16_t rssi; ///< RSSI level bool hidden; ///< True if AP is hidden + +private: + friend class StationClass; + BssInfo(bss_info* info); }; /** @brief Global instance of WiFi station object diff --git a/Sming/Platform/WifiEvents.h b/Sming/Platform/WifiEvents.h index 51dacc6b9e..86fa65a02b 100644 --- a/Sming/Platform/WifiEvents.h +++ b/Sming/Platform/WifiEvents.h @@ -17,6 +17,8 @@ #include "WString.h" #include "IPAddress.h" +#include + //Define WifiEvents Delegates types typedef Delegate StationConnectDelegate; typedef Delegate StationDisconnectDelegate; From 17d1c40740332c7bdc5ca3afb00776c4ef5fa7c8 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Thu, 23 May 2019 10:31:20 +0100 Subject: [PATCH 05/19] WifiEvents - move trivial methods into header --- Sming/Arch/Esp8266/Platform/WifiEvents.cpp | 42 +--------------------- Sming/Platform/WifiEvents.h | 42 +++++++++++++++++----- 2 files changed, 35 insertions(+), 49 deletions(-) diff --git a/Sming/Arch/Esp8266/Platform/WifiEvents.cpp b/Sming/Arch/Esp8266/Platform/WifiEvents.cpp index 80c1942a4f..8463403d7e 100644 --- a/Sming/Arch/Esp8266/Platform/WifiEvents.cpp +++ b/Sming/Arch/Esp8266/Platform/WifiEvents.cpp @@ -16,47 +16,7 @@ WifiEventsClass WifiEvents; WifiEventsClass::WifiEventsClass() { - wifi_set_event_handler_cb(staticWifiEventHandler); -} - -void WifiEventsClass::onStationConnect(StationConnectDelegate delegateFunction) -{ - onSTAConnect = delegateFunction; -} - -void WifiEventsClass::onStationDisconnect(StationDisconnectDelegate delegateFunction) -{ - onSTADisconnect = delegateFunction; -} - -void WifiEventsClass::onStationAuthModeChange(StationAuthModeChangeDelegate delegateFunction) -{ - onSTAAuthModeChange = delegateFunction; -} - -void WifiEventsClass::onStationGotIP(StationGotIPDelegate delegateFunction) -{ - onSTAGotIP = delegateFunction; -} - -void WifiEventsClass::onAccessPointConnect(AccessPointConnectDelegate delegateFunction) -{ - onSOFTAPConnect = delegateFunction; -} - -void WifiEventsClass::onAccessPointDisconnect(AccessPointDisconnectDelegate delegateFunction) -{ - onSOFTAPDisconnect = delegateFunction; -} - -void WifiEventsClass::onAccessPointProbeReqRecved(AccessPointProbeReqRecvedDelegate delegateFunction) -{ - onSOFTAPProbeReqRecved = delegateFunction; -} - -void WifiEventsClass::staticWifiEventHandler(System_Event_t* evt) -{ - WifiEvents.WifiEventHandler(evt); + wifi_set_event_handler_cb([](System_Event_t* evt) { WifiEvents.WifiEventHandler(evt); }); } void WifiEventsClass::WifiEventHandler(System_Event_t* evt) diff --git a/Sming/Platform/WifiEvents.h b/Sming/Platform/WifiEvents.h index 86fa65a02b..43456e8c5f 100644 --- a/Sming/Platform/WifiEvents.h +++ b/Sming/Platform/WifiEvents.h @@ -33,16 +33,42 @@ class WifiEventsClass public: WifiEventsClass(); - void onStationConnect(StationConnectDelegate delegateFunction); - void onStationDisconnect(StationDisconnectDelegate delegateFunction); - void onStationAuthModeChange(StationAuthModeChangeDelegate delegateFunction); - void onStationGotIP(StationGotIPDelegate delegateFunction); - void onAccessPointConnect(AccessPointConnectDelegate delegateFunction); - void onAccessPointDisconnect(AccessPointDisconnectDelegate delegateFunction); - void onAccessPointProbeReqRecved(AccessPointProbeReqRecvedDelegate delegateFunction); + void onStationConnect(StationConnectDelegate delegateFunction) + { + onSTAConnect = delegateFunction; + } + + void onStationDisconnect(StationDisconnectDelegate delegateFunction) + { + onSTADisconnect = delegateFunction; + } + + void onStationAuthModeChange(StationAuthModeChangeDelegate delegateFunction) + { + onSTAAuthModeChange = delegateFunction; + } + + void onStationGotIP(StationGotIPDelegate delegateFunction) + { + onSTAGotIP = delegateFunction; + } + + void onAccessPointConnect(AccessPointConnectDelegate delegateFunction) + { + onSOFTAPConnect = delegateFunction; + } + + void onAccessPointDisconnect(AccessPointDisconnectDelegate delegateFunction) + { + onSOFTAPDisconnect = delegateFunction; + } + + void onAccessPointProbeReqRecved(AccessPointProbeReqRecvedDelegate delegateFunction) + { + onSOFTAPProbeReqRecved = delegateFunction; + } private: - static void staticWifiEventHandler(System_Event_t* evt); void WifiEventHandler(System_Event_t* evt); StationConnectDelegate onSTAConnect = nullptr; From 007f915a1e9a6541247d5e3fc9514201004467cc Mon Sep 17 00:00:00 2001 From: mikee47 Date: Sat, 18 May 2019 17:26:57 +0100 Subject: [PATCH 06/19] Initial `Host` architecture implementation Implemented: * Serial port driver emulation, based on gdbstub technique. Socket server support added to allow multiple terminal connection via telnet. * Flash memory emulated using backing file * Dummy gdbstub component (not required) * Task queues * Timers * Basic time functions * Network support for Linux and Windows Dummy modules: * Digital * Interrupts Build * Use different build subdirectory for Linux/Windows (based on UNAME) --- .gitignore | 2 + .gitmodules | 4 + Sming/Arch/Esp8266/build.mk | 3 +- .../Components/driver/include/driver/adc.h | 15 + .../Components/driver/include/driver/gpio.h | 22 + .../Components/driver/include/driver/pwm.h | 65 +++ .../Components/driver/include/driver/uart.h | 4 + Sming/Arch/Host/Components/driver/uart.cpp | 532 ++++++++++++++++++ Sming/Arch/Host/Components/esp_hal/clk.c | 19 + .../Host/Components/esp_hal/include/c_types.h | 27 + .../Components/esp_hal/include/esp_attr.h | 17 + .../Host/Components/esp_hal/include/esp_clk.h | 18 + .../Components/esp_hal/include/esp_libc.h | 18 + .../Components/esp_hal/include/esp_sleep.h | 53 ++ .../Components/esp_hal/include/esp_system.h | 59 ++ .../esp_hal/include/esp_systemapi.h | 62 ++ .../Components/esp_hal/include/esp_tasks.h | 40 ++ .../esp_hal/include/esp_timer_legacy.h | 28 + .../Host/Components/esp_hal/include/gpio.h | 2 + Sming/Arch/Host/Components/esp_hal/libc.c | 43 ++ Sming/Arch/Host/Components/esp_hal/sleep.c | 86 +++ Sming/Arch/Host/Components/esp_hal/system.cpp | 84 +++ Sming/Arch/Host/Components/esp_hal/tasks.cpp | 91 +++ .../Host/Components/esp_hal/timer_legacy.cpp | 62 ++ .../Arch/Host/Components/esp_wifi/esp_wifi.c | 114 ++++ .../esp_wifi/include/esp_smartconfig.h | 50 ++ .../Components/esp_wifi/include/esp_wifi.h | 145 +++++ .../esp_wifi/include/esp_wifi_types.h | 132 +++++ Sming/Arch/Host/Components/fatfs/ff.h | 0 .../Host/Components/gdbstub/gdb_syscall.cpp | 6 + Sming/Arch/Host/Components/gdbstub/gdbcmds | 8 + Sming/Arch/Host/Components/gdbstub/gdbstub.c | 29 + Sming/Arch/Host/Components/heap/heap.c | 7 + .../Arch/Host/Components/heap/include/heap.h | 15 + Sming/Arch/Host/Components/hostlib/except.c | 66 +++ Sming/Arch/Host/Components/hostlib/except.h | 30 + .../Arch/Host/Components/hostlib/flashmem.cpp | 156 +++++ Sming/Arch/Host/Components/hostlib/flashmem.h | 39 ++ Sming/Arch/Host/Components/hostlib/hostapi.h | 35 ++ Sming/Arch/Host/Components/hostlib/hostlib.c | 47 ++ Sming/Arch/Host/Components/hostlib/hostlib.h | 64 +++ Sming/Arch/Host/Components/hostlib/hostmsg.c | 72 +++ Sming/Arch/Host/Components/hostlib/hostmsg.h | 38 ++ .../Arch/Host/Components/hostlib/options.cpp | 92 +++ Sming/Arch/Host/Components/hostlib/options.h | 60 ++ .../Arch/Host/Components/hostlib/sockets.cpp | 455 +++++++++++++++ Sming/Arch/Host/Components/hostlib/sockets.h | 239 ++++++++ .../Arch/Host/Components/hostlib/startup.cpp | 232 ++++++++ Sming/Arch/Host/Components/hostlib/threads.h | 133 +++++ .../Host/Components/hostlib/uart_server.cpp | 212 +++++++ .../Host/Components/hostlib/uart_server.h | 73 +++ Sming/Arch/Host/Components/libc/memmem.c | 37 ++ .../Host/Components/lwip/Linux/CMakeLists.txt | 43 ++ .../Host/Components/lwip/Linux/host_lwip.c | 168 ++++++ .../Components/lwip/Windows/CMakeLists.txt | 59 ++ .../Host/Components/lwip/Windows/host_lwip.c | 226 ++++++++ .../Host/Components/lwip/Windows/lwipcfg.h | 15 + .../Arch/Host/Components/lwip/Windows/npcap.c | 120 ++++ .../Arch/Host/Components/lwip/Windows/npcap.h | 29 + .../Host/Components/lwip/Windows/ntddndis.h | 4 + Sming/Arch/Host/Components/lwip/host_lwip.h | 42 ++ Sming/Arch/Host/Components/lwip/lwip | 1 + Sming/Arch/Host/Components/lwip/lwip.patch | 127 +++++ Sming/Arch/Host/Components/lwip/lwipopts.h | 511 +++++++++++++++++ .../spi_flash/include/esp_spi_flash.h | 4 + Sming/Arch/Host/Core/Digital.cpp | 71 +++ Sming/Arch/Host/Core/HardwareTimer.cpp | 111 ++++ Sming/Arch/Host/Core/Interrupts.cpp | 64 +++ Sming/Arch/Host/Core/pins_arduino.h | 32 ++ Sming/Arch/Host/Platform/AccessPoint.cpp | 73 +++ Sming/Arch/Host/Platform/RTC.cpp | 44 ++ Sming/Arch/Host/Platform/Station.cpp | 251 +++++++++ Sming/Arch/Host/Platform/WifiEvents.cpp | 86 +++ Sming/Arch/Host/System/include/user_config.h | 20 + Sming/Arch/Host/app.mk | 195 +++++++ Sming/Arch/Host/build.mk | 33 ++ Sming/Arch/Host/flash.mk | 41 ++ Sming/Arch/Host/readme.md | 158 ++++++ Sming/Arch/Host/sming.mk | 94 ++++ Sming/Core/Network/Http/HttpConnection.cpp | 6 +- Sming/Core/Network/NetUtils.cpp | 6 +- Sming/Core/SmingCore.h | 5 +- Sming/System/include/gdb/gdb_hooks.h | 4 + Sming/System/include/stringutil.h | 2 + Sming/Wiring/IPAddress.h | 8 +- Sming/build.mk | 7 +- samples/HostTests/Makefile-user.mk | 41 ++ samples/LiveDebug/app/application.cpp | 2 + 88 files changed, 6632 insertions(+), 13 deletions(-) create mode 100644 Sming/Arch/Host/Components/driver/include/driver/adc.h create mode 100644 Sming/Arch/Host/Components/driver/include/driver/gpio.h create mode 100644 Sming/Arch/Host/Components/driver/include/driver/pwm.h create mode 100644 Sming/Arch/Host/Components/driver/include/driver/uart.h create mode 100644 Sming/Arch/Host/Components/driver/uart.cpp create mode 100644 Sming/Arch/Host/Components/esp_hal/clk.c create mode 100644 Sming/Arch/Host/Components/esp_hal/include/c_types.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_attr.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_clk.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_libc.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_system.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_systemapi.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_tasks.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/esp_timer_legacy.h create mode 100644 Sming/Arch/Host/Components/esp_hal/include/gpio.h create mode 100644 Sming/Arch/Host/Components/esp_hal/libc.c create mode 100644 Sming/Arch/Host/Components/esp_hal/sleep.c create mode 100644 Sming/Arch/Host/Components/esp_hal/system.cpp create mode 100644 Sming/Arch/Host/Components/esp_hal/tasks.cpp create mode 100644 Sming/Arch/Host/Components/esp_hal/timer_legacy.cpp create mode 100644 Sming/Arch/Host/Components/esp_wifi/esp_wifi.c create mode 100644 Sming/Arch/Host/Components/esp_wifi/include/esp_smartconfig.h create mode 100644 Sming/Arch/Host/Components/esp_wifi/include/esp_wifi.h create mode 100644 Sming/Arch/Host/Components/esp_wifi/include/esp_wifi_types.h create mode 100644 Sming/Arch/Host/Components/fatfs/ff.h create mode 100644 Sming/Arch/Host/Components/gdbstub/gdb_syscall.cpp create mode 100644 Sming/Arch/Host/Components/gdbstub/gdbcmds create mode 100644 Sming/Arch/Host/Components/gdbstub/gdbstub.c create mode 100644 Sming/Arch/Host/Components/heap/heap.c create mode 100644 Sming/Arch/Host/Components/heap/include/heap.h create mode 100644 Sming/Arch/Host/Components/hostlib/except.c create mode 100644 Sming/Arch/Host/Components/hostlib/except.h create mode 100644 Sming/Arch/Host/Components/hostlib/flashmem.cpp create mode 100644 Sming/Arch/Host/Components/hostlib/flashmem.h create mode 100644 Sming/Arch/Host/Components/hostlib/hostapi.h create mode 100644 Sming/Arch/Host/Components/hostlib/hostlib.c create mode 100644 Sming/Arch/Host/Components/hostlib/hostlib.h create mode 100644 Sming/Arch/Host/Components/hostlib/hostmsg.c create mode 100644 Sming/Arch/Host/Components/hostlib/hostmsg.h create mode 100644 Sming/Arch/Host/Components/hostlib/options.cpp create mode 100644 Sming/Arch/Host/Components/hostlib/options.h create mode 100644 Sming/Arch/Host/Components/hostlib/sockets.cpp create mode 100644 Sming/Arch/Host/Components/hostlib/sockets.h create mode 100644 Sming/Arch/Host/Components/hostlib/startup.cpp create mode 100644 Sming/Arch/Host/Components/hostlib/threads.h create mode 100644 Sming/Arch/Host/Components/hostlib/uart_server.cpp create mode 100644 Sming/Arch/Host/Components/hostlib/uart_server.h create mode 100644 Sming/Arch/Host/Components/libc/memmem.c create mode 100644 Sming/Arch/Host/Components/lwip/Linux/CMakeLists.txt create mode 100644 Sming/Arch/Host/Components/lwip/Linux/host_lwip.c create mode 100644 Sming/Arch/Host/Components/lwip/Windows/CMakeLists.txt create mode 100644 Sming/Arch/Host/Components/lwip/Windows/host_lwip.c create mode 100644 Sming/Arch/Host/Components/lwip/Windows/lwipcfg.h create mode 100644 Sming/Arch/Host/Components/lwip/Windows/npcap.c create mode 100644 Sming/Arch/Host/Components/lwip/Windows/npcap.h create mode 100644 Sming/Arch/Host/Components/lwip/Windows/ntddndis.h create mode 100644 Sming/Arch/Host/Components/lwip/host_lwip.h create mode 160000 Sming/Arch/Host/Components/lwip/lwip create mode 100644 Sming/Arch/Host/Components/lwip/lwip.patch create mode 100644 Sming/Arch/Host/Components/lwip/lwipopts.h create mode 100644 Sming/Arch/Host/Components/spi_flash/include/esp_spi_flash.h create mode 100644 Sming/Arch/Host/Core/Digital.cpp create mode 100644 Sming/Arch/Host/Core/HardwareTimer.cpp create mode 100644 Sming/Arch/Host/Core/Interrupts.cpp create mode 100644 Sming/Arch/Host/Core/pins_arduino.h create mode 100644 Sming/Arch/Host/Platform/AccessPoint.cpp create mode 100644 Sming/Arch/Host/Platform/RTC.cpp create mode 100644 Sming/Arch/Host/Platform/Station.cpp create mode 100644 Sming/Arch/Host/Platform/WifiEvents.cpp create mode 100644 Sming/Arch/Host/System/include/user_config.h create mode 100644 Sming/Arch/Host/app.mk create mode 100644 Sming/Arch/Host/build.mk create mode 100644 Sming/Arch/Host/flash.mk create mode 100644 Sming/Arch/Host/readme.md create mode 100644 Sming/Arch/Host/sming.mk create mode 100644 samples/HostTests/Makefile-user.mk diff --git a/.gitignore b/.gitignore index 8442c6d179..310a9a3186 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ vssver2.scc .metadata .submodule +/Sming/Arch/Host/Components/lwip/Windows/src +/Sming/Arch/Host/Components/lwip/Windows/tmp diff --git a/.gitmodules b/.gitmodules index ec9674fefe..8b76287fe2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -100,4 +100,8 @@ [submodule "Libraries.ArduinoJson"] path = Sming/Libraries/ArduinoJson url = https://github.com/bblanchon/ArduinoJson.git + +[submodule "Host.lwip"] + path = Sming/Arch/Host/Components/lwip/lwip + url = git://git.savannah.gnu.org/lwip.git ignore = dirty diff --git a/Sming/Arch/Esp8266/build.mk b/Sming/Arch/Esp8266/build.mk index 3647d3bec5..15eaf0793e 100644 --- a/Sming/Arch/Esp8266/build.mk +++ b/Sming/Arch/Esp8266/build.mk @@ -4,7 +4,8 @@ # ############## -CFLAGS += -DARCH_ESP8266 +CFLAGS += -DARCH_ESP8266 +CXXFLAGS += -fno-rtti -fno-exceptions ifndef ESP_HOME $(error ESP_HOME variable is not set to a valid directory.) diff --git a/Sming/Arch/Host/Components/driver/include/driver/adc.h b/Sming/Arch/Host/Components/driver/include/driver/adc.h new file mode 100644 index 0000000000..9dd39af641 --- /dev/null +++ b/Sming/Arch/Host/Components/driver/include/driver/adc.h @@ -0,0 +1,15 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint16_t system_adc_read(void); +void system_adc_read_fast(uint16_t* adc_addr, uint16_t adc_num, uint8_t adc_clk_div); +uint16_t system_get_vdd33(void); + +#ifdef __cplusplus +} +#endif + diff --git a/Sming/Arch/Host/Components/driver/include/driver/gpio.h b/Sming/Arch/Host/Components/driver/include/driver/gpio.h new file mode 100644 index 0000000000..f8037eab5f --- /dev/null +++ b/Sming/Arch/Host/Components/driver/include/driver/gpio.h @@ -0,0 +1,22 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Core/Interrupts.h */ + +typedef enum { + GPIO_PIN_INTR_DISABLE = 0, + GPIO_PIN_INTR_POSEDGE = 1, + GPIO_PIN_INTR_NEGEDGE = 2, + GPIO_PIN_INTR_ANYEDGE = 3, + GPIO_PIN_INTR_LOLEVEL = 4, + GPIO_PIN_INTR_HILEVEL = 5 +} GPIO_INT_TYPE; + +#ifdef __cplusplus +} +#endif + diff --git a/Sming/Arch/Host/Components/driver/include/driver/pwm.h b/Sming/Arch/Host/Components/driver/include/driver/pwm.h new file mode 100644 index 0000000000..b003ec121a --- /dev/null +++ b/Sming/Arch/Host/Components/driver/include/driver/pwm.h @@ -0,0 +1,65 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __PWM_H__ +#define __PWM_H__ + +#pragma once + +#if defined(__cplusplus) +extern "C" { +#endif + +/*pwm.h: function and macro definition of PWM API , driver level */ +/*user_light.h: user interface for light API, user level*/ +/*user_light_adj: API for color changing and lighting effects, user level*/ + +/*NOTE!! : DO NOT CHANGE THIS FILE*/ + +/*SUPPORT UP TO 8 PWM CHANNEL*/ +#define PWM_CHANNEL_NUM_MAX 8 + +//struct pwm_param { +// uint32_t period; +// uint32_t freq; +// uint32_t duty[PWM_CHANNEL_NUM_MAX]; //PWM_CHANNEL<=8 +//}; +// +///* pwm_init should be called only once, for now */ +//void pwm_init(uint32_t period, uint32_t* duty, uint32_t pwm_channel_num, uint32_t (*pin_info_list)[3]); +//void pwm_start(void); +// +//void pwm_set_duty(uint32_t duty, uint8_t channel); +//uint32_t pwm_get_duty(uint8_t channel); +//void pwm_set_period(uint32_t period); +//uint32_t pwm_get_period(void); +// +//uint32_t get_pwm_version(void); +//void set_pwm_debug_en(uint8_t print_en); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/Sming/Arch/Host/Components/driver/include/driver/uart.h b/Sming/Arch/Host/Components/driver/include/driver/uart.h new file mode 100644 index 0000000000..f3ee98eb04 --- /dev/null +++ b/Sming/Arch/Host/Components/driver/include/driver/uart.h @@ -0,0 +1,4 @@ + + +#include +#include_next diff --git a/Sming/Arch/Host/Components/driver/uart.cpp b/Sming/Arch/Host/Components/driver/uart.cpp new file mode 100644 index 0000000000..7e68f53613 --- /dev/null +++ b/Sming/Arch/Host/Components/driver/uart.cpp @@ -0,0 +1,532 @@ +/* + uart.cpp - esp8266 UART HAL + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + @author 2018 mikee47 + + Additional features to support flexible transmit buffering and callbacks + + */ + +#include +#include +#include +#include + +/* + * Parameters relating to RX FIFO and buffer thresholds + * + * 'headroom' is the number of characters which may be received before a receive overrun + * condition occurs and data is lost. + * + * For the hardware FIFO, data is processed via interrupt so the headroom can be fairly small. + * The greater the headroom, the more interrupts will be generated thus reducing efficiency. + */ +#define RX_FIFO_FULL_THRESHOLD 120 ///< UIFF interrupt when FIFO bytes > threshold +#define RX_FIFO_HEADROOM (UART_RX_FIFO_SIZE - RX_FIFO_FULL_THRESHOLD) ///< Chars between UIFF and UIOF +/* + * Using a buffer, data is typically processed via task callback so requires additional time. + * This figure is set to a nominal default which should provide robust operation for most situations. + * It can be adjusted if necessary via the rx_headroom parameter. +*/ +#define DEFAULT_RX_HEADROOM (32 - RX_FIFO_HEADROOM) + +static int s_uart_debug_nr = UART_NO; + +// Keep track of interrupt enable state for each UART +static uint8_t isrMask; +// Keep a reference to all created UARTS - required because they share an ISR +static uart_t* uartInstances[UART_COUNT]; + +// Registered port callback functions +static uart_notify_callback_t notifyCallbacks[UART_COUNT]; + +/** @brief Invoke a port callback, if one has been registered + * @param uart + * @param code + */ +static void notify(uart_t* uart, uart_notify_code_t code) +{ + auto callback = notifyCallbacks[uart->uart_nr]; + if(callback != nullptr) { + callback(uart, code); + } +} + +__forceinline static bool uart_isr_enabled(uint8_t nr) +{ + return bitRead(isrMask, nr); +} + +uart_t* uart_get_uart(uint8_t uart_nr) +{ + return (uart_nr < UART_COUNT) ? uartInstances[uart_nr] : nullptr; +} + +uint8_t uart_disable_interrupts() +{ + return isrMask; +} + +void uart_restore_interrupts() +{ +} + +bool uart_set_notify(unsigned uart_nr, uart_notify_callback_t callback) +{ + if(uart_nr >= UART_COUNT) { + return false; + } + + notifyCallbacks[uart_nr] = callback; + return true; +} + +void uart_set_callback(uart_t* uart, uart_callback_t callback, void* param) +{ + if(uart != nullptr) { + uart->callback = nullptr; // In case interrupt fires between setting param and callback + uart->param = param; + uart->callback = callback; + } +} + +static bool realloc_buffer(SerialBuffer*& buffer, size_t new_size) +{ + if(buffer != nullptr) { + if(new_size == 0) { + uart_disable_interrupts(); + delete buffer; + buffer = nullptr; + uart_restore_interrupts(); + return true; + } + + return buffer->resize(new_size) == new_size; + } + + if(new_size == 0) { + return true; + } + + auto new_buf = new SerialBuffer; + if(new_buf != nullptr && new_buf->resize(new_size) == new_size) { + buffer = new_buf; + return true; + } + + delete new_buf; + return false; +} + +size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size) +{ + if(uart_rx_enabled(uart)) { + realloc_buffer(uart->rx_buffer, new_size); + } + return uart_rx_buffer_size(uart); +} + +size_t uart_rx_buffer_size(uart_t* uart) +{ + return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->getSize() : 0; +} + +size_t uart_resize_tx_buffer(uart_t* uart, size_t new_size) +{ + if(uart_tx_enabled(uart)) { + realloc_buffer(uart->tx_buffer, new_size); + } + return uart_tx_buffer_size(uart); +} + +size_t uart_tx_buffer_size(uart_t* uart) +{ + return uart != nullptr && uart->tx_buffer != nullptr ? uart->tx_buffer->getSize() : 0; +} + +int uart_peek_char(uart_t* uart) +{ + return uart != nullptr && uart->rx_buffer ? uart->rx_buffer->peekChar() : -1; +} + +int uart_rx_find(uart_t* uart, char c) +{ + if(uart == nullptr || uart->rx_buffer == nullptr) { + return -1; + } + + return uart->rx_buffer->find(c); +} + +int uart_peek_last_char(uart_t* uart) +{ + return uart != nullptr && uart->rx_buffer != nullptr ? uart->rx_buffer->peekLastChar() : -1; +} + +size_t uart_read(uart_t* uart, void* buffer, size_t size) +{ + if(!uart_rx_enabled(uart) || buffer == nullptr || size == 0) { + return 0; + } + + notify(uart, UART_NOTIFY_BEFORE_READ); + + size_t read = 0; + + auto buf = static_cast(buffer); + + // First read data from RX buffer if in use + if(uart->rx_buffer != nullptr) { + while(read < size && !uart->rx_buffer->isEmpty()) + buf[read++] = uart->rx_buffer->readChar(); + } + + return read; +} + +size_t uart_rx_available(uart_t* uart) +{ + if(!uart_rx_enabled(uart)) { + return 0; + } + + uart_disable_interrupts(); + + size_t avail = 0; + + if(uart->rx_buffer != nullptr) { + avail += uart->rx_buffer->available(); + } + + uart_restore_interrupts(); + + return avail; +} + +void uart_start_isr(uart_t* uart) +{ + if(!bitRead(isrMask, uart->uart_nr)) { + bitSet(isrMask, uart->uart_nr); + } +} + +size_t uart_write(uart_t* uart, const void* buffer, size_t size) +{ + if(!uart_tx_enabled(uart) || buffer == nullptr || size == 0) { + return 0; + } + + size_t written = 0; + + auto buf = static_cast(buffer); + + while(written < size) { + if(uart->tx_buffer != nullptr) { + while(written < size && uart->tx_buffer->writeChar(buf[written])) { + ++written; + } + } + + notify(uart, UART_NOTIFY_AFTER_WRITE); + + if(!bitRead(uart->options, UART_OPT_TXWAIT)) { + break; + } + } + + return written; +} + +size_t uart_tx_free(uart_t* uart) +{ + if(!uart_tx_enabled(uart)) { + return 0; + } + + uart_disable_interrupts(); + + size_t space = 0; + if(uart->tx_buffer != nullptr) { + space += uart->tx_buffer->getFreeSpace(); + } + + uart_restore_interrupts(); + + return space; +} + +void uart_wait_tx_empty(uart_t* uart) +{ + if(!uart_tx_enabled(uart)) { + return; + } + + notify(uart, UART_NOTIFY_WAIT_TX); + + if(uart->tx_buffer != nullptr) { + while(!uart->tx_buffer->isEmpty()) { + delay(0); + } + } +} + +void uart_set_break(uart_t* uart, bool state) +{ + // uart = get_physical(uart); + // if(uart != nullptr) { + // bitWrite(USC0(uart->uart_nr), UCBRK, state); + // } +} + +uint8_t uart_get_status(uart_t* uart) +{ + uint8_t status = 0; + // if(uart != nullptr) { + // uart_disable_interrupts(); + // // Get break/overflow flags from actual uart (physical or otherwise) + // status = uart->status & (_BV(UIBD) | _BV(UIOF)); + // uart->status = 0; + // // Read raw status register directly from real uart, masking out non-error bits + // uart = get_physical(uart); + // if(uart != nullptr) { + // status |= USIR(uart->uart_nr) & (_BV(UIBD) | _BV(UIOF) | _BV(UIFR) | _BV(UIPE)); + // // Clear errors + // USIC(uart->uart_nr) = status; + // } + // uart_restore_interrupts(); + // } + return status; +} + +void uart_flush(uart_t* uart, uart_mode_t mode) +{ + if(uart == nullptr) { + return; + } + + bool flushRx = mode != UART_TX_ONLY && uart->mode != UART_TX_ONLY; + bool flushTx = mode != UART_RX_ONLY && uart->mode != UART_RX_ONLY; + + uart_disable_interrupts(); + if(flushRx && uart->rx_buffer != nullptr) { + uart->rx_buffer->clear(); + } + + if(flushTx && uart->tx_buffer != nullptr) { + uart->tx_buffer->clear(); + } + + uart_restore_interrupts(); +} + +uint32_t uart_set_baudrate_reg(int uart_nr, uint32_t baud_rate) +{ + // if(!is_physical(uart_nr) || baud_rate == 0) { + // return 0; + // } + // + // uint32_t clkdiv = ESP8266_CLOCK / baud_rate; + // USD(uart_nr) = clkdiv; + // // Return the actual baud rate in use + // baud_rate = clkdiv ? ESP8266_CLOCK / clkdiv : 0; + return baud_rate; +} + +uint32_t uart_set_baudrate(uart_t* uart, uint32_t baud_rate) +{ + if(uart == nullptr) { + return 0; + } + + baud_rate = uart_set_baudrate_reg(uart->uart_nr, baud_rate); + // Store the actual baud rate in use + uart->baud_rate = baud_rate; + return baud_rate; +} + +uint32_t uart_get_baudrate(uart_t* uart) +{ + return (uart == nullptr) ? 0 : uart->baud_rate; +} + +uart_t* uart_init_ex(const uart_config& cfg) +{ + // Already initialised? + if(uart_get_uart(cfg.uart_nr) != nullptr) { + return nullptr; + } + + auto uart = new uart_t; + if(uart == nullptr) { + return nullptr; + } + + memset(uart, 0, sizeof(uart_t)); + uart->uart_nr = cfg.uart_nr; + uart->mode = cfg.mode; + uart->options = cfg.options; + uart->tx_pin = 255; + uart->rx_pin = 255; + uart->rx_headroom = DEFAULT_RX_HEADROOM; + + auto rxBufferSize = cfg.rx_size; + auto txBufferSize = cfg.tx_size; + + // Virtual uart requires a minimum RAM buffer + rxBufferSize += UART_RX_FIFO_SIZE; + txBufferSize += UART_TX_FIFO_SIZE; + + switch(cfg.uart_nr) { + case UART0: + case UART2: + if(uart_rx_enabled(uart) && !realloc_buffer(uart->rx_buffer, rxBufferSize)) { + delete uart; + return nullptr; + } + + if(uart_tx_enabled(uart) && !realloc_buffer(uart->tx_buffer, txBufferSize)) { + delete uart->rx_buffer; + delete uart; + return nullptr; + } + + if(cfg.uart_nr == UART2) { + break; + } + + // OK, buffers allocated so setup hardware + uart_detach(cfg.uart_nr); + + break; + + case UART1: + // Note: uart_interrupt_handler does not support RX on UART 1 + if(uart->mode == UART_RX_ONLY) { + delete uart; + return nullptr; + } + uart->mode = UART_TX_ONLY; + + // Transmit buffer optional + if(!realloc_buffer(uart->tx_buffer, txBufferSize)) { + delete uart; + return nullptr; + } + + // Setup hardware + uart_detach(cfg.uart_nr); + break; + + default: + // big fail! + delete uart; + return nullptr; + } + + uart_set_baudrate(uart, cfg.baudrate); + uart_flush(uart); + uartInstances[cfg.uart_nr] = uart; + uart_start_isr(uart); + + notify(uart, UART_NOTIFY_AFTER_OPEN); + + return uart; +} + +void uart_uninit(uart_t* uart) +{ + if(uart == nullptr) { + return; + } + + notify(uart, UART_NOTIFY_BEFORE_CLOSE); + + uart_stop_isr(uart); + // If debug output being sent to this UART, disable it + if(uart->uart_nr == s_uart_debug_nr) { + uart_set_debug(UART_NO); + } + + delete uart->rx_buffer; + delete uart->tx_buffer; + delete uart; +} + +uart_t* uart_init(uint8_t uart_nr, uint32_t baudrate, uint32_t config, uart_mode_t mode, uint8_t tx_pin, size_t rx_size, + size_t tx_size) +{ + uart_config cfg = {.uart_nr = uart_nr, + .tx_pin = tx_pin, + .mode = mode, + .options = _BV(UART_OPT_TXWAIT), + .baudrate = baudrate, + .config = config, + .rx_size = rx_size, + .tx_size = tx_size}; + return uart_init_ex(cfg); +} + +void uart_swap(uart_t* uart, int tx_pin) +{ +} + +void uart_set_tx(uart_t* uart, int tx_pin) +{ +} + +void uart_set_pins(uart_t* uart, int tx, int rx) +{ +} + +void uart_debug_putc(char c) +{ + uart_t* uart = uart_get_uart(s_uart_debug_nr); + if(uart != nullptr) { + uart_write_char(uart, c); + } +} + +void uart_set_debug(int uart_nr) +{ + s_uart_debug_nr = uart_nr; + system_set_os_print(uart_nr >= 0); + ets_install_putc1(uart_debug_putc); +} + +int uart_get_debug() +{ + return s_uart_debug_nr; +} + +void uart_detach(int uart_nr) +{ + bitClear(isrMask, uart_nr); +} + +void uart_detach_all() +{ + // uart_disable_interrupts(); + // for(unsigned uart_nr = 0; uart_nr < UART_PHYSICAL_COUNT; ++uart_nr) { + // USC1(uart_nr) = 0; + // USIC(uart_nr) = 0xffff; + // USIE(uart_nr) = 0; + // } + // isrMask = 0; +} diff --git a/Sming/Arch/Host/Components/esp_hal/clk.c b/Sming/Arch/Host/Components/esp_hal/clk.c new file mode 100644 index 0000000000..2a5593e891 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/clk.c @@ -0,0 +1,19 @@ +#include "include/esp_clk.h" + +// The current CPU frequency +static uint8_t __cpu_frequency = 80; + +bool system_update_cpu_freq(uint8 freq) +{ + if(freq == 80 || freq == 160) { + __cpu_frequency = freq; + return true; + } else { + return false; + } +} + +uint8 system_get_cpu_freq(void) +{ + return __cpu_frequency; +} diff --git a/Sming/Arch/Host/Components/esp_hal/include/c_types.h b/Sming/Arch/Host/Components/esp_hal/include/c_types.h new file mode 100644 index 0000000000..6c0deec22f --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/c_types.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +// Non-preferred types commonly used in Arduino libraries +typedef uint8_t uint8; +typedef uint8_t u8; +typedef int8_t sint8; +typedef int8_t int8; +typedef int8_t s8; +typedef uint16_t uint16; +typedef uint16_t u16; +typedef int16_t sint16; +typedef int16_t s16; +typedef uint32_t uint32; +typedef uint32_t u_int; +typedef uint32_t u32; +typedef int32_t sint32; +typedef int32_t s32; +typedef int32_t int32; +typedef int64_t sint64; +typedef uint64_t uint64; +typedef uint64_t u64; +typedef float real32; +typedef double real64; diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_attr.h b/Sming/Arch/Host/Components/esp_hal/include/esp_attr.h new file mode 100644 index 0000000000..b515f6befc --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_attr.h @@ -0,0 +1,17 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IRAM_ATTR +#define STORE_TYPEDEF_ATTR __attribute__((aligned(4), packed)) +#define STORE_ATTR __attribute__((aligned(4))) +#define ICACHE_FLASH_ATTR + +#define GDB_IRAM_ATTR + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_clk.h b/Sming/Arch/Host/Components/esp_hal/include/esp_clk.h new file mode 100644 index 0000000000..b4a5ec20e9 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_clk.h @@ -0,0 +1,18 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Frequencies in MHz */ + +#define SYS_CPU_80MHZ 80 +#define SYS_CPU_160MHZ 160 + +bool system_update_cpu_freq(uint8 freq); +uint8 system_get_cpu_freq(void); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_libc.h b/Sming/Arch/Host/Components/esp_hal/include/esp_libc.h new file mode 100644 index 0000000000..496858fe91 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_libc.h @@ -0,0 +1,18 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t os_random(void); +int os_get_random(uint8_t* buf, size_t len); + +void ets_install_putc1(void (*p)(char c)); +void system_set_os_print(bool onoff); + +#define ets_memcpy(dest, src, n) memcpy(dest, src, n) + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h b/Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h new file mode 100644 index 0000000000..460f7942a7 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_sleep.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum sleep_type { + NONE_SLEEP_T = 0, + LIGHT_SLEEP_T, + MODEM_SLEEP_T, +}; + +typedef void (*fpm_wakeup_cb)(void); + +void system_deep_sleep(uint32_t time_in_us); +bool system_deep_sleep_set_option(uint8_t option); + +/* Forced sleep */ + +void wifi_fpm_open(void); +void wifi_fpm_close(void); +void wifi_fpm_do_wakeup(void); +void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb); +sint8 wifi_fpm_do_sleep(uint32_t sleep_time_in_us); +void wifi_fpm_set_sleep_type(enum sleep_type type); +enum sleep_type wifi_fpm_get_sleep_type(void); +void wifi_fpm_auto_sleep_set_in_null_mode(uint8_t req); + +/* GPIO */ + +void wifi_enable_gpio_wakeup(uint32 i, GPIO_INT_TYPE intr_status); +void wifi_disable_gpio_wakeup(void); + +/* These aren't defined in the RTOS SDK */ + +enum sleep_level { + MIN_SLEEP_T, + MAX_SLEEP_T, +}; + +bool wifi_set_sleep_type(enum sleep_type type); +enum sleep_type wifi_get_sleep_type(void); +bool wifi_set_sleep_level(enum sleep_level level); +enum sleep_level wifi_get_sleep_level(void); +bool wifi_set_listen_interval(uint8_t interval); +uint8_t wifi_get_listen_interval(void); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_system.h b/Sming/Arch/Host/Components/esp_hal/include/esp_system.h new file mode 100644 index 0000000000..21a911751f --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_system.h @@ -0,0 +1,59 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void system_restart(void); + +void system_soft_wdt_stop(void); +void system_soft_wdt_restart(void); +void system_soft_wdt_feed(void); + +/* Arch/Esp8266/Components/spiffs/spiffs_sming.c */ +#define ETS_INTR_LOCK() ets_intr_lock() +#define ETS_INTR_UNLOCK() ets_intr_unlock() + +void ets_intr_lock(); +void ets_intr_unlock(); +void xt_disable_interrupts(); +void xt_enable_interrupts(); + +enum rst_reason { + REASON_DEFAULT_RST = 0, + REASON_WDT_RST = 1, + REASON_EXCEPTION_RST = 2, + REASON_SOFT_WDT_RST = 3, + REASON_SOFT_RESTART = 4, + REASON_DEEP_SLEEP_AWAKE = 5, + REASON_EXT_SYS_RST = 6 +}; + +struct rst_info { + uint32_t reason; + uint32_t exccause; + uint32_t epc1; + uint32_t epc2; + uint32_t epc3; + uint32_t excvaddr; + uint32_t depc; +}; + +struct rst_info* system_get_rst_info(void); + +/* System/include/debug_progmem.h */ +uint32_t system_get_time(void); + +/* Implementing NOW() macro, fixed at 1us */ +#define TIMER_CLK_FREQ 1000000UL +uint32_t os_get_ticks(); +#define NOW() os_get_ticks() + +void os_delay_us(uint32_t us); + +const char* system_get_sdk_version(void); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_systemapi.h b/Sming/Arch/Host/Components/esp_hal/include/esp_systemapi.h new file mode 100644 index 0000000000..74750353fa --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_systemapi.h @@ -0,0 +1,62 @@ +/* + * esp_systemapi.h + * + * Created on: 28 Aug 2018 + * Author: Mike + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// ESP SDK config +#define LWIP_OPEN_SRC +#define USE_US_TIMER + +// Default types +#include +#include "c_types.h" + +struct ip_addr { + uint32_t addr; +}; + +#include +#include "esp_attr.h" +#include "esp_clk.h" +#include "esp_libc.h" +#include "esp_tasks.h" +#include "esp_timer_legacy.h" +#include +#include "esp_system.h" +#include +#include +#include +#include +#include "esp_sleep.h" + +#include + +#include +#include +#include + +#include + +#include "debug_progmem.h" +#define debugf debug_i + +#define SYSTEM_ERROR(fmt, ...) hostmsg("ERROR: " fmt "\r\n", ##__VA_ARGS__) + +#define noInterrupts() +#define interrupts() + + +//#include +//#include + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_tasks.h b/Sming/Arch/Host/Components/esp_hal/include/esp_tasks.h new file mode 100644 index 0000000000..67bc6a44aa --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_tasks.h @@ -0,0 +1,40 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t os_signal_t; +typedef uint32_t os_param_t; + +typedef struct { + os_signal_t sig; + os_param_t par; +} os_event_t; + +enum { + USER_TASK_PRIO_0, + USER_TASK_PRIO_1, + USER_TASK_PRIO_2, + USER_TASK_PRIO_MAX, +}; + +typedef void (*os_task_t)(os_event_t* e); + +bool system_os_task(os_task_t task, uint8_t prio, os_event_t* queue, uint8_t qlen); +bool system_os_post(uint8_t prio, os_signal_t sig, os_param_t par); + +// Setup default task queues +void host_init_tasks(); + +// Hook function to process task queues +void host_service_tasks(); + +typedef void (*host_task_callback_t)(uint32_t param); + +void host_queue_callback(host_task_callback_t callback, uint32_t param); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/esp_timer_legacy.h b/Sming/Arch/Host/Components/esp_hal/include/esp_timer_legacy.h new file mode 100644 index 0000000000..6f02542ea4 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/esp_timer_legacy.h @@ -0,0 +1,28 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void os_timer_func_t(void* timer_arg); + +struct os_timer_t { + struct os_timer_t* timer_next; + uint32_t timer_expire; + uint32_t timer_period; + os_timer_func_t* timer_func; + void* timer_arg; +}; + +void os_timer_arm(struct os_timer_t* ptimer, uint32_t time, bool repeat_flag); +void os_timer_arm_us(struct os_timer_t* ptimer, uint32_t time, bool repeat_flag); +void os_timer_disarm(struct os_timer_t* ptimer); +void os_timer_setfn(struct os_timer_t* ptimer, os_timer_func_t* pfunction, void* parg); + +// Hook function to service timers +void host_service_timers(); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_hal/include/gpio.h b/Sming/Arch/Host/Components/esp_hal/include/gpio.h new file mode 100644 index 0000000000..f182070cca --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/include/gpio.h @@ -0,0 +1,2 @@ +// @deprecated use #include +#include diff --git a/Sming/Arch/Host/Components/esp_hal/libc.c b/Sming/Arch/Host/Components/esp_hal/libc.c new file mode 100644 index 0000000000..0396634bbe --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/libc.c @@ -0,0 +1,43 @@ + +#include "include/esp_libc.h" + +#include +#include + +/* Random numbers */ + +uint32_t os_random(void) +{ + srand(time(NULL)); + return rand(); +} + +int os_get_random(uint8_t* buf, size_t len) +{ + srand(time(NULL)); + + // RAND_MAX is 0x7fff + uint16_t n = rand(); + for(size_t i = 0; i < len; ++i) { + if(i % 2 == 0) + n = rand(); + buf[i] = n; + n >>= 8; + } + + // Success + return 0; +} + +/* Misc */ + +void ets_install_putc1(void (*p)(char c)) +{ + // +} + +void system_set_os_print(bool onoff) +{ + // +} + diff --git a/Sming/Arch/Host/Components/esp_hal/sleep.c b/Sming/Arch/Host/Components/esp_hal/sleep.c new file mode 100644 index 0000000000..0bf7d24205 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/sleep.c @@ -0,0 +1,86 @@ +#include "include/esp_sleep.h" + +void system_deep_sleep(uint32_t time_in_us) +{ +} + +bool system_deep_sleep_set_option(uint8_t option) +{ + return false; +} + +void wifi_fpm_open(void) +{ +} + +void wifi_fpm_close(void) +{ +} + +void wifi_fpm_do_wakeup(void) +{ +} + +void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb) +{ +} + +sint8 wifi_fpm_do_sleep(uint32_t sleep_time_in_us) +{ + return -2; // not enabled +} + +void wifi_fpm_set_sleep_type(enum sleep_type type) +{ +} + +enum sleep_type wifi_fpm_get_sleep_type(void) +{ + return NONE_SLEEP_T; +} + +void wifi_fpm_auto_sleep_set_in_null_mode(uint8_t req) +{ +} + +/* GPIO */ + +void wifi_enable_gpio_wakeup(uint32 i, GPIO_INT_TYPE intr_status) +{ +} + +void wifi_disable_gpio_wakeup(void) +{ +} + +/* These aren't defined in the RTOS SDK */ + +bool wifi_set_sleep_type(enum sleep_type type) +{ + return type == NONE_SLEEP_T; +} + +enum sleep_type wifi_get_sleep_type(void) +{ + return NONE_SLEEP_T; +} + +bool wifi_set_sleep_level(enum sleep_level level) +{ + return false; +} + +enum sleep_level wifi_get_sleep_level(void) +{ + return MIN_SLEEP_T; +} + +bool wifi_set_listen_interval(uint8_t interval) +{ + return false; +} + +uint8_t wifi_get_listen_interval(void) +{ + return 0; +} diff --git a/Sming/Arch/Host/Components/esp_hal/system.cpp b/Sming/Arch/Host/Components/esp_hal/system.cpp new file mode 100644 index 0000000000..fe0de215f3 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/system.cpp @@ -0,0 +1,84 @@ +#include "include/esp_system.h" +#include + +/* System time */ + +#include +using namespace std::chrono; + +static high_resolution_clock::time_point system_start_time = high_resolution_clock::now(); + +// From pthreads library +extern "C" int sched_yield(void); + +uint32_t os_get_ticks() +{ + return duration_cast(high_resolution_clock::now() - system_start_time).count(); +} + +uint32_t system_get_time() +{ + return os_get_ticks(); +} + +void os_delay_us(uint32_t us) +{ + auto start = system_get_time(); + while(system_get_time() - start < us) { + // + } +} + +/* Core system */ + +struct rst_info* system_get_rst_info(void) +{ + static rst_info info = {REASON_DEFAULT_RST}; + return &info; +} + +void system_restart(void) +{ + host_exit(0); +} + +/* Watchdog */ + +void system_soft_wdt_feed(void) +{ + sched_yield(); +} + +void system_soft_wdt_stop(void) +{ +} + +void system_soft_wdt_restart(void) +{ +} + +/* Misc */ + +const char* system_get_sdk_version(void) +{ + static const char version_string[] = "Host-SDK-v1.0"; + return version_string; +} + +/* Interrupts */ + +void ets_intr_lock() +{ +} + +void ets_intr_unlock() +{ +} + +void xt_disable_interrupts() +{ +} + +void xt_enable_interrupts() +{ +} diff --git a/Sming/Arch/Host/Components/esp_hal/tasks.cpp b/Sming/Arch/Host/Components/esp_hal/tasks.cpp new file mode 100644 index 0000000000..c9c6432241 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/tasks.cpp @@ -0,0 +1,91 @@ +#include "include/esp_tasks.h" +#include +#include + +struct task_queue_t { + os_task_t callback; + os_event_t* events; + uint8_t read; + uint8_t count; + uint8_t length; + + void init(os_task_t callback, os_event_t* events, uint8_t length) + { + this->callback = callback; + this->events = events; + this->length = length; + read = count = 0; + } + + bool post(os_signal_t sig, os_param_t par) + { + if(count == length) { + return false; + } + + events[(read + count) % length] = os_event_t{sig, par}; + ++count; + return true; + } + + void process() + { + while(count != 0) { + auto evt = events[read]; + read = (read + 1) % length; + --count; + callback(&evt); + } + } +}; + +static task_queue_t task_queues[USER_TASK_PRIO_MAX + 1]; + +const uint8_t HOST_TASK_PRIO = USER_TASK_PRIO_MAX; + +bool system_os_task(os_task_t callback, uint8_t prio, os_event_t* events, uint8_t qlen) +{ + if(prio >= USER_TASK_PRIO_MAX) { + hostmsg("Invalid priority %u", prio); + return false; + } + + task_queues[prio].init(callback, events, qlen); + return true; +} + +bool system_os_post(uint8_t prio, os_signal_t sig, os_param_t par) +{ + if(prio >= USER_TASK_PRIO_MAX) { + hostmsg("Invalid priority %u", prio); + return false; + } + + return task_queues[prio].post(sig, par); +} + +void host_init_tasks() +{ + static os_event_t events[32]; + + task_queues[HOST_TASK_PRIO].init( + [](os_event_t* event) { + auto callback = host_task_callback_t(event->sig); + if(callback) { + callback(event->par); + } + }, + events, ARRAY_SIZE(events)); +} + +void host_service_tasks() +{ + for(int prio = HOST_TASK_PRIO; prio >= 0; --prio) { + task_queues[prio].process(); + } +} + +void host_queue_callback(host_task_callback_t callback, uint32_t param) +{ + task_queues[HOST_TASK_PRIO].post(os_signal_t(callback), param); +} diff --git a/Sming/Arch/Host/Components/esp_hal/timer_legacy.cpp b/Sming/Arch/Host/Components/esp_hal/timer_legacy.cpp new file mode 100644 index 0000000000..a47d6cfe43 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_hal/timer_legacy.cpp @@ -0,0 +1,62 @@ + +#include "include/esp_system.h" +#include "include/esp_timer_legacy.h" + +// Dummy timer, never gets used just makes code simpler +static os_timer_t timer_head = {0}; + +void os_timer_arm(struct os_timer_t* ptimer, uint32_t time, bool repeat_flag) +{ + os_timer_arm_us(ptimer, time * 1000UL, repeat_flag); +} + +void os_timer_arm_us(struct os_timer_t* ptimer, uint32_t time, bool repeat_flag) +{ + os_timer_disarm(ptimer); + auto t = &timer_head; + while(t->timer_next != nullptr) { + t = t->timer_next; + } + ptimer->timer_next = nullptr; + ptimer->timer_expire = system_get_time() + time; + ptimer->timer_period = repeat_flag ? time : 0; + t->timer_next = ptimer; +} + +void os_timer_disarm(struct os_timer_t* ptimer) +{ + auto t_prev = &timer_head; + for(auto t = t_prev->timer_next; t != nullptr; t_prev = t, t = t->timer_next) { + if(t == ptimer) { + t_prev->timer_next = t->timer_next; + break; + } + } +} + +void os_timer_setfn(struct os_timer_t* ptimer, os_timer_func_t* pfunction, void* parg) +{ + if(ptimer != nullptr) { + ptimer->timer_func = pfunction; + ptimer->timer_arg = parg; + } +} + +void host_service_timers() +{ + auto time_now = system_get_time(); + auto t_prev = &timer_head; + for(auto t = t_prev->timer_next; t != nullptr; t_prev = t, t = t->timer_next) { + if(t->timer_expire > time_now) { + continue; + } + if(t->timer_period == 0) { + // Non-repeating timer, remove now + t_prev->timer_next = t->timer_next; + } + if(t->timer_func != nullptr) { + t->timer_func(t->timer_arg); + } + t->timer_expire = time_now + t->timer_period; + } +} diff --git a/Sming/Arch/Host/Components/esp_wifi/esp_wifi.c b/Sming/Arch/Host/Components/esp_wifi/esp_wifi.c new file mode 100644 index 0000000000..2de8e7e675 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_wifi/esp_wifi.c @@ -0,0 +1,114 @@ +/** + * esp_wifi.c + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "include/esp_wifi.h" +#include +#include + +static wifi_event_handler_cb_t event_handler; + +void wifi_set_event_handler_cb(wifi_event_handler_cb_t cb) +{ + event_handler = cb; +} + +static void wifi_status_callback(struct netif* nif) +{ + if(event_handler == NULL || nif == NULL) { + return; + } + + static uint32_t prev_flags; + + uint32_t changed_flags = prev_flags ^ nif->flags; + prev_flags = nif->flags; + + if(changed_flags & NETIF_FLAG_UP) { + System_Event_t evt = {.event = + (nif->flags & NETIF_FLAG_UP) ? EVENT_STAMODE_CONNECTED : EVENT_STAMODE_DISCONNECTED}; + const char SSID[] = "Host WiFi"; + memcpy(evt.event_info.connected.ssid, SSID, sizeof(SSID)); + evt.event_info.connected.ssid_len = sizeof(SSID) - 1; + memcpy(evt.event_info.connected.bssid, nif->hwaddr, 6); + evt.event_info.connected.channel = 1; + event_handler(&evt); + } + + if(!ip4_addr_isany_val(nif->ip_addr)) { + System_Event_t evt = {.event = EVENT_STAMODE_GOT_IP, + .event_info = {.got_ip = { + .ip.addr = nif->ip_addr.addr, + .mask.addr = nif->netmask.addr, + .gw.addr = nif->gw.addr, + }}}; + event_handler(&evt); + } +} + +static void status_callback(struct netif* netif) +{ + host_queue_callback((host_task_callback_t)wifi_status_callback, (uint32_t)netif); +} + +// Called directly from startup code +void host_wifi_lwip_init_complete(void) +{ + struct netif* nif = netif_default; + + if(nif == NULL) { + return; + } + + netif_set_status_callback(nif, status_callback); + + netif_set_up(nif); +#if LWIP_IPV6 + netif_create_ip6_linklocal_address(&nif, 1); +#endif + + if(ip4_addr_isany_val(nif->ip_addr)) { + dhcp_start(nif); + } +} + +bool wifi_get_ip_info(uint8 if_index, struct ip_info* info) +{ + struct netif* nif = netif_default; + + if(if_index != STATION_IF || nif == NULL) { + return false; + } + + info->ip.addr = nif->ip_addr.addr; + info->gw.addr = nif->gw.addr; + info->netmask.addr = nif->netmask.addr; + return true; +} + +bool wifi_get_macaddr(uint8 if_index, uint8* macaddr) +{ + struct netif* nif = netif_default; + + if(if_index != STATION_IF || nif == NULL) { + return false; + } + + memcpy(macaddr, nif->hwaddr, 6); + return true; +} diff --git a/Sming/Arch/Host/Components/esp_wifi/include/esp_smartconfig.h b/Sming/Arch/Host/Components/esp_wifi/include/esp_smartconfig.h new file mode 100644 index 0000000000..a351cb4d27 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_wifi/include/esp_smartconfig.h @@ -0,0 +1,50 @@ +/* + * ESPRESSIF MIT License + * + * Copyright (c) 2016 + * + * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, + * it is free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished + * to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __SMARTCONFIG_H__ +#define __SMARTCONFIG_H__ + +typedef enum { + SC_STATUS_WAIT = 0, + SC_STATUS_FIND_CHANNEL, + SC_STATUS_GETTING_SSID_PSWD, + SC_STATUS_LINK, + SC_STATUS_LINK_OVER, +} sc_status; + +typedef enum { + SC_TYPE_ESPTOUCH = 0, + SC_TYPE_AIRKISS, + SC_TYPE_ESPTOUCH_AIRKISS, +} sc_type; + +//typedef void (*sc_callback_t)(sc_status status, void *pdata); +// +//const char *smartconfig_get_version(void); +//bool smartconfig_start(sc_callback_t cb, ...); +//bool smartconfig_stop(void); +//bool esptouch_set_timeout(uint8 time_s); //15s~255s, offset:45s +//bool smartconfig_set_type(sc_type type); + +#endif diff --git a/Sming/Arch/Host/Components/esp_wifi/include/esp_wifi.h b/Sming/Arch/Host/Components/esp_wifi/include/esp_wifi.h new file mode 100644 index 0000000000..4cc0c366fc --- /dev/null +++ b/Sming/Arch/Host/Components/esp_wifi/include/esp_wifi.h @@ -0,0 +1,145 @@ +#pragma once + +#include "esp_wifi_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//#define NULL_MODE 0x00 +//#define STATION_MODE 0x01 +//#define SOFTAP_MODE 0x02 +//#define STATIONAP_MODE 0x03 + +//uint8 wifi_get_opmode(void); +//uint8 wifi_get_opmode_default(void); +//bool wifi_set_opmode(uint8 opmode); +//bool wifi_set_opmode_current(uint8 opmode); +//uint8 wifi_get_broadcast_if(void); +//bool wifi_set_broadcast_if(uint8 interface); + +//bool wifi_station_get_config(struct station_config *config); +//bool wifi_station_get_config_default(struct station_config *config); +//bool wifi_station_set_config(struct station_config *config); +//bool wifi_station_set_config_current(struct station_config *config); + +//bool wifi_station_connect(void); +//bool wifi_station_disconnect(void); + +//void wifi_enable_signaling_measurement(void); +//void wifi_disable_signaling_measurement(void); + +//sint8 wifi_station_get_rssi(void); + +//uint8 wifi_station_get_connect_status(void); + +//uint8 wifi_station_get_current_ap_id(void); +//bool wifi_station_ap_change(uint8 current_ap_id); +//bool wifi_station_ap_number_set(uint8 ap_number); +//uint8 wifi_station_get_ap_info(struct station_config config[]); + +//bool wifi_station_dhcpc_start(void); +//bool wifi_station_dhcpc_stop(void); +//enum dhcp_status wifi_station_dhcpc_status(void); +//bool wifi_station_dhcpc_set_maxtry(uint8 num); + +//char* wifi_station_get_hostname(void); +//bool wifi_station_set_hostname(char *name); + +//int wifi_station_set_cert_key(uint8 *client_cert, int client_cert_len, +// uint8 *private_key, int private_key_len, +// uint8 *private_key_passwd, int private_key_passwd_len); +//void wifi_station_clear_cert_key(void); +//int wifi_station_set_username(uint8 *username, int len); +//void wifi_station_clear_username(void); + +//bool wifi_softap_get_config(struct softap_config *config); +//bool wifi_softap_get_config_default(struct softap_config *config); +//bool wifi_softap_set_config(struct softap_config *config); +//bool wifi_softap_set_config_current(struct softap_config *config); + +//uint8 wifi_softap_get_station_num(void); +//struct station_info * wifi_softap_get_station_info(void); +//void wifi_softap_free_station_info(void); + +//bool wifi_softap_dhcps_start(void); +//bool wifi_softap_dhcps_stop(void); + +//bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please); +//bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please); +//uint32 wifi_softap_get_dhcps_lease_time(void); +//bool wifi_softap_set_dhcps_lease_time(uint32 minute); +//bool wifi_softap_reset_dhcps_lease_time(void); + +//enum dhcp_status wifi_softap_dhcps_status(void); +//bool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg); + +bool wifi_get_ip_info(uint8 if_index, struct ip_info *info); +//bool wifi_set_ip_info(uint8 if_index, struct ip_info *info); +bool wifi_get_macaddr(uint8 if_index, uint8 *macaddr); +//bool wifi_set_macaddr(uint8 if_index, uint8 *macaddr); + +//uint8 wifi_get_channel(void); +//bool wifi_set_channel(uint8 channel); + +//void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func); +//void wifi_status_led_uninstall(); + +//void wifi_promiscuous_enable(uint8 promiscuous); + +//typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len); + +//void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); + +//void wifi_promiscuous_set_mac(const uint8_t *address); + +//enum phy_mode wifi_get_phy_mode(void); +//bool wifi_set_phy_mode(enum phy_mode mode); + +typedef void (* wifi_event_handler_cb_t)(System_Event_t *event); + +void wifi_set_event_handler_cb(wifi_event_handler_cb_t cb); + +//bool wifi_wps_enable(WPS_TYPE_t wps_type); +//bool wifi_wps_disable(void); +//bool wifi_wps_start(void); + +//typedef void (*wps_st_cb_t)(int status); +//bool wifi_set_wps_cb(wps_st_cb_t cb); + +//typedef void (*freedom_outside_cb_t)(uint8 status); +//int wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb); +//void wifi_unregister_send_pkt_freedom_cb(void); +//int wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq); + +//int wifi_rfid_locp_recv_open(void); +//void wifi_rfid_locp_recv_close(void); + +//typedef void (*rfid_locp_cb_t)(uint8 *frm, int len, int rssi); +//int wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb); +//void wifi_unregister_rfid_locp_recv_cb(void); + +//int wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate); +//int wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate); + +//int wifi_set_user_sup_rate(uint8 min, uint8 max); + +//bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min); +//uint8 wifi_get_user_limit_rate_mask(void); +//bool wifi_set_user_limit_rate_mask(uint8 enable_mask); + +//typedef void (*user_ie_manufacturer_recv_cb_t)(uint8 type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, int rssi); + +//bool wifi_set_user_ie(bool enable, uint8 *m_oui, uint8 type, uint8 *user_ie, uint8 len); +//int wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb); +//void wifi_unregister_user_ie_manufacturer_recv_cb(void); + +//bool wifi_set_country(wifi_country_t *country); +//bool wifi_get_country(wifi_country_t *country); + +void host_wifi_lwip_init_complete(void); + + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/esp_wifi/include/esp_wifi_types.h b/Sming/Arch/Host/Components/esp_wifi/include/esp_wifi_types.h new file mode 100644 index 0000000000..e0ecbab829 --- /dev/null +++ b/Sming/Arch/Host/Components/esp_wifi/include/esp_wifi_types.h @@ -0,0 +1,132 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define STATION_IF 0x00 +#define SOFTAP_IF 0x01 + +/* Platform/WifiEvents.h */ + +struct ip_info { + struct ip_addr ip; + struct ip_addr netmask; + struct ip_addr gw; +}; + +/* System events */ + +enum { + EVENT_STAMODE_CONNECTED = 0, + EVENT_STAMODE_DISCONNECTED, + EVENT_STAMODE_AUTHMODE_CHANGE, + EVENT_STAMODE_GOT_IP, + EVENT_STAMODE_DHCP_TIMEOUT, + EVENT_SOFTAPMODE_STACONNECTED, + EVENT_SOFTAPMODE_STADISCONNECTED, + EVENT_SOFTAPMODE_PROBEREQRECVED, + EVENT_OPMODE_CHANGED, + EVENT_SOFTAPMODE_DISTRIBUTE_STA_IP, + EVENT_MAX, +}; + +typedef struct { + uint8 ssid[32]; + uint8 ssid_len; + uint8 bssid[6]; + uint8 channel; +} Event_StaMode_Connected_t; + +typedef struct { + uint8 ssid[32]; + uint8 ssid_len; + uint8 bssid[6]; + uint8 reason; +} Event_StaMode_Disconnected_t; + +typedef struct { + uint8 old_mode; + uint8 new_mode; +} Event_StaMode_AuthMode_Change_t; + +typedef struct { + struct ip_addr ip; + struct ip_addr mask; + struct ip_addr gw; +} Event_StaMode_Got_IP_t; + +typedef struct { + uint8 mac[6]; + uint8 aid; +} Event_SoftAPMode_StaConnected_t; + +typedef struct { + uint8 mac[6]; + struct ip_addr ip; + uint8 aid; +} Event_SoftAPMode_Distribute_Sta_IP_t; + +typedef struct { + uint8 mac[6]; + uint8 aid; +} Event_SoftAPMode_StaDisconnected_t; + +typedef struct { + int rssi; + uint8 mac[6]; +} Event_SoftAPMode_ProbeReqRecved_t; + +typedef struct { + uint8 old_opmode; + uint8 new_opmode; +} Event_OpMode_Change_t; + +typedef union { + Event_StaMode_Connected_t connected; + Event_StaMode_Disconnected_t disconnected; + Event_StaMode_AuthMode_Change_t auth_change; + Event_StaMode_Got_IP_t got_ip; + Event_SoftAPMode_StaConnected_t sta_connected; + Event_SoftAPMode_Distribute_Sta_IP_t distribute_sta_ip; + Event_SoftAPMode_StaDisconnected_t sta_disconnected; + Event_SoftAPMode_ProbeReqRecved_t ap_probereqrecved; + Event_OpMode_Change_t opmode_changed; +} Event_Info_u; + +typedef struct _esp_event { + uint32 event; + Event_Info_u event_info; +} System_Event_t; + +/* Platform/Station.h */ + +enum STATUS { + OK, + FAIL, + PENDING, + BUSY, + CANCEL, +}; + +struct bss_info; + +enum AUTH_MODE { + AUTH_OPEN, + AUTH_WEP, + AUTH_WPA_PSK, + AUTH_WPA2_PSK, + AUTH_WPA_WPA2_PSK, + AUTH_MAX, +}; + +/* Platform/AccessPoint */ + +struct softap_config; + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/fatfs/ff.h b/Sming/Arch/Host/Components/fatfs/ff.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Arch/Host/Components/gdbstub/gdb_syscall.cpp b/Sming/Arch/Host/Components/gdbstub/gdb_syscall.cpp new file mode 100644 index 0000000000..984877cb59 --- /dev/null +++ b/Sming/Arch/Host/Components/gdbstub/gdb_syscall.cpp @@ -0,0 +1,6 @@ +#include + +int gdb_syscall(const GdbSyscallInfo& info) +{ + return -1; +} diff --git a/Sming/Arch/Host/Components/gdbstub/gdbcmds b/Sming/Arch/Host/Components/gdbstub/gdbcmds new file mode 100644 index 0000000000..362a5e18da --- /dev/null +++ b/Sming/Arch/Host/Components/gdbstub/gdbcmds @@ -0,0 +1,8 @@ +# Enable this if you want to log all traffic between GDB and the stub +#set remotelogfile gdb_rsp_logfile.txt + +# Useful for lower-level debugging to see the result of stepping through assembler code +#set disassemble-next-line on + +# Display a welcome prompt +echo \nWelcome to SMING!\nType 'r' to run application\n\n diff --git a/Sming/Arch/Host/Components/gdbstub/gdbstub.c b/Sming/Arch/Host/Components/gdbstub/gdbstub.c new file mode 100644 index 0000000000..c36ff2643a --- /dev/null +++ b/Sming/Arch/Host/Components/gdbstub/gdbstub.c @@ -0,0 +1,29 @@ +#include + +void gdb_enable(bool state) +{ +} + +GdbState gdb_present(void) +{ + return eGDB_NotPresent; +} + +void __attribute__((weak)) gdb_on_attach(bool attached) +{ +} + +void gdb_detach(void) +{ +} + + + +unsigned __gdb_no_op(void) +{ + return 0; +} + +//#define NOOP __attribute__((weak, alias("__gdb_no_op"))) +// +//void gdb_on_attach(bool attached) NOOP; diff --git a/Sming/Arch/Host/Components/heap/heap.c b/Sming/Arch/Host/Components/heap/heap.c new file mode 100644 index 0000000000..f6e5c7a0c0 --- /dev/null +++ b/Sming/Arch/Host/Components/heap/heap.c @@ -0,0 +1,7 @@ + +#include "include/heap.h" + +uint32_t system_get_free_heap_size(void) +{ + return (uint32_t)-1; +} diff --git a/Sming/Arch/Host/Components/heap/include/heap.h b/Sming/Arch/Host/Components/heap/include/heap.h new file mode 100644 index 0000000000..a18851dab9 --- /dev/null +++ b/Sming/Arch/Host/Components/heap/include/heap.h @@ -0,0 +1,15 @@ +#pragma once +#include "c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t system_get_free_heap_size(void); + +#define os_malloc(s) malloc(s) +#define os_free(p) free(p) + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/hostlib/except.c b/Sming/Arch/Host/Components/hostlib/except.c new file mode 100644 index 0000000000..fd9f134862 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/except.c @@ -0,0 +1,66 @@ +/** + * except.c + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "except.h" +#include +#include +#include "hostapi.h" + +static void signal_handler(int sig) +{ + host_puts("\r\n"); + switch(sig) { + case SIGABRT: + hostmsg("SIGABRT - usually caused by an abort() or assert()"); + break; + case SIGFPE: + hostmsg("SIGFPE - arithmetic exception such as divide by zero"); + break; + case SIGILL: + hostmsg("SIGILL - illegal instruction"); + break; + case SIGINT: + hostmsg("SIGINT - Ctrl+C pressed"); + host_exit(0); + return; + case SIGSEGV: + hostmsg("SIGSEGV - segmentation fault"); + break; + case SIGTERM: + hostmsg("SIGTERM - a termination request was sent to the program"); + host_exit(1); + return; + default: + hostmsg("Signal #%i", sig); + break; + } + + host_puts("\r\n"); + _Exit(1); +} + +void trap_exceptions() +{ + signal(SIGABRT, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGTERM, signal_handler); +} diff --git a/Sming/Arch/Host/Components/hostlib/except.h b/Sming/Arch/Host/Components/hostlib/except.h new file mode 100644 index 0000000000..4ebb5a6fa4 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/except.h @@ -0,0 +1,30 @@ +/** + * except.h - Exception handling + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void trap_exceptions(); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/hostlib/flashmem.cpp b/Sming/Arch/Host/Components/hostlib/flashmem.cpp new file mode 100644 index 0000000000..5f58b4880b --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/flashmem.cpp @@ -0,0 +1,156 @@ +/** + * flashmem.c + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "flashmem.h" +#include +#include + +static int flashFile = -1; +static size_t flashFileSize = 0x400000U; +static const char* flashFileName = "flash.bin"; + +#define SPI_FLASH_SEC_SIZE 4096 + +#define CHECK_ALIGNMENT(_x) assert(((uint32_t)(_x)&0x00000003) == 0) +#define CHECK_RANGE(_addr, _size) assert((_addr) + (_size) <= flashFileSize); + +bool host_flashmem_init(const FlashmemConfig& config) +{ + if(config.filename != NULL) { + flashFileName = config.filename; + } + flashFile = open(flashFileName, O_CREAT | O_RDWR | O_BINARY, 0644); + if(flashFile < 0) { + hostmsg("Error opening \"%s\"", flashFileName); + return false; + } + + int res = lseek(flashFile, 0, SEEK_END); + if(res < 0) { + hostmsg("Error seeking \"%s\"", flashFileName); + close(flashFile); + return false; + } + + if(res == 0) { + size_t size = config.createSize ?: flashFileSize; + res = lseek(flashFile, size, SEEK_SET); + if(res != int(size)) { + hostmsg("Error seeking beyond end of file \"%s\"", flashFileName); + } else if(ftruncate(flashFile, size) < 0) { + hostmsg("Error truncating \"%s\" to %u bytes", flashFileName, size); + } else { + hostmsg("Created blank \"%s\", %u bytes", flashFileName, size); + } + } else { + hostmsg("Opened \"%s\", size = 0x%08x", flashFileName, res); + } + + flashFileSize = res; + + return true; +} + +void host_flashmem_cleanup() +{ + close(flashFile); + flashFile = -1; + hostmsg("Closed \"%s\"", flashFileName); +} + +static int readFlashFile(uint32_t offset, void* buffer, size_t count) +{ + if(flashFile < 0) { + return -1; + } + int res = lseek(flashFile, offset, SEEK_SET); + return (res < 0) ? res : read(flashFile, buffer, count); +} + +static int writeFlashFile(uint32_t offset, const void* data, size_t count) +{ + if(flashFile < 0) { + return -1; + } + int res = lseek(flashFile, offset, SEEK_SET); + return (res < 0) ? res : write(flashFile, data, count); +} + +//SPIFlashInfo flashmem_get_info() +//{ +//} + +//uint8_t flashmem_get_size_type() +//{ +//} + +uint32_t flashmem_get_size_bytes() +{ + return flashFileSize; +} + +uint16_t flashmem_get_size_sectors() +{ + return flashFileSize / SPI_FLASH_SEC_SIZE; +} + +uint32_t flashmem_write_internal(const void* from, uint32_t toaddr, uint32_t size) +{ + CHECK_ALIGNMENT(from); + CHECK_ALIGNMENT(toaddr); + CHECK_ALIGNMENT(size); + return flashmem_write(from, toaddr, size); +} + +uint32_t flashmem_read_internal(void* to, uint32_t fromaddr, uint32_t size) +{ + CHECK_ALIGNMENT(to); + CHECK_ALIGNMENT(fromaddr); + CHECK_ALIGNMENT(size); + int res = readFlashFile(fromaddr, to, size); + return (res < 0) ? 0 : res; +} + +uint32_t flashmem_write(const void* from, uint32_t toaddr, uint32_t size) +{ + CHECK_RANGE(toaddr, size); + int res = writeFlashFile(toaddr, from, size); + return (res < 0) ? 0 : res; +} + +uint32_t flashmem_read(void* to, uint32_t fromaddr, uint32_t size) +{ + CHECK_RANGE(fromaddr, size); + int res = readFlashFile(fromaddr, to, size); + return (res < 0) ? 0 : res; +} + +uint32_t flashmem_get_sector_of_address(uint32_t addr) +{ + return addr / INTERNAL_FLASH_SECTOR_SIZE; +} + +bool flashmem_erase_sector(uint32_t sector_id) +{ + uint32_t addr = sector_id * INTERNAL_FLASH_SECTOR_SIZE; + CHECK_RANGE(addr, INTERNAL_FLASH_SECTOR_SIZE); + uint8_t tmp[INTERNAL_FLASH_SECTOR_SIZE]; + memset(tmp, 0xFF, sizeof(tmp)); + return writeFlashFile(addr, tmp, sizeof(tmp)) == sizeof(tmp); +} diff --git a/Sming/Arch/Host/Components/hostlib/flashmem.h b/Sming/Arch/Host/Components/hostlib/flashmem.h new file mode 100644 index 0000000000..9435983f70 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/flashmem.h @@ -0,0 +1,39 @@ +/** + * flashmem.h - Flash memory emulation using backing file + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#include "hostlib.h" + +struct FlashmemConfig { + const char* filename; ///< Path to flash backing file + size_t createSize; ///< If file doesn't exist, created with this size +}; + +/** + * @brief Open/create flash backing file + * @param filename Path to flash backing file + * @param createSize If file doesn't exist, created with this size + * @retval bool true if backing file was opened successfully + * @note Specify nullptr, 0 to use default values + * All flash operations will be restricted to size of initial backing file + */ +bool host_flashmem_init(const FlashmemConfig& config); + +void host_flashmem_cleanup(); diff --git a/Sming/Arch/Host/Components/hostlib/hostapi.h b/Sming/Arch/Host/Components/hostlib/hostapi.h new file mode 100644 index 0000000000..207896051e --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/hostapi.h @@ -0,0 +1,35 @@ +/** + * hostapi.h - Host functions for use by applications + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#include "hostmsg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Instruct the host to finish and return the given code to the OS + */ +void host_exit(int code); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/hostlib/hostlib.c b/Sming/Arch/Host/Components/hostlib/hostlib.c new file mode 100644 index 0000000000..cb435676b3 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/hostlib.c @@ -0,0 +1,47 @@ +/** + * hostlib.c + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "hostlib.h" +#include +#include + +int msleep(unsigned ms) +{ + struct timespec req, rem; + req.tv_sec = ms / 1000; + req.tv_nsec = (ms % 1000) * 1000000; + return nanosleep(&req, &rem); +} + +void getHostAppDir(char* path, size_t bufSize) +{ + size_t len __attribute__((unused)); + char sep; +#ifdef __WIN32 + len = GetModuleFileName(NULL, path, bufSize); + sep = '\\'; +#else + len = readlink("/proc/self/exe", path, bufSize); + sep = '/'; +#endif + char* p = strrchr(path, sep); + if(p) { + p[1] = '\0'; + } +} diff --git a/Sming/Arch/Host/Components/hostlib/hostlib.h b/Sming/Arch/Host/Components/hostlib/hostlib.h new file mode 100644 index 0000000000..8281ddf840 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/hostlib.h @@ -0,0 +1,64 @@ +/** + * hostlib.h + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +// Required for sleep(), ftruncate(), probably others +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L + +#ifdef __WIN32 +// Prevent early inclusion of winsock.h +#include +#undef EVENT_MAX // Conflicts with definitions in esp_wifi_types.h +#endif + +#include +#include +#include +#include +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof((x)[0])) +#endif + +// Used for parameterised token pasting +#ifndef JOIN +#define JOIN_AGAIN(_a, _b) _a##_b +#define JOIN(_a, _b) JOIN_AGAIN(_a, _b) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int msleep(unsigned ms); + +// Include trailing path separator +void getHostAppDir(char* path, size_t bufSize); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/hostlib/hostmsg.c b/Sming/Arch/Host/Components/hostlib/hostmsg.c new file mode 100644 index 0000000000..a613b5d3ab --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/hostmsg.c @@ -0,0 +1,72 @@ +/** + * hostmsg.c + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include +#include +#include +#include "hostmsg.h" + +/* + * e.g. from "void a::sub(int)" we just want "a::sub" + */ +static const char* get_method_name(const char* pretty_function, size_t* length) +{ + const char* pbrace = strchr(pretty_function, '('); + if(pbrace == NULL) { + *length = strlen(pretty_function); + return pretty_function; + } + const char* pcls = pbrace; + while(pcls >= pretty_function && *pcls != ' ') { + --pcls; + } + ++pcls; + *length = pbrace - pcls; + return pcls; +} + +void host_printf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +void host_printfp(const char* fmt, const char* pretty_function, ...) +{ + size_t len; + const char* name = get_method_name(pretty_function, &len); + + va_list args; + va_start(args, pretty_function); + char buffer[1024]; + memcpy(buffer, name, len); + buffer[len++] = ':'; + buffer[len++] = ' '; + vsnprintf(&buffer[len], sizeof(buffer) - len, fmt, args); + va_end(args); + + host_puts(buffer); +} + +void host_puts(const char* str) +{ + fputs(str, stderr); +} diff --git a/Sming/Arch/Host/Components/hostlib/hostmsg.h b/Sming/Arch/Host/Components/hostlib/hostmsg.h new file mode 100644 index 0000000000..43b9977443 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/hostmsg.h @@ -0,0 +1,38 @@ +/** + * hostmsg.h - Print support for host output + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void host_printf(const char* fmt, ...); +void host_printfp(const char* fmt, const char* pretty_function, ...); +void host_puts(const char* str); + +#ifdef __cplusplus +#define hostmsg(fmt, ...) host_printfp(fmt "\n", __PRETTY_FUNCTION__, ##__VA_ARGS__) +#else +#define hostmsg(fmt, ...) host_printfp(fmt "\n", __func__, ##__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/hostlib/options.cpp b/Sming/Arch/Host/Components/hostlib/options.cpp new file mode 100644 index 0000000000..1bdaae87a7 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/options.cpp @@ -0,0 +1,92 @@ +/** + * options.cpp + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "options.h" +#include "hostmsg.h" +#include +#include +#include + +struct option_help_t { + const char* brief; + const char* argname; + const char* arghelp; + const char* description; +}; + +static const option long_options[] = { +#define XX(tag, has_arg, desc, argname, arghelp, examples) {#tag, has_arg}, + OPTION_MAP(XX) +#undef XX + {nullptr}, +}; + +static const option_help_t option_help[] = { +#define XX(tag, has_arg, desc, argname, arghelp, examples) {desc, argname, arghelp, examples}, + OPTION_MAP(XX) +#undef XX +}; + +void print_help() +{ + const unsigned COL = 23; + auto help = option_help; + auto opt = long_options; + for(; opt->name; ++opt, ++help) { + char s[256]; + strcpy(s, opt->name); + if(help->argname) { + if(opt->has_arg == optional_argument) { + strcat(s, "["); + } + strcat(s, "="); + strcat(s, help->argname); + if(opt->has_arg == optional_argument) { + strcat(s, "]"); + } + } + host_printf("%*s%s\n", -COL, s, help->brief); + if(help->argname) { + host_printf("%*s%s - %s\n", COL + 2, "", help->argname, help->arghelp); + } + auto ex = help->description; + if(ex) { + while(*ex) { + host_printf("%*s%s\n", COL + 2, "", ex); + ex += strlen(ex) + 1; + } + } + } +} + +option_tag_t get_option(int argc, char* argv[], const char*& arg) +{ + int option_index = 0; + int c = getopt_long_only(argc, argv, "", long_options, &option_index); + if(c == '?') { + host_printf("Invalid command line. Try --help\n"); + exit(1); + } + if(c != 0) { + return opt_none; + } + + arg = optarg; + return option_tag_t(option_index); +} diff --git a/Sming/Arch/Host/Components/hostlib/options.h b/Sming/Arch/Host/Components/hostlib/options.h new file mode 100644 index 0000000000..cc5598db49 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/options.h @@ -0,0 +1,60 @@ +/** + * options.h - command-line option parsing + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +/* + * tag option tag + * has_arg no_argument, optional_argument, required_argument + * brief Brief description of option + * argname Name of argument, if any + * argdesc Description of argument + * longdesc Long description, lines are null-terminated + */ +#define OPTION_MAP(XX) \ + XX(help, no_argument, "Show help", nullptr, nullptr, nullptr) \ + XX(uart, required_argument, "Enable UART server", "PORT", "Which UART number to enable", \ + "e.g. --uart=0 --uart=1 enable servers for UART0, UART1\0") \ + XX(portbase, required_argument, "Specify base port number for UART socket servers", "PORT", "IP port number", \ + nullptr) \ + XX(ifname, required_argument, "Specify network interface", "NAME", "Network interface to use (e.g. tap0)", \ + nullptr) \ + XX(ipaddr, required_argument, "Specify network IP address", "ADDR", "IP4 network address (e.g. 192.168.13.2)", \ + nullptr) \ + XX(gateway, required_argument, "Specify network gateway address", "ADDR", \ + "IP4 network address (e.g. 192.168.1.254)", nullptr) \ + XX(netmask, required_argument, "Specify IP network mask", "MASK", "e.g. 255.255.255.0", nullptr) \ + XX(pause, optional_argument, "Pause at startup", "SECS", "How long to pause for, omit to wait for ENTER", nullptr) \ + XX(exitpause, optional_argument, "Pause at exit", "SECS", "How long to pause for, omit to wait for ENTER", \ + nullptr) \ + XX(flashfile, required_argument, "Use alternative flash backing file", "FILENAME", "Path to flash backing file", \ + nullptr) \ + XX(flashsize, required_argument, "Change default flash size if file doesn't exist", "SIZE", \ + "Size of flash in bytes (e.g. 512K, 524288, 0x80000)", nullptr) \ + XX(initonly, no_argument, "Initialise only, do not start Sming", nullptr, nullptr, nullptr) + +enum option_tag_t { +#define XX(tag, has_arg, desc, argname, arghelp, examples) opt_##tag, + OPTION_MAP(XX) +#undef XX + opt_none = -1 +}; + +option_tag_t get_option(int argc, char* argv[], const char*& arg); +void print_help(); diff --git a/Sming/Arch/Host/Components/hostlib/sockets.cpp b/Sming/Arch/Host/Components/hostlib/sockets.cpp new file mode 100644 index 0000000000..d69d1613db --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/sockets.cpp @@ -0,0 +1,455 @@ +/** + * sockets.cpp + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "sockets.h" +#include "hostmsg.h" +#include + +#ifndef __WIN32 +// For FIONREAD +#include +#include +#endif + +void sockets_initialise() +{ +#ifdef __WIN32 + WORD versionWanted = MAKEWORD(1, 1); + WSADATA wsaData; + WSAStartup(versionWanted, &wsaData); +#endif +} + +void sockets_finalise() +{ +#ifdef __WIN32 + WSACleanup(); +#endif +} + +static void socket_close(int fd) +{ + if(fd <= 0) { + return; + } + + ::shutdown(fd, SHUT_RDWR); +#ifdef __WIN32 + ::closesocket(fd); +#else + ::close(fd); +#endif +} + +static bool socket_blocking(int fd, bool block) +{ +#ifdef __WIN32 + u_long iMode = block ? 0 : 1; + return ioctlsocket(fd, FIONBIO, &iMode) == 0; +#else + int fl = fcntl(fd, F_GETFL); + int fl_new = block ? (fl & ~O_NONBLOCK) : (fl | O_NONBLOCK); + if(fl_new == fl) + return true; + return fcntl(fd, F_SETFL, fl_new) == 0; +#endif +} + +/* + * CSockAddr + */ + +std::string CSockAddr::text() const +{ + if(m_addr.sin_family != AF_INET) { + return "(not ip4: " + std::to_string(m_addr.sin_family) + ")"; + } + + char* addr = inet_ntoa(m_addr.in4.sin_addr); + if(addr == nullptr) { + return ""; + } + + return std::string(addr) + ':' + std::to_string(ntohs(m_addr.in4.sin_port)); +} + +bool CSockAddr::assign(const char* addr, unsigned port) +{ + if(port > 0xFFFF) { + return false; + } + m_addr.in4.sin_port = htons(port); + m_addr.in4.sin_family = AF_INET; + uint32_t ina = (addr == nullptr || *addr == '\0') ? 0 : inet_addr(addr); + m_addr.in4.sin_addr.s_addr = ina; + return ina != INADDR_NONE; +} + +bool CSockAddr::get_host(int fd) +{ + clear(); + socklen_t len = sizeof(m_addr.sa); + return (getsockname(fd, &m_addr.sa, &len) == 0); +} + +bool CSockAddr::get_peer(int fd) +{ + clear(); + socklen_t len = sizeof(m_addr.sa); + return (getpeername(fd, &m_addr.sa, &len) == 0); +} + +/* + * CSocket + */ + +std::string socket_strerror() +{ + char buf[256]; + buf[0] = '\0'; + int ErrorCode; +#ifdef __WIN32 + ErrorCode = WSAGetLastError(); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY, nullptr, + ErrorCode, 0, buf, sizeof(buf), nullptr); +#else + ErrorCode = errno; + auto res = strerror_r(ErrorCode, buf, sizeof(buf)); +#endif + return buf[0] ? buf : std::string("Error #" + std::to_string(ErrorCode)); +} + +bool CSocket::create() +{ + if(m_fd > 0) { + return true; + } + + // creation of the socket + m_fd = ::socket(AF_INET, m_type, 0); + if(m_fd <= 0) { + hostmsg("%s", socket_strerror().c_str()); + return false; + } + + int reuse = 1; + if(setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (sock_ptr_t)&reuse, sizeof(reuse)) < 0) { + hostmsg("REUSEADDR: %s", socket_strerror().c_str()); + close(); + return false; + } + +#ifdef SO_REUSEPORT + if(setsockopt(m_fd, SOL_SOCKET, SO_REUSEPORT, (sock_ptr_t)&reuse, sizeof(reuse)) < 0) { + hostmsg("REUSEPORT: %s", socket_strerror().c_str()); + close(); + return false; + } +#endif + + return true; +} + +bool CSocket::setblocking(bool block) +{ + return socket_blocking(m_fd, block); +} + +bool CSocket::bind(const CSockAddr& sa) +{ + if(!create()) { + return false; + } + + m_addr = sa; + return ::bind(m_fd, &sa.addr(), sizeof(struct sockaddr)) == 0; +} + +bool CSocket::connect(const CSockAddr& sa) +{ + bool res = create(); + + if(!res) { + return false; + } + + m_addr = sa; + if(::connect(m_fd, &sa.addr(), sizeof(struct sockaddr))) { + //!! TODO: Implement event notifications for everything (connect, close, data ready, etc.) +#ifdef __WIN32 + if(WSAGetLastError() != WSAEWOULDBLOCK) +#else + if(errno != EAGAIN) +#endif + res = false; + } + + return res; +} + +void CSocket::close() +{ + if(m_fd <= 0) { + return; + } + + hostmsg("%s", addr().text().c_str()); + + socket_close(m_fd); + m_fd = 0; +} + +// Returns available data to receive +int CSocket::available() +{ + u_long av = 0; +#ifdef __WIN32 + int res = ioctlsocket(m_fd, FIONREAD, &av); +#else + int res = ioctl(m_fd, FIONREAD, &av); +#endif + return (res == 0) ? int(av) : -1; +} + +/* + * If we rebuffer then the receiver has to deal with fragmented data packets. + * For command use data is small so that will never happen, but with video it's likely. + */ +int CSocket::send(const void* data, size_t n, int flags) +{ + int sent = 0; + while(n != 0) { + int ret = ::send(m_fd, static_cast(data) + sent, n, flags); + if(ret < 0) { + return ret; + } + sent += ret; + if(size_t(ret) > n) { + break; + } + n -= ret; + } + return sent; +} + +bool CSocket::wait(unsigned timeout_ms, unsigned flags) +{ +#ifdef __WIN32 + fd_set set; + FD_ZERO(&set); + FD_SET(m_fd, &set); + + struct timeval tv; + tv.tv_sec = long(timeout_ms) / 1000; + tv.tv_usec = (timeout_ms - tv.tv_sec * 1000) * 1000; + + auto rdSet = (flags & SOCKET_WAIT_READ) ? &set : nullptr; + auto wrSet = (flags & SOCKET_WAIT_WRITE) ? &set : nullptr; + return select(m_fd + 1, rdSet, wrSet, nullptr, &tv) == 1; + +#else + short events = 0; + if(flags & SOCKET_WAIT_READ) { + events |= POLLIN; + } + if(flags & SOCKET_WAIT_WRITE) { + events |= POLLOUT; + } + struct pollfd pfd = {m_fd, events, 0}; + return poll(&pfd, 1, timeout_ms) == 1; +#endif +} + +int CSocket::recv(void* buf, size_t n, int flags) +{ +#ifdef __WIN32 + // Emulate MSG_NOWAIT behaviour + if(flags & MSG_DONTWAIT) { + int av = available(); + if(av < 0) { + return av; + } + if(av == 0) { + WSASetLastError(WSAEWOULDBLOCK); + return -1; + } + if(size_t(av) < n) { + n = size_t(av); + } + flags &= ~MSG_DONTWAIT; + } +#endif + + return ::recv(m_fd, (char*)buf, n, flags); +} + +/* + * CSocketList + */ + +CSocketList::~CSocketList() +{ + for(auto& s : *this) { + delete s; + s = nullptr; + } +} + +void CSocketList::add(CSocket* skt) +{ + lock(); + for(auto& s : *this) { + if(!s->active()) { + delete s; + s = skt; + skt = nullptr; + break; + } + } + + if(skt != nullptr) { + push_back(skt); + } + unlock(); +} + +void CSocketList::send(const void* data, size_t n, int flags) +{ + lock(); + for(auto& skt : *this) { + if(!skt->active()) { + continue; + } + + int num_sent = skt->send(data, n, flags); + if(num_sent != (int)n) { +#ifndef __WIN32 + if(errno != EPIPE) + perror(__FUNCTION__); +#endif + skt->close(); + } + } + unlock(); +} + +CSocket* CSocketList::recv(void* buf, size_t& n) +{ + lock(); + for(auto& skt : *this) { + if(!skt->active()) { + continue; + } + + int num_recv = skt->recv(buf, n, MSG_DONTWAIT); + if(num_recv > 0) { + n = num_recv; + unlock(); + return skt; + } + + if(num_recv < 0) +#ifdef __WIN32 + if(WSAGetLastError() != WSAEWOULDBLOCK) { +#else + if(errno != EAGAIN) { +#endif + if(errno != EPIPE) { + // Broken pipe + hostmsg("%s", socket_strerror().c_str()); + } + skt->close(); + } + } + unlock(); + return nullptr; +} + +unsigned CSocketList::active() +{ + lock(); + unsigned n = 0; + for(auto& skt : *this) { + if(skt->active()) + ++n; + } + unlock(); + return n; +} + +void CSocketList::closeall() +{ + for(auto& s : *this) { + s->close(); + } +} + +/* + * CServerSocket + */ + +bool CServerSocket::listen(const CSockAddr& addr, unsigned max_connections) +{ + if(!create()) { + return false; + } + + if(!bind(addr)) { + return false; + } + + if(::listen(m_fd, 3)) { + return false; + } + + m_max_connections = max_connections; + + return setblocking(false); +} + +CSocket* CServerSocket::try_connect() +{ + // Initialised? + if(m_fd <= 0) { + return nullptr; + } + + // Ignore further attempts until we're ready + if(m_clients.active() >= m_max_connections) { + return nullptr; + } + + struct sockaddr sa; + socklen_t len = sizeof(sa); + int fd = ::accept(m_fd, &sa, &len); + if(fd <= 0) { + return nullptr; + } + + if(socket_blocking(fd, false)) { + CSocket* skt = new_connection(fd, CSockAddr(sa)); + if(skt) { + m_clients.add(skt); + return skt; + } + } + + socket_close(fd); + return nullptr; +} diff --git a/Sming/Arch/Host/Components/hostlib/sockets.h b/Sming/Arch/Host/Components/hostlib/sockets.h new file mode 100644 index 0000000000..00f2291838 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/sockets.h @@ -0,0 +1,239 @@ +/** + * sockets.h - C++ socket support for Windows / Linux + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#include "hostlib.h" +#include "threads.h" +#include +#include + +#ifdef __WIN32 +#include + +#define MSG_NOSIGNAL 0 +#define MSG_DONTWAIT 0x40 +#define SHUT_RDWR SD_BOTH +typedef char* sock_ptr_t; +typedef int socklen_t; + +#else + +#include +typedef void* sock_ptr_t; + +#endif + +// CSocket::wait flags +#define SOCKET_WAIT_READ 0x01 +#define SOCKET_WAIT_WRITE 0x02 + +// Call exactly once for the application +void sockets_initialise(); +void sockets_finalise(); +std::string socket_strerror(); + +class CSockAddr +{ +private: + union { + short sin_family; + struct sockaddr sa; + struct sockaddr_in in4; // AF_INET + struct sockaddr_in6 in6; // AF_INET6 + } m_addr; + +public: + CSockAddr() + { + clear(); + } + + CSockAddr(const char* addr, unsigned port) + { + assign(addr, port); + } + + CSockAddr(const struct sockaddr& addr) + { + m_addr.sa = addr; + } + + CSockAddr(const struct sockaddr_in& addr) + { + m_addr.in4 = addr; + } + + bool assign(const char* addr, unsigned port); + + bool get_host(int fd); + bool get_peer(int fd); + + void clear() + { + m_addr = {}; + } + + std::string text() const; + + const struct sockaddr& addr() const + { + return m_addr.sa; + } +}; + +class CSocketList; + +class CSocket +{ +public: + CSocket(int type = SOCK_STREAM, int protocol = 0) : m_type(type), m_protocol(protocol), m_fd(0) + { + } + + CSocket(int fd, const CSockAddr& addr) : CSocket() + { + assign(fd, addr); + } + + virtual ~CSocket() + { + close(); + } + + virtual void close(); + + bool setblocking(bool block); + bool bind(const CSockAddr& sa); + bool connect(const CSockAddr& sa); + bool active() const + { + return m_fd > 0; + } + + void assign(int fd, const CSockAddr& addr) + { + if(fd != m_fd) { + close(); + m_fd = fd; + } + m_addr = addr; + } + + CSockAddr get_host() const + { + CSockAddr addr; + addr.get_host(m_fd); + return addr; + } + + CSockAddr get_peer() const + { + CSockAddr addr; + addr.get_peer(m_fd); + return addr; + } + + const CSockAddr& addr() const + { + return m_addr; + } + + int send(const void* data, size_t n, int flags = MSG_NOSIGNAL); + + int available(); + bool wait(unsigned timeout_ms, unsigned flags = SOCKET_WAIT_READ); + int recv(void* buf, size_t n, int flags = 0); + + // If we take a copy of this socket this ensures it doesn't get closed + void release() + { + m_fd = 0; + } + +protected: + bool create(); + +protected: + // Type of socket: SOCK_STREAM, SOCK_DGRAM, etc. + int m_type; + // Typically 0, or some other value if type is SOCK_RAW + int m_protocol; + // + int m_fd; + CSockAddr m_addr; +}; + +class CSocketList : public std::vector +{ +public: + ~CSocketList(); + + void lock() + { + m_mutex.lock(); + } + + void unlock() + { + m_mutex.unlock(); + } + + void add(CSocket* skt); + + void send(const void* data, size_t n, int flags = MSG_NOSIGNAL); + + CSocket* recv(void* buf, size_t& n); + + unsigned active(); + + void closeall(); + +private: + CMutex m_mutex; +}; + +class CServerSocket : public CSocket +{ +public: + CServerSocket(int type = SOCK_STREAM) : CSocket(type), m_max_connections(1) + { + } + + void close() override + { + m_clients.closeall(); + CSocket::close(); + } + + bool listen(const CSockAddr& addr, unsigned max_connections); + + CSocket* try_connect(); + +protected: + // Inherited classes override this - return false to reject connection + virtual CSocket* new_connection(int& fd, const CSockAddr& addr) + { + return new CSocket(fd, addr); + } + +private: + unsigned m_max_connections; + CSocketList m_clients; +}; diff --git a/Sming/Arch/Host/Components/hostlib/startup.cpp b/Sming/Arch/Host/Components/hostlib/startup.cpp new file mode 100644 index 0000000000..3cbfaab227 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/startup.cpp @@ -0,0 +1,232 @@ +/** + * startup.cpp - Sming Host Emulator startup code + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +// Prevent inclusion of networking, conflicts with sockets +#define __USER_CONFIG_H__ + +#include "sockets.h" +#include "except.h" +#include "options.h" +#include "flashmem.h" +#include "uart_server.h" +#include +#include +#include +#include "host_lwip.h" +#include +#include + +#include + +static int exitCode = 0; +static bool done = false; + +extern void init(); + +static void cleanup() +{ + host_flashmem_cleanup(); + CUartServer::shutdown(); + sockets_finalise(); + host_lwip_shutdown(); + hostmsg("Goodbye!"); +} + +void host_exit(int code) +{ + static unsigned exit_count; + + hostmsg("returning %d", code); + exitCode = code; + done = true; + + if(exit_count++) { + hostmsg("Forcing exit"); + exit(exitCode); + } +} + +/* + * Size may be specified as decimal, hex or with 'K' or 'M' suffix + */ +static size_t parse_flash_size(const char* str) +{ + if(str == nullptr) { + return 0; + } + char* tail; + long res = strtol(str, &tail, 0); + if(res < 0) { + return 0; + } + switch(*tail) { + case 'k': + case 'K': + return size_t(res) * 1024U; + case 'm': + case 'M': + return size_t(res) * 1024U * 1024U; + default: + return size_t(res); + } +} + +static void pause(int secs) +{ + if(secs == 0) { + hostmsg("Hit ENTER to continue."); + getchar(); + } else if(secs > 0) { + hostmsg("Waiting for %u seconds...", secs); + msleep(secs * 1000); + } +} + +int main(int argc, char* argv[]) +{ + trap_exceptions(); + + host_printf("\nWelcome to the Sming Host emulator\n\n"); + + static struct { + int pause; + int exitpause; + bool initonly; + UartServerConfig uart; + FlashmemConfig flash; + struct lwip_param lwip; + } config = { + .pause = -1, + .exitpause = -1, + .initonly = false, + .uart = + { + .enableMask = 0, + .portBase = 0, + }, + .flash = + { + .filename = nullptr, + .createSize = 0, + + }, + .lwip = + { + .ifname = nullptr, + .ipaddr = nullptr, + }, + }; + + option_tag_t opt; + const char* arg; + while((opt = get_option(argc, argv, arg)) != opt_none) { + switch(opt) { + case opt_help: + print_help(); + return 0; + + case opt_uart: + bitSet(config.uart.enableMask, atoi(arg)); + break; + + case opt_portbase: + config.uart.portBase = atoi(arg); + break; + + case opt_ifname: + config.lwip.ifname = arg; + break; + + case opt_ipaddr: + config.lwip.ipaddr = arg; + break; + + case opt_gateway: + config.lwip.gateway = arg; + break; + + case opt_netmask: + config.lwip.netmask = arg; + break; + + case opt_pause: + config.pause = arg ? atoi(arg) : 0; + break; + + case opt_exitpause: + config.exitpause = arg ? atoi(arg) : 0; + break; + + case opt_flashfile: + config.flash.filename = arg; + break; + + case opt_flashsize: + config.flash.createSize = parse_flash_size(arg); + break; + + case opt_initonly: + config.initonly = true; + break; + + default:; + } + } + + if(!host_flashmem_init(config.flash)) { + return 1; + } + + atexit(cleanup); + + if(config.initonly) { + hostmsg("Initialise-only requested"); + } else { + host_init_tasks(); + + sockets_initialise(); + CUartServer::startup(config.uart); + + if(host_lwip_init(&config.lwip)) { + host_wifi_lwip_init_complete(); + } + + hostmsg("If required, you may start terminal application(s) now"); + pause(config.pause); + + hostmsg(">> Starting Sming <<\n"); + + System.initialize(); + + init(); + + while(!done) { + host_service_tasks(); + host_service_timers(); + host_lwip_service(); + system_soft_wdt_feed(); + } + + hostmsg(">> Normal Exit <<\n"); + } + + pause(config.exitpause); + + return exitCode; +} diff --git a/Sming/Arch/Host/Components/hostlib/threads.h b/Sming/Arch/Host/Components/hostlib/threads.h new file mode 100644 index 0000000000..011cd09e40 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/threads.h @@ -0,0 +1,133 @@ +/** + * threads.h - C++ support for threads and related sychronisation primitives using pthread library + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#include "hostlib.h" +#include +#include + +class CThread +{ +public: + virtual ~CThread() + { + join(); + } + + bool execute() + { + return pthread_create(&m_thread, NULL, thread_start, this) == 0; + } + + bool detach() + { + return pthread_detach(m_thread) == 0; + } + + bool cancel() + { + return pthread_cancel(m_thread) == 0; + } + + void join() + { + pthread_join(m_thread, nullptr); + } + +protected: + virtual void* thread_routine() = 0; + +private: + pthread_t m_thread = {0}; + static void* thread_start(void* param) + { + return ((CThread*)param)->thread_routine(); + } +}; + +class CMutex +{ +public: + ~CMutex() + { + pthread_mutex_destroy(&m_priv); + } + + void lock() + { + pthread_mutex_lock(&m_priv); + } + void unlock() + { + pthread_mutex_unlock(&m_priv); + } + +private: + /* + * This behaviour allows threads to lock the mutex multiple times whilst + * blocking other threads. Avoids risk of deadlocks and simplifies code. + */ + pthread_mutex_t m_priv = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +}; + +class CSemaphore +{ +public: + CSemaphore() + { + sem_init(&m_sem, 0, 0); + } + + ~CSemaphore() + { + sem_destroy(&m_sem); + } + + bool post() + { + return sem_post(&m_sem) == 0; + } + + bool wait() + { + return sem_wait(&m_sem) == 0; + } + + bool trywait() + { + return sem_trywait(&m_sem) == 0; + } + + bool timedwait(const struct timespec* abs_timeout) + { + return sem_timedwait(&m_sem, abs_timeout) == 0; + } + + bool timedwait(unsigned ms) + { + timespec to; + to.tv_sec = ms / 1000; + to.tv_nsec = (ms % 1000) * 1000000; + return timedwait(&to); + } + +private: + sem_t m_sem; +}; diff --git a/Sming/Arch/Host/Components/hostlib/uart_server.cpp b/Sming/Arch/Host/Components/hostlib/uart_server.cpp new file mode 100644 index 0000000000..32f6012907 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/uart_server.cpp @@ -0,0 +1,212 @@ +/** + * uart_server.cpp + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "uart_server.h" + +#include +#include +#include + +const unsigned IDLE_SLEEP_MS = 100; + +unsigned CUartServer::portBase = 10000; + +static CUartServer* uartServers[UART_COUNT]; + +void CUartServer::startup(const UartServerConfig& config) +{ + if(config.portBase != 0) { + portBase = config.portBase; + } + + auto notify = [](uart_t* uart, uart_notify_code_t code) { + auto server = uartServers[uart->uart_nr]; + if(server) { + server->onNotify(uart, code); + } else if(code == UART_NOTIFY_AFTER_WRITE) { + uart->tx_buffer->clear(); + } + }; + + for(unsigned i = 0; i < UART_COUNT; ++i) { + uart_set_notify(i, notify); + if(!bitRead(config.enableMask, i)) { + continue; + } + auto& server = uartServers[i]; + server = new CUartServer(i); + server->execute(); + } +} + +void CUartServer::shutdown() +{ + for(unsigned i = 0; i < UART_COUNT; ++i) { + auto& server = uartServers[i]; + delete server; + server = nullptr; + } +} + +CUartServer::~CUartServer() +{ + close(); + hostmsg("UART%u server destroyed", uart_nr); +} + +void CUartServer::onNotify(uart_t* uart, uart_notify_code_t code) +{ + switch(code) { + case UART_NOTIFY_AFTER_OPEN: + this->uart = uart; + break; + + case UART_NOTIFY_BEFORE_CLOSE: + this->uart = nullptr; + break; + + case UART_NOTIFY_AFTER_WRITE: { + if(socket == nullptr) { + // Not connected, discard data + uart->tx_buffer->clear(); + } else { + // Kick the thread to send now + txsem.post(); + } + break; + } + + case UART_NOTIFY_WAIT_TX: + break; + + case UART_NOTIFY_BEFORE_READ: + break; + } +} + +int CUartServer::serviceRead() +{ + if(!uart_rx_enabled(uart)) { + return 0; + } + + int avail = socket->available(); + if(avail <= 0) { + return avail; + } + + int space = uart->rx_buffer->getFreeSpace(); + int read = std::min(space, avail); + if(read == 0) { + return 0; + } + + char buffer[read]; + read = socket->recv(buffer, read); + if(read > 0) { + for(int i = 0; i < read; ++i) { + uart->rx_buffer->writeChar(buffer[i]); + } + space -= read; + if(space == 0) { + bitSet(uart->status, UIFF); + } else { + bitSet(uart->status, UITO); + } + } + + return read; +} + +int CUartServer::serviceWrite() +{ + if(!uart_tx_enabled(uart)) { + return 0; + } + + int result = 0; + size_t avail; + void* data; + auto txbuf = uart->tx_buffer; + while((avail = txbuf->getReadData(data)) != 0) { + int sent = socket->send(data, avail); + if(sent < 0) { + hostmsg("Uart send returned %d", sent); + result = sent; + break; + } + txbuf->skipRead(sent); + result += sent; + } + + if(txbuf->isEmpty()) { + bitSet(uart->status, UIFE); + } else { + txsem.post(); + } + + return result; +} + +void* CUartServer::thread_routine() +{ + auto port = portBase + uart_nr; + CSockAddr addr(nullptr, port); + if(!listen(addr, 1)) { + hostmsg("Listen %s failed", addr.text().c_str()); + return nullptr; + } + + hostmsg("UART%u server listening on port %u", uart_nr, port); + + while(active()) { + socket = try_connect(); + if(socket == nullptr) { + msleep(300); + continue; + } + + hostmsg("Uart #%u socket open", uart_nr); + + while(socket->active()) { + if(txsem.timedwait(IDLE_SLEEP_MS)) { + if(serviceWrite() < 0) { + break; + } + } + + if(serviceRead() < 0) { + break; + } + + if(uart != nullptr) { + auto status = uart->status; + uart->status = 0; + if(status != 0 && uart->callback != nullptr) { + uart->callback(uart, status); + } + } + } + + socket->close(); + hostmsg("Uart #%u socket closed", uart_nr); + } + + return nullptr; +} diff --git a/Sming/Arch/Host/Components/hostlib/uart_server.h b/Sming/Arch/Host/Components/hostlib/uart_server.h new file mode 100644 index 0000000000..84a57a7e93 --- /dev/null +++ b/Sming/Arch/Host/Components/hostlib/uart_server.h @@ -0,0 +1,73 @@ +/** + * uart_server.h - UART emulation using sockets + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#include +#include "sockets.h" +#include "threads.h" + +#define UART_SOCKET_PORT_BASE 10000 ///< Port for UART0 + +struct UartServerConfig { + unsigned enableMask; ///< Bit mask for required servers + unsigned portBase; ///< Base port address (optional) +}; + +/* + * Each server allocates a thread to listen for incoming connections. Only one client + * connection is permitted. + * + * For simplicity this implementation uses sockets for communication, so we can just use + * telnet as the terminal application. + * + * A socket is opened for each uart on the system at startup. If no client is connected + * any output is discarded. + * + */ +class CUartServer : public CThread, public CServerSocket +{ +public: + /** + * @brief Start requested servers + * @param config + */ + static void startup(const UartServerConfig& config); + + static void shutdown(); + + CUartServer(unsigned uart_nr) : uart_nr(uart_nr) + { + } + + ~CUartServer(); + +protected: + void onNotify(uart_t* uart, uart_notify_code_t code); + int serviceRead(); + int serviceWrite(); + void* thread_routine() override; + +private: + static unsigned portBase; + CSocket* socket = nullptr; ///< Connected client + CSemaphore txsem; ///< Signals when there's data to be sent out + unsigned uart_nr; ///< Which port we represent + uart_t* uart = nullptr; ///< On set if port is open by application +}; diff --git a/Sming/Arch/Host/Components/libc/memmem.c b/Sming/Arch/Host/Components/libc/memmem.c new file mode 100644 index 0000000000..4c8747337b --- /dev/null +++ b/Sming/Arch/Host/Components/libc/memmem.c @@ -0,0 +1,37 @@ + +#include + +#ifndef _GNU_SOURCE + +void *memmem(const void *haystack, size_t haystack_len, + const void *needle, size_t needle_len) +{ + const char *begin = haystack; + const char *last_possible = begin + haystack_len - needle_len; + const char *tail = needle; + char point; + + /* + * The first occurrence of the empty string is deemed to occur at + * the beginning of the string. + */ + if (needle_len == 0) + return (void *)begin; + + /* + * Sanity check, otherwise the loop might search through the whole + * memory. + */ + if (haystack_len < needle_len) + return NULL; + + point = *tail++; + for (; begin <= last_possible; begin++) { + if (*begin == point && !memcmp(begin + 1, tail, needle_len - 1)) + return (void *)begin; + } + + return NULL; +} + +#endif diff --git a/Sming/Arch/Host/Components/lwip/Linux/CMakeLists.txt b/Sming/Arch/Host/Components/lwip/Linux/CMakeLists.txt new file mode 100644 index 0000000000..58152d0579 --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Linux/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.8) + +project(lwip C) + +set (BUILD_SHARED_LIBS OFF) +set (CMAKE_C_STANDARD 11) +set (CMAKE_C_STANDARD_REQUIRED ON) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_SYSTEM_NAME STREQUAL "GNU") + message(FATAL_ERROR "Lwip shared library is only working on Linux or the Hurd") +endif() + +set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DLWIP_DEBUG") +set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../lwip) +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/.." + "${LWIP_DIR}/src/include" + "${LWIP_CONTRIB_DIR}/ports/unix/port/include" + "${CMAKE_CURRENT_SOURCE_DIR}/" +) + +include(${LWIP_CONTRIB_DIR}/ports/unix/Filelists.cmake) +include(${LWIP_DIR}/src/Filelists.cmake) + +add_library(lwip + host_lwip.c + ${LWIP_DIR}/src/api/err.c + ${lwipcore_SRCS} + ${lwipcore4_SRCS} + ${lwipcore6_SRCS} + ${lwipnetif_SRCS} + ${lwipcontribportunix_SRCS} + ${lwipcontribportunixnetifs_SRCS} +) + +set_target_properties(lwip + PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR}) + +target_compile_options(lwip PRIVATE ${LWIP_COMPILER_FLAGS} -m32) +target_compile_definitions(lwip PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_include_directories(lwip PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) diff --git a/Sming/Arch/Host/Components/lwip/Linux/host_lwip.c b/Sming/Arch/Host/Components/lwip/Linux/host_lwip.c new file mode 100644 index 0000000000..a7dd6bc34e --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Linux/host_lwip.c @@ -0,0 +1,168 @@ +/** + * host_lwip.cpp + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "../host_lwip.h" +#include "../../hostlib/hostmsg.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct net_config { + char ifname[32]; + ip4_addr_t ipaddr; + ip4_addr_t netmask; + ip4_addr_t gw; +}; + +static struct netif netif; + +static void getMacAddress(const char* ifname, uint8_t hwaddr[6]) +{ + struct ifreq ifr = {0}; + ifr.ifr_addr.sa_family = AF_INET; + strcpy(ifr.ifr_name, ifname); + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + ioctl(fd, SIOCGIFHWADDR, &ifr); + close(fd); + + memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6); +} + +/** + * @brief Fetch address and network mask for an interface + * @param ifname NULL to get first compatible interface + */ +static bool getifaddr(const char* ifname, struct net_config* netcfg) +{ + struct ifaddrs* list; + if(getifaddrs(&list) < 0) { + hostmsg("getifaddrs: %s", strerror(errno)); + return false; + } + + bool res = false; + + for(struct ifaddrs* ifa = list; ifa != NULL; ifa = ifa->ifa_next) { + if(ifa->ifa_addr == NULL) { + continue; + } + if(ifa->ifa_addr->sa_family != AF_INET) { + continue; + } + + if(ifname == NULL) { + if(memcmp(ifa->ifa_name, "tap", 3) != 0) { + continue; + } + } else if(strcmp(ifa->ifa_name, ifname) != 0) { + continue; + } + + strcpy(netcfg->ifname, ifa->ifa_name); + netcfg->gw.addr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr; + netcfg->netmask.addr = ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr; + + res = true; + break; + } + + freeifaddrs(list); + return res; +} + +bool host_lwip_init(const struct lwip_param* param) +{ + hostmsg("%s", "Initialising LWIP"); + + struct net_config netcfg = {0}; + + if(!getifaddr(param->ifname, &netcfg)) { + if(param->ifname == NULL) { + hostmsg("%s", "No compatible interface found"); + } else { + hostmsg("Interface '%s' not found", param->ifname); + } + return false; + } + + if(param->gateway != NULL && ip4addr_aton(param->gateway, &netcfg.gw) != 1) { + hostmsg("Failed to parse provided Gateway address '%s'", param->gateway); + return false; + } + + if(param->netmask != NULL && ip4addr_aton(param->netmask, &netcfg.netmask) != 1) { + hostmsg("Failed to parse provided Network Mask '%s'", param->netmask); + return false; + } + + if(param->ipaddr == NULL) { + // Choose a default IP address + IP4_ADDR(&netcfg.ipaddr, ip4_addr1(&netcfg.gw), ip4_addr2(&netcfg.gw), ip4_addr3(&netcfg.gw), 10); + } else if(ip4addr_aton(param->ipaddr, &netcfg.ipaddr) != 1) { + hostmsg("Failed to parse provided IP address '%s'", param->ipaddr); + return false; + } + + char ip_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&netcfg.ipaddr, ip_str, sizeof(ip_str)); + char nm_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&netcfg.netmask, nm_str, sizeof(nm_str)); + char gw_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&netcfg.gw, gw_str, sizeof(gw_str)); + hostmsg("Using interface '%s', gateway = %s, netmask = %s; using ip = %s", netcfg.ifname, gw_str, nm_str, ip_str); + + setenv("PRECONFIGURED_TAPIF", netcfg.ifname, true); + + lwip_init(); + + netif_add(&netif, &netcfg.ipaddr, &netcfg.netmask, &netcfg.gw, NULL, tapif_init, ethernet_input); + + getMacAddress(netcfg.ifname, netif.hwaddr); + hostmsg("MAC: %02x:%02x:%02x:%02x:%02x:%02x", netif.hwaddr[0], netif.hwaddr[1], netif.hwaddr[2], netif.hwaddr[3], + netif.hwaddr[4], netif.hwaddr[5]); + + netif_set_default(&netif); + + return true; +} + +void host_lwip_service(void) +{ + /* poll netif, pass packet to lwIP */ + tapif_select(&netif); + sys_check_timeouts(); +} + +void host_lwip_shutdown(void) +{ +} diff --git a/Sming/Arch/Host/Components/lwip/Windows/CMakeLists.txt b/Sming/Arch/Host/Components/lwip/Windows/CMakeLists.txt new file mode 100644 index 0000000000..f3819e1f39 --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Windows/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.8) + +project(lwip C) + +set (BUILD_SHARED_LIBS OFF) +set (CMAKE_C_STANDARD 11) +set (CMAKE_C_STANDARD_REQUIRED ON) + +include (ExternalProject) + +set (PCAP_SRC npcap-sdk-1.03.zip) +set (PCAP_DIR src/npcap) +ExternalProject_Add(npcap + PREFIX ${CMAKE_CURRENT_SOURCE_DIR} + URL https://nmap.org/npcap/dist/${PCAP_SRC} + URL_HASH MD5=b9bfe28d9c9dc1110d6d635d7e7f9e23 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" +) + +set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DLWIP_DEBUG") + +set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../lwip) +include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake) + +set (LWIP_INCLUDE_DIRS + "${LWIP_DIR}/.." + "${LWIP_DIR}/src/include" + "${LWIP_CONTRIB_DIR}/ports/win32/include" + "${PCAP_DIR}/Include" + "${CMAKE_CURRENT_SOURCE_DIR}/" +) + +include(${LWIP_DIR}/src/Filelists.cmake) + +add_library(lwip + host_lwip.c + npcap.c + ${LWIP_CONTRIB_DIR}/ports/win32/sys_arch.c + ${LWIP_CONTRIB_DIR}/ports/win32/pcapif.c + ${LWIP_CONTRIB_DIR}/ports/win32/pcapif_helper.c + ${LWIP_DIR}/src/api/err.c + ${lwipcore_SRCS} + ${lwipcore4_SRCS} + ${lwipcore6_SRCS} + ${lwipnetif_SRCS} +) + +add_dependencies(lwip npcap) + +set_target_properties(lwip + PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${USER_LIBDIR} +) + +target_compile_options(lwip PRIVATE ${LWIP_COMPILER_FLAGS} -m32 -Wno-strict-aliasing) +target_compile_definitions(lwip PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) +target_compile_definitions(lwip PUBLIC ${CFLAGS_EXTRA}) +target_include_directories(lwip PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) diff --git a/Sming/Arch/Host/Components/lwip/Windows/host_lwip.c b/Sming/Arch/Host/Components/lwip/Windows/host_lwip.c new file mode 100644 index 0000000000..d72881251a --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Windows/host_lwip.c @@ -0,0 +1,226 @@ +/** + * host_lwip.cpp + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include "../host_lwip.h" +#include "../../hostlib/hostmsg.h" + +#include "lwipcfg.h" +#include <../pcapif.h> +#include "npcap.h" +#include + +#include +#include +#include +#include +#include +#include + +struct net_config { + char ifname[128]; + unsigned ifindex; + ip4_addr_t ipaddr; + ip4_addr_t netmask; + ip4_addr_t gw; +}; + +static struct netif netif; + +/* + * Find an IP4 address in a list of addresses + */ +static bool find_ip4_addr(struct pcap_addr* pca, ip4_addr_t* addr, ip4_addr_t* mask) +{ +#define IP4(saddr) ((ip4_addr_t*)&(((struct sockaddr_in*)saddr)->sin_addr)) + for(; pca != NULL; pca = pca->next) { + if(pca->addr == NULL || pca->addr->sa_family != AF_INET) { + continue; + } + addr->addr = ((struct sockaddr_in*)pca->addr)->sin_addr.s_addr; + mask->addr = ((struct sockaddr_in*)pca->netmask)->sin_addr.s_addr; + return true; + } + return false; +} + +/* + * param->ifname can be: + * + * A GUID doesn't need to be complete + * An adapter number 0, 1, 2, etc. + * NULL autodetect - if provided, will use param->ipaddr + * ? list adapters + * + */ +static bool find_adapter(const struct lwip_param* param, struct net_config* netcfg) +{ + int ifindex = -1; + + if(param->ifname != NULL) { + // Check for valid numeric argument, interpreted as the adapter number + char* tail; + ifindex = strtol(param->ifname, &tail, 0); + if(*tail != '\0') { + ifindex = -1; // Not a valid number + } + } + + pcap_if_t* alldevs; + char errbuf[PCAP_ERRBUF_SIZE + 1]; + if(pcap_findalldevs(&alldevs, errbuf) < 0) { + hostmsg("Error in pcap_findalldevs: %s", errbuf); + return false; + } + + if(param->ifname != NULL && param->ifname[0] == '?') { + printf("Available adapters:\n"); + } + + bool res = false; + + pcap_if_t* d = alldevs; + int idx = 0; + for(; d != NULL; d = d->next, idx++) { + if(param->ifname == NULL) { + // @todo autodetect + ip4_addr_t addr; + ip4_addr_t mask; + if(find_ip4_addr(d->addresses, &addr, &mask)) { + if(ip4_addr_isany_val(addr)) { + continue; + } + + // If an IP address was requested, use that in our search for an appropriate adapter + if(!ip4_addr_isany_val(netcfg->ipaddr) && !ip4_addr_netcmp(&netcfg->ipaddr, &addr, &mask)) { + // Skip, address doesn't comply + continue; + } + + netcfg->ifindex = idx; + strncpy(netcfg->ifname, d->description, sizeof(netcfg->ifname)); + netcfg->ifname[sizeof(netcfg->ifname) - 1] = '\0'; + netcfg->netmask.addr = mask.addr; + res = true; + break; + } + } else if(param->ifname[0] == '?') { + const char* guid_ptr = strchr(d->name, '{'); + if(guid_ptr == NULL) { + guid_ptr = d->name; + } + printf("- %d: %s", idx, guid_ptr); + if(d->description != NULL) { + printf(" - %s", d->description); + } + printf("\n"); + + ip4_addr_t addr; + ip4_addr_t mask; + if(find_ip4_addr(d->addresses, &addr, &mask)) { + char s[128]; + strcpy(s, ip4addr_ntoa(&addr)); + strcat(s, " / "); + strcat(s, ip4addr_ntoa(&mask)); + printf(" %s\n", s); + } + } else if(idx == ifindex || (ifindex < 0 && strstr(d->name, param->ifname) != NULL)) { + netcfg->ifindex = idx; + strncpy(netcfg->ifname, d->description, sizeof(netcfg->ifname)); + netcfg->ifname[sizeof(netcfg->ifname) - 1] = '\0'; + if(ip4_addr_isany_val(netcfg->netmask)) { + ip4_addr_t addr; + find_ip4_addr(d->addresses, &addr, &netcfg->netmask); + } + res = true; + break; + } + } + + pcap_freealldevs(alldevs); + + if(param->ifname != NULL && param->ifname[0] == '?') { + exit(1); + } + + return res; +} + +bool host_lwip_init(const struct lwip_param* param) +{ + hostmsg("%s", "Initialising LWIP"); + + if(!npcap_init()) { + return false; + } + + struct net_config netcfg = {0}; + + if(param->ipaddr != NULL && ip4addr_aton(param->ipaddr, &netcfg.ipaddr) != 1) { + hostmsg("Failed to parse IP address '%s'", param->ipaddr); + return false; + } + + if(param->netmask != NULL && ip4addr_aton(param->netmask, &netcfg.netmask) != 1) { + hostmsg("Failed to parse Network Mask '%s'", param->netmask); + return false; + } + + if(param->gateway != NULL && ip4addr_aton(param->gateway, &netcfg.gw) != 1) { + hostmsg("Failed to parse Gateway address '%s'", param->gateway); + return false; + } + + if(!find_adapter(param, &netcfg)) { + return false; + } + + char ip_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&netcfg.ipaddr, ip_str, sizeof(ip_str)); + char nm_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&netcfg.netmask, nm_str, sizeof(nm_str)); + char gw_str[IP4ADDR_STRLEN_MAX]; + ip4addr_ntoa_r(&netcfg.gw, gw_str, sizeof(gw_str)); + hostmsg("gateway = %s, netmask = %s; using ip = %s", gw_str, nm_str, ip_str); + + // Even though we're running as NO_SYS, stuff like crypt needs initialising + sys_init(); + lwip_init(); + + void* state = (void*)(netcfg.ifindex + 1); // See pcapif_low_level_init() + netif_add(&netif, &netcfg.ipaddr, &netcfg.netmask, &netcfg.gw, state, pcapif_init, ethernet_input); + netif_set_default(&netif); + + hostmsg("MAC: %02x:%02x:%02x:%02x:%02x:%02x", netif.hwaddr[0], netif.hwaddr[1], netif.hwaddr[2], netif.hwaddr[3], + netif.hwaddr[4], netif.hwaddr[5]); + + return true; +} + +void host_lwip_service(void) +{ + /* check for packets and link status*/ + pcapif_poll(&netif); + sys_check_timeouts(); +} + +void host_lwip_shutdown(void) +{ + /* release the pcap library... */ + pcapif_shutdown(&netif); +} diff --git a/Sming/Arch/Host/Components/lwip/Windows/lwipcfg.h b/Sming/Arch/Host/Components/lwip/Windows/lwipcfg.h new file mode 100644 index 0000000000..1feab2a8ae --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Windows/lwipcfg.h @@ -0,0 +1,15 @@ +/** + * Additional settings for the win32 port. + */ + +#define PCAPIF_LIB_QUIET + +#define PCAPIF_HANDLE_LINKSTATE 0 +#define PCAPIF_FILTER_GROUP_ADDRESSES 0 + +/* remember to change this MAC address to suit your needs! + the last octet will be increased by netif->num for each netif */ +#define LWIP_MAC_ADDR_BASE \ + { \ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 \ + } diff --git a/Sming/Arch/Host/Components/lwip/Windows/npcap.c b/Sming/Arch/Host/Components/lwip/Windows/npcap.c new file mode 100644 index 0000000000..c60e021ba4 --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Windows/npcap.c @@ -0,0 +1,120 @@ +/** + * npcap.c + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#include + +#include "npcap.h" + +#undef PCAP_API +#define PCAP_API + +// Casting of void* to function pointer not permitted by Ansi C +#pragma GCC diagnostic ignored "-Wpedantic" + +WINAPI BOOL SetDllDirectoryA(LPCSTR lpPathName); + +/* + * Define a table for all the functions we need to bind. We use this to create for each function: + * + * Function pointer - bound address of imported function + * Function typedef - so we can cast bound pointer for calling + * Function stub - passes call onto actual function + * + * If we get any of this wrong the compiler should complain as it'll check against prototypes in pcap.h. + * + * name, rettype, errval, argtypes, args + * + * name Name of the function + * rettype Return type + * errval Value returned if function wasn't bound + * argtypes Parameter types for declaring the function + * args Parameter names, used for invoking the function + */ +#define PCAP_FUNCTIONS(XX) \ + XX(pcap_lib_version, const char*, NULL, (void), ()) \ + XX(pcap_close, void, 0, (pcap_t * a), (a)) \ + XX(pcap_dispatch, int, PCAP_ERROR, (pcap_t * a, int b, pcap_handler c, u_char* d), (a, b, c, d)) \ + XX(pcap_sendpacket, int, PCAP_ERROR, (pcap_t * a, const u_char* b, int c), (a, b, c)) \ + XX(pcap_findalldevs, int, PCAP_ERROR, (pcap_if_t * *a, char* b), (a, b)) \ + XX(pcap_freealldevs, void, 0, (pcap_if_t * a), (a)) \ + XX(pcap_open_live, pcap_t*, NULL, (const char* a, int b, int c, int d, char* e), (a, b, c, d, e)) \ + XX(pcap_breakloop, void, 0, (pcap_t * a), (a)) + +#define XX(name, rettype, errval, argtypes, args) static void* pf_##name; +PCAP_FUNCTIONS(XX) +#undef XX + +#define XX(name, rettype, errval, argtypes, args) typedef rettype(*name##_t) argtypes; +PCAP_FUNCTIONS(XX) +#undef XX + +#define XX(name, rettype, errval, argtypes, args) \ + rettype name argtypes \ + { \ + if(pf_##name == NULL) { \ + return (rettype)errval; \ + } else { \ + return ((name##_t)pf_##name)args; \ + } \ + } +PCAP_FUNCTIONS(XX) +#undef XX + +static HMODULE wpcap_module; +static void* bind_func(const char* name) +{ + void* pf = GetProcAddress(wpcap_module, name); + if(pf == NULL) { + fprintf(stderr, "Failed to bind '%s'", name); + } + return pf; +} + +bool npcap_init(void) +{ + const char* NPCAP_DIR = "npcap"; + const char* WPCAP_DLL = "wpcap.dll"; + + char path[MAX_PATH]; + GetSystemDirectory(path, MAX_PATH); + strcat(path, "\\"); + strcat(path, NPCAP_DIR); + SetDllDirectoryA(path); + wpcap_module = LoadLibrary(WPCAP_DLL); + if(wpcap_module == 0) { + fprintf(stderr, + "\n" + " ERROR! Failed to load 'wpcap.dll'\n" + " Have you installed the NPCAP library? See https://nmap.org/npcap/\n" + " Alternatively install Wireshark 3.0.2 or later. See https://www.wireshark.org/download.html\n" + "\n"); + return false; + } + +#define XX(name, rettype, retval, argtypes, args) \ + if((pf_##name = bind_func(#name)) == NULL) { \ + return false; \ + } + PCAP_FUNCTIONS(XX) +#undef XX + + fprintf(stderr, "** %s\n", pcap_lib_version()); + + return true; +} diff --git a/Sming/Arch/Host/Components/lwip/Windows/npcap.h b/Sming/Arch/Host/Components/lwip/Windows/npcap.h new file mode 100644 index 0000000000..80d36b9443 --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Windows/npcap.h @@ -0,0 +1,29 @@ +/** + * npcap.h - Load NPCAP library dynamically + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#include + +/* + * Load NPCAP library (actually called wpdand bind required functions + * + * If + */ +bool npcap_init(void); diff --git a/Sming/Arch/Host/Components/lwip/Windows/ntddndis.h b/Sming/Arch/Host/Components/lwip/Windows/ntddndis.h new file mode 100644 index 0000000000..da7b7c4eab --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/Windows/ntddndis.h @@ -0,0 +1,4 @@ +#pragma once + +#include +#include diff --git a/Sming/Arch/Host/Components/lwip/host_lwip.h b/Sming/Arch/Host/Components/lwip/host_lwip.h new file mode 100644 index 0000000000..232159d236 --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/host_lwip.h @@ -0,0 +1,42 @@ +/** + * host_lwip.h - Sming Host LWIP network support + * + * Copyright 2019 mikee47 + * + * This file is part of the Sming Framework Project + * + * This library is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, version 3 or later. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SHEM. + * If not, see . + * + ****/ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct lwip_param { + const char* ifname; ///< Name of interface to use + const char* ipaddr; ///< Client IP address + const char* gateway; ///< Network gateway address + const char* netmask; ///< Network mask +}; + +bool host_lwip_init(const struct lwip_param* param); +void host_lwip_service(void); +void host_lwip_shutdown(void); + +#ifdef __cplusplus +} +#endif diff --git a/Sming/Arch/Host/Components/lwip/lwip b/Sming/Arch/Host/Components/lwip/lwip new file mode 160000 index 0000000000..ec11b289cb --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/lwip @@ -0,0 +1 @@ +Subproject commit ec11b289cb18490fae94fda199fbb54cc35226f8 diff --git a/Sming/Arch/Host/Components/lwip/lwip.patch b/Sming/Arch/Host/Components/lwip/lwip.patch new file mode 100644 index 0000000000..ebed698266 --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/lwip.patch @@ -0,0 +1,127 @@ +diff --git a/contrib/ports/unix/port/sys_arch.c b/contrib/ports/unix/port/sys_arch.c +index a56d7de1..dd3f16e1 100644 +--- a/contrib/ports/unix/port/sys_arch.c ++++ b/contrib/ports/unix/port/sys_arch.c +@@ -730,13 +730,3 @@ sys_arch_unprotect(sys_prot_t pval) + } + #endif /* SYS_LIGHTWEIGHT_PROT */ + +-/* get keyboard state to terminate the debug app by using select */ +-int +-lwip_unix_keypressed(void) +-{ +- struct timeval tv = { 0L, 0L }; +- fd_set fds; +- FD_ZERO(&fds); +- FD_SET(0, &fds); +- return select(1, &fds, NULL, NULL, &tv); +-} +diff --git a/contrib/ports/CMakeCommon.cmake b/contrib/ports/CMakeCommon.cmake +index fccf0f31..0a6378c4 100644 +--- a/contrib/ports/CMakeCommon.cmake ++++ b/contrib/ports/CMakeCommon.cmake +@@ -65,25 +65,12 @@ set(LWIP_COMPILER_FLAGS_GNU_CLANG + -Wlogical-not-parentheses + ) + +-if (NOT LWIP_HAVE_MBEDTLS) +- list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG +- -Wredundant-decls +- $<$:-Wc++-compat> +- ) +-endif() +- + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG + -Wlogical-op + -Wtrampolines + ) + +- if (NOT LWIP_HAVE_MBEDTLS) +- list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG +- $<$:-Wc90-c99-compat> +- ) +- endif() +- + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) + if(LWIP_USE_SANITIZERS) + list(APPEND LWIP_COMPILER_FLAGS_GNU_CLANG +diff --git a/contrib/ports/win32/sys_arch.c b/contrib/ports/win32/sys_arch.c +index 84c1bcaf..f23dfa67 100644 +--- a/contrib/ports/win32/sys_arch.c ++++ b/contrib/ports/win32/sys_arch.c +@@ -38,6 +38,7 @@ + #pragma warning (push, 3) + #endif + #include ++#include + #ifdef _MSC_VER + #pragma warning (pop) + #endif +@@ -732,28 +733,6 @@ sys_arch_netconn_sem_free(void) + + #endif /* !NO_SYS */ + +-/* get keyboard state to terminate the debug app on any kbhit event using win32 API */ +-int +-lwip_win32_keypressed(void) +-{ +- INPUT_RECORD rec; +- DWORD num = 0; +- HANDLE h = GetStdHandle(STD_INPUT_HANDLE); +- BOOL ret = PeekConsoleInput(h, &rec, 1, &num); +- if (ret && num) { +- ReadConsoleInput(h, &rec, 1, &num); +- if (rec.EventType == KEY_EVENT) { +- if (rec.Event.KeyEvent.bKeyDown) { +- /* not a special key? */ +- if (rec.Event.KeyEvent.uChar.AsciiChar != 0) { +- return 1; +- } +- } +- } +- } +- return 0; +-} +- + #include + + /* This is an example implementation for LWIP_PLATFORM_DIAG: + +diff --git a/contrib/ports/win32/pcapif.c b/contrib/ports/win32/pcapif.c +index 36356ca5..895f2a2d 100644 +--- a/contrib/ports/win32/pcapif.c ++++ b/contrib/ports/win32/pcapif.c +@@ -40,16 +40,7 @@ + #include + #include + +-#ifdef _MSC_VER +-#pragma warning( push, 3 ) + #include "pcap.h" +-#pragma warning ( pop ) +-#else +-/* e.g. mingw */ +-#define _MSC_VER 1500 +-#include "pcap.h" +-#undef _MSC_VER +-#endif + + #include "lwip/opt.h" + +@@ -477,7 +468,6 @@ pcap_reopen_adapter(struct pcapif_private *pa) + static struct pcapif_private* + pcapif_init_adapter(int adapter_num, void *arg) + { +- int i; + int number_of_adapters; + struct pcapif_private *pa; + char errbuf[PCAP_ERRBUF_SIZE+1]; +@@ -539,6 +529,7 @@ pcapif_init_adapter(int adapter_num, void *arg) + } + + #ifndef PCAPIF_LIB_QUIET ++ int i; + /* Scan the list printing every entry */ + for (d = alldevs, i = 0; d != NULL; d = d->next, i++) { + char *desc = d->description; diff --git a/Sming/Arch/Host/Components/lwip/lwipopts.h b/Sming/Arch/Host/Components/lwip/lwipopts.h new file mode 100644 index 0000000000..790ca500cb --- /dev/null +++ b/Sming/Arch/Host/Components/lwip/lwipopts.h @@ -0,0 +1,511 @@ +/** + * @file + * + * lwIP Options Configuration + * + * Note: + * This is a copy of lwip/contrib/ports/unix/lib/lwipopts.h + * It is included via lwip/opts.h and MUST NOT be included directly from Sming code + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +#ifndef LWIP_LWIPOPTS_H +#define LWIP_LWIPOPTS_H + +#include "lwip/debug.h" + +/* + ----------------------------------------------- + ---------- Platform specific locking ---------- + ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 1 + +/** + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#define NO_SYS 1 + +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#define MEM_ALIGNMENT 4U + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#define MEM_SIZE 16000 + +/* + ------------------------------------------------ + ---------- Internal Memory Pool Sizes ---------- + ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#define MEMP_NUM_PBUF 16 + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#define MEMP_NUM_RAW_PCB 4 + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#define MEMP_NUM_UDP_PCB 4 + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB 4 + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_PCB_LISTEN 4 + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#define MEMP_NUM_TCP_SEG 16 + +/** + * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * reassembly (whole packets, not fragments!) + */ +#define MEMP_NUM_REASSDATA 1 + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#define MEMP_NUM_ARP_QUEUE 10 +#define ARP_QUEUEING 1 + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#define MEMP_NUM_SYS_TIMEOUT 8 + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#define MEMP_NUM_NETBUF 0 + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#define MEMP_NUM_NETCONN 0 + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication. + * (only needed if you use tcpip.c) + */ +#define MEMP_NUM_TCPIP_MSG_API 4 + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets. + * (only needed if you use tcpip.c) + */ +#define MEMP_NUM_TCPIP_MSG_INPKT 4 + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + */ +#define PBUF_POOL_SIZE 8 + +/* + --------------------------------- + ---------- ARP options ---------- + --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#define LWIP_ARP 1 + +/* + -------------------------------- + ---------- IP options ---------- + -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#define IP_FORWARD 0 + +/** + * IP_OPTIONS: Defines the behavior for IP options. + * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#define IP_OPTIONS_ALLOWED 1 + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#define IP_REASSEMBLY 0 + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#define IP_FRAG 0 + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#define IP_REASS_MAXAGE 3 + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#define IP_REASS_MAX_PBUFS 10 + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented. +*/ +#define IP_FRAG_USES_STATIC_BUF 0 + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#define IP_DEFAULT_TTL 255 + +/* + ---------------------------------- + ---------- ICMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#define LWIP_ICMP 1 + +/* + --------------------------------- + ---------- RAW options ---------- + --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#define LWIP_RAW 1 + +/* + ---------------------------------- + ---------- DHCP options ---------- + ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#define LWIP_DHCP 1 +#define LWIP_DHCP_GET_NTP_SRV 0 + + +/* + ------------------------------------ + ---------- AUTOIP options ---------- + ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#define LWIP_AUTOIP 0 + +/* + ---------------------------------- + ---------- SNMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#define LWIP_SNMP 0 + +/* + ---------------------------------- + ---------- IGMP options ---------- + ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#define LWIP_IGMP 0 + +/* + ---------------------------------- + ---------- DNS options ----------- + ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#define LWIP_DNS 1 + +/* + --------------------------------- + ---------- UDP options ---------- + --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#define LWIP_UDP 1 +#define LWIP_UDPLITE LWIP_UDP + +#define LWIP_NETBUF_RECVINFO 0 + +/* + --------------------------------- + ---------- TCP options ---------- + --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#define LWIP_TCP 1 +#define LWIP_LISTEN_BACKLOG 0 +#define TCP_QUEUE_OOSEQ 0 +#define LWIP_TCP_KEEPALIVE 1 + +/* + ---------------------------------- + ---------- Pbuf options ---------- + ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#define PBUF_LINK_HLEN 16 + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. +* + */ +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#define LWIP_HAVE_LOOPIF 0 + +/* + ---------------------------------------------- + ---------- Sequential layer options ---------- + ---------------------------------------------- +*/ + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN 0 + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET 0 +#define LWIP_POSIX_SOCKETS_IO_NAMES 0 + +/** + * SO_REUSE==1: Enable SO_REUSEADDR + */ +#define SO_REUSE 1 + +/* + ---------------------------------------- + ---------- Statistics options ---------- + ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#define LWIP_STATS 0 +/* + --------------------------------- + ---------- PPP options ---------- + --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#define PPP_SUPPORT 0 + + + +/* + --------------------------------------- + ---------- Threading options ---------- + --------------------------------------- +*/ + +#define LWIP_TCPIP_CORE_LOCKING 0 + + +/* + * + * May 2019 - appended options for Sming + * + */ + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquisition) + */ +#define LWIP_NETIF_STATUS_CALLBACK 1 + +/** Set this to 1 to enable querying ".local" names via mDNS + * using a One-Shot Multicast DNS Query */ +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 + + +/* + * Use Google Public DNS servers + */ +#define DNS_SERVER_ADDRESS(ipaddr) IP4_ADDR(ipaddr, 8, 8, 8, 8) + +/* + * Enable/disable sntp_setservername / sntp_getservername + */ +#define SNTP_SERVER_DNS 0 +#define SNTP_SERVER_ADDRESS "pool.ntp.org" +#define SNTP_GET_SERVERS_FROM_DHCP 1 +#define SNTP_SET_SYSTEM_TIME(t) sntp_set_system_time(t) + + +#ifdef LWIP_DEBUG + +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define IGMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TIMERS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF +#define AUTOIP_DEBUG LWIP_DBG_OFF +#define DNS_DEBUG LWIP_DBG_OFF +#define IP6_DEBUG LWIP_DBG_OFF +#define DHCP6_DEBUG LWIP_DBG_OFF +#define LWIP_TESTMODE 0 + +#endif + +#endif /* LWIP_LWIPOPTS_H */ diff --git a/Sming/Arch/Host/Components/spi_flash/include/esp_spi_flash.h b/Sming/Arch/Host/Components/spi_flash/include/esp_spi_flash.h new file mode 100644 index 0000000000..86db814730 --- /dev/null +++ b/Sming/Arch/Host/Components/spi_flash/include/esp_spi_flash.h @@ -0,0 +1,4 @@ + +#define SPI_FLASH_SEC_SIZE 4096 + +#include_next diff --git a/Sming/Arch/Host/Core/Digital.cpp b/Sming/Arch/Host/Core/Digital.cpp new file mode 100644 index 0000000000..f3a50e36ab --- /dev/null +++ b/Sming/Arch/Host/Core/Digital.cpp @@ -0,0 +1,71 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Digital.cpp + * + ****/ + +#include "Digital.h" +#include "WiringFrameworkIncludes.h" + +#define PIN_MAX 16 +static uint8 pinModes[PIN_MAX]; + +static inline bool checkPin(uint16_t pin) +{ + if(pin < 16) { + return true; + } else { + hostmsg("BAD PIN %u", pin); + return false; + } +} + +void pinMode(uint16_t pin, uint8_t mode) +{ + if(checkPin(pin)) { + pinModes[pin] = mode; + hostmsg("pinMode(%u, %u)", pin, mode); + } +} + +//Detect if pin is input +bool isInputPin(uint16_t pin) +{ + return checkPin(pin) ? pinModes[pin] : false; +} + +void digitalWrite(uint16_t pin, uint8_t val) +{ + checkPin(pin); + hostmsg("digitalWrite(%u, %u)", pin, val); +} + +uint8_t digitalRead(uint16_t pin) +{ + checkPin(pin); + hostmsg("digitalRead(%u)", pin); + return 0; +} + +void pullup(uint16_t pin) +{ + checkPin(pin); + hostmsg("pullup(%u)", pin); +} + +void noPullup(uint16_t pin) +{ + checkPin(pin); + hostmsg("noPullup(%u)", pin); +} + +unsigned long pulseIn(uint16_t pin, uint8_t state, unsigned long timeout) +{ + checkPin(pin); + hostmsg("pulseIn(%u, %u, %lu)", pin, state, timeout); + return 0; +} diff --git a/Sming/Arch/Host/Core/HardwareTimer.cpp b/Sming/Arch/Host/Core/HardwareTimer.cpp new file mode 100644 index 0000000000..f0ebb4e04a --- /dev/null +++ b/Sming/Arch/Host/Core/HardwareTimer.cpp @@ -0,0 +1,111 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * HWTimer.cpp + * + * Created 23.11.2015 by johndoe + * + ****/ + +#include "HardwareTimer.h" +#include + +void os_timer_arm(struct os_timer_t* ptimer, uint32_t time, bool repeat_flag); +void os_timer_arm_us(struct os_timer_t* ptimer, uint32_t time, bool repeat_flag); +void os_timer_disarm(struct os_timer_t* ptimer); +void os_timer_setfn(struct os_timer_t* ptimer, os_timer_func_t* pfunction, void* parg); + +static os_timer_t timer; + +uint32_t usToTimerTicks(uint32_t us) +{ + return us; +} + +uint32_t timerTicksToUs(uint32_t ticks) +{ + return ticks; +} + +static void hw_timer_isr_cb(void* param) +{ + if(param != nullptr) { + static_cast(param)->call(); + } +} + +HardwareTimer::HardwareTimer(HardwareTimerMode mode) +{ + os_timer_setfn(&timer, hw_timer_isr_cb, this); +} + +HardwareTimer::~HardwareTimer() +{ + stop(); +} + +HardwareTimer& HardwareTimer::initializeMs(uint32_t milliseconds, InterruptCallback callback) +{ + setCallback(callback); + setIntervalMs(milliseconds); + return *this; +} + +HardwareTimer& HardwareTimer::initializeUs(uint32_t microseconds, InterruptCallback callback) +{ + setCallback(callback); + setIntervalUs(microseconds); + return *this; +} + +bool HardwareTimer::start(bool repeating) +{ + this->repeating = repeating; + stop(); + if(interval == 0 || !callback) { + return started; + } + + started = true; + + os_timer_arm_us(&timer, interval, repeating); + + return started; +} + +void HardwareTimer::stop() +{ + os_timer_disarm(&timer); +} + +bool HardwareTimer::restart() +{ + stop(); + start(repeating); + return started; +} + +bool HardwareTimer::setIntervalUs(uint32_t microseconds) +{ + if(microseconds < MAX_HW_TIMER_INTERVAL_US && microseconds > MIN_HW_TIMER_INTERVAL_US) { + interval = microseconds; + if(started) { + restart(); + } + } else { + stop(); + } + return started; +} + +void HardwareTimer::setCallback(InterruptCallback interrupt) +{ + callback = interrupt; + + if(!interrupt) { + stop(); + } +} diff --git a/Sming/Arch/Host/Core/Interrupts.cpp b/Sming/Arch/Host/Core/Interrupts.cpp new file mode 100644 index 0000000000..9d03304481 --- /dev/null +++ b/Sming/Arch/Host/Core/Interrupts.cpp @@ -0,0 +1,64 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Interrupts.cpp + * + ****/ + +#include "Interrupts.h" +#include "Digital.h" +#include "WiringFrameworkIncludes.h" +#include "Platform/System.h" + +void attachInterrupt(uint8_t pin, InterruptCallback callback, uint8_t mode) +{ +} + +void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, uint8_t mode) +{ +} + +void attachInterrupt(uint8_t pin, InterruptCallback callback, GPIO_INT_TYPE mode) +{ +} + +void attachInterrupt(uint8_t pin, InterruptDelegate delegateFunction, GPIO_INT_TYPE mode) +{ +} + +void attachInterruptHandler(uint8_t pin, GPIO_INT_TYPE mode) +{ +} + +void detachInterrupt(uint8_t pin) +{ +} + +void interruptMode(uint8_t pin, uint8_t mode) +{ +} + +void interruptMode(uint8_t pin, GPIO_INT_TYPE type) +{ +} + +GPIO_INT_TYPE ConvertArduinoInterruptMode(uint8_t mode) +{ + switch(mode) { + case LOW: // to trigger the interrupt whenever the pin is low, + return GPIO_PIN_INTR_LOLEVEL; + case CHANGE: // to trigger the interrupt whenever the pin changes value + return (GPIO_INT_TYPE)3; // GPIO_PIN_INTR_ANYEDGE + case RISING: // to trigger when the pin goes from low to high, + return GPIO_PIN_INTR_POSEDGE; + case FALLING: // for when the pin goes from high to low. + return GPIO_PIN_INTR_NEGEDGE; + case HIGH: // to trigger the interrupt whenever the pin is high. + return GPIO_PIN_INTR_HILEVEL; + default: + return GPIO_PIN_INTR_DISABLE; + } +} diff --git a/Sming/Arch/Host/Core/pins_arduino.h b/Sming/Arch/Host/Core/pins_arduino.h new file mode 100644 index 0000000000..23dd35c576 --- /dev/null +++ b/Sming/Arch/Host/Core/pins_arduino.h @@ -0,0 +1,32 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * pins_arduino.h + * + ****/ + +#pragma once + +const uint16_t A0 = 9999; + +//#define NOT_A_PIN 0 +//#define NOT_A_PORT 0 +//#define NOT_ON_TIMER 0 +// +//#define PA 1 +//#define PB 2 +//#define PC 3 + +typedef uint32_t GPIO_REG_TYPE; + +// We use maximum compatibility to standard Arduino logic. + +//#define digitalPinToPort(pin) (0) +//#define digitalPinToBitMask(pin) (1UL << (pin)) +//#define digitalPinToTimer(pin) (NOT_ON_TIMER) +//#define portOutputRegister(port) ((volatile uint32_t*)&GPO) +//#define portInputRegister(port) ((volatile uint32_t*)&GPI) +//#define portModeRegister(port) ((volatile uint32_t*)&GPE) diff --git a/Sming/Arch/Host/Platform/AccessPoint.cpp b/Sming/Arch/Host/Platform/AccessPoint.cpp new file mode 100644 index 0000000000..1541d730f5 --- /dev/null +++ b/Sming/Arch/Host/Platform/AccessPoint.cpp @@ -0,0 +1,73 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * AccessPoint.cpp + * + ****/ + +#include "Platform/AccessPoint.h" +#include "Data/HexString.h" + +AccessPointClass WifiAccessPoint; + +void AccessPointClass::enable(bool enabled, bool save) +{ +} + +bool AccessPointClass::isEnabled() +{ + return false; +} + +bool AccessPointClass::config(const String& ssid, String password, AUTH_MODE mode, bool hidden, int channel, + int beaconInterval) +{ + return false; +} + +IPAddress AccessPointClass::getIP() +{ + return IPADDR_NONE; +} + +IPAddress AccessPointClass::getNetworkBroadcast() +{ + return IPADDR_NONE; +} + +IPAddress AccessPointClass::getNetworkMask() +{ + return IPADDR_NONE; +} + +IPAddress AccessPointClass::getNetworkGateway() +{ + return IPADDR_NONE; +} + +bool AccessPointClass::setIP(IPAddress address) +{ + return false; +} + +String AccessPointClass::getMAC(char sep) +{ + return nullptr; +} + +String AccessPointClass::getSSID() +{ + return nullptr; +} + +String AccessPointClass::getPassword() +{ + return nullptr; +} + +void AccessPointClass::onSystemReady() +{ +} diff --git a/Sming/Arch/Host/Platform/RTC.cpp b/Sming/Arch/Host/Platform/RTC.cpp new file mode 100644 index 0000000000..3ad7eb7b60 --- /dev/null +++ b/Sming/Arch/Host/Platform/RTC.cpp @@ -0,0 +1,44 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * RTC.cpp + * + ****/ + +#include + +#include + +RtcClass RTC; + +RtcClass::RtcClass() +{ +} + +uint64_t RtcClass::getRtcNanoseconds() +{ + struct timeval tv; + gettimeofday(&tv, nullptr); + uint64_t usecs = (tv.tv_sec * 1000000ULL) + (uint32_t)tv.tv_usec; + return usecs * 1000; +} + +uint32_t RtcClass::getRtcSeconds() +{ + struct timeval tv; + gettimeofday(&tv, nullptr); + return tv.tv_sec; +} + +bool RtcClass::setRtcNanoseconds(uint64_t nanoseconds) +{ + return false; +} + +bool RtcClass::setRtcSeconds(uint32_t seconds) +{ + return false; +} diff --git a/Sming/Arch/Host/Platform/Station.cpp b/Sming/Arch/Host/Platform/Station.cpp new file mode 100644 index 0000000000..bd3fde4e5c --- /dev/null +++ b/Sming/Arch/Host/Platform/Station.cpp @@ -0,0 +1,251 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Station.cpp + * + ****/ + +#include "Platform/Station.h" +#include "Data/HexString.h" + +StationClass WifiStation; + +void StationClass::enable(bool enabled, bool save) +{ +} + +bool StationClass::isEnabled() +{ + return true; +} + +bool StationClass::config(const String& ssid, const String& password, bool autoConnectOnStartup, bool save) +{ + return true; +} + +bool StationClass::connect() +{ + return true; +} + +bool StationClass::disconnect() +{ + return true; +} + +bool StationClass::isConnected() +{ + return true; +} + +bool StationClass::isConnectionFailed() +{ + return false; +} + +bool StationClass::isEnabledDHCP() +{ + return true; +} + +void StationClass::enableDHCP(bool enable) +{ +} + +void StationClass::setHostname(const String& hostname) +{ +} + +String StationClass::getHostname() +{ + return nullptr; +} + +IPAddress StationClass::getIP() +{ + struct ip_info info = {0}; + wifi_get_ip_info(STATION_IF, &info); + return info.ip; +} + +String StationClass::getMAC(char sep) +{ + uint8 hwaddr[6]; + if(wifi_get_macaddr(STATION_IF, hwaddr)) { + return makeHexString(hwaddr, sizeof(hwaddr), sep); + } else { + return nullptr; + } +} + +IPAddress StationClass::getNetworkBroadcast() +{ + struct ip_info info = {0}; + wifi_get_ip_info(STATION_IF, &info); + return (info.ip.addr | ~info.netmask.addr); +} + +IPAddress StationClass::getNetworkMask() +{ + struct ip_info info = {0}; + wifi_get_ip_info(STATION_IF, &info); + return info.netmask; +} + +IPAddress StationClass::getNetworkGateway() +{ + struct ip_info info = {0}; + wifi_get_ip_info(STATION_IF, &info); + return info.gw; +} + +bool StationClass::setIP(IPAddress address) +{ + return false; +} + +bool StationClass::setIP(IPAddress address, IPAddress netmask, IPAddress gateway) +{ + return false; +} + +String StationClass::getSSID() +{ + return nullptr; +} + +int8_t StationClass::getRssi() +{ + return -120; +} + +uint8_t StationClass::getChannel() +{ + return 0; +} + +String StationClass::getPassword() +{ + return nullptr; +} + +EStationConnectionStatus StationClass::getConnectionStatus() +{ + return eSCS_GotIP; +} + +bool StationClass::startScan(ScanCompletedDelegate scanCompleted) +{ + scanCompletedCallback = scanCompleted; + if(!scanCompleted) { + return false; + } + + host_queue_callback( + [](uint32_t param) { + auto self = reinterpret_cast(param); + BssList list; + BssInfo info(nullptr); + info.ssid = "Dummy SSID"; + info.channel = 1; + info.rssi = -50; + info.hidden = false; + info.authorization = AUTH_OPEN; + wifi_get_macaddr(STATION_IF, info.bssid); + list.add(info); + self->scanCompletedCallback(true, list); + }, + uint32_t(this)); + + return true; +} + +void StationClass::onSystemReady() +{ +} + +const char* StationClass::getConnectionStatusName() +{ + switch(getConnectionStatus()) { + case eSCS_Idle: + return "Idle"; + case eSCS_Connecting: + return "Connecting"; + case eSCS_WrongPassword: + return "Wrong password"; + case eSCS_AccessPointNotFound: + return "Access point not found"; + case eSCS_ConnectionFailed: + return "Connection failed"; + case eSCS_GotIP: + return "Successful connected"; + default: + SYSTEM_ERROR("Unknown status: %d", getConnectionStatus()); + return ""; + }; +} + +void StationClass::smartConfigStart(SmartConfigType sctype, SmartConfigDelegate callback) +{ +} + +void StationClass::smartConfigStop() +{ +} + +#ifdef ENABLE_WPS +void StationClass::internalWpsConfig(wps_cb_status status) +{ +} + +bool StationClass::wpsConfigStart(WPSConfigDelegate callback) +{ + return false; +} + +bool StationClass::beginWPSConfig() +{ + debugf("StationClass::beginWPSConfig()\n"); + return (wpsConfigStart()); +} + +void StationClass::wpsConfigStop() +{ +} +#endif + +//////////// + +BssInfo::BssInfo(bss_info* info) +{ +} + +const char* BssInfo::getAuthorizationMethodName() +{ + switch(authorization) { + case AUTH_OPEN: + return "OPEN"; + case AUTH_WEP: + return "WEP"; + case AUTH_WPA_PSK: + return "WPA_PSK"; + case AUTH_WPA2_PSK: + return "WPA2_PSK"; + case AUTH_WPA_WPA2_PSK: + return "WPA_WPA2_PSK"; + default: + SYSTEM_ERROR("Unknown auth: %d", authorization); + return ""; + } +} + +uint32_t BssInfo::getHashId() +{ + uint32_t a = bssid[4] | (bssid[5] << 8); + uint32_t b = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24); + return a ^ b; +} diff --git a/Sming/Arch/Host/Platform/WifiEvents.cpp b/Sming/Arch/Host/Platform/WifiEvents.cpp new file mode 100644 index 0000000000..95f525b317 --- /dev/null +++ b/Sming/Arch/Host/Platform/WifiEvents.cpp @@ -0,0 +1,86 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * WifiEvents.cpp + * + */ + +#include +#include "Platform/WifiEvents.h" +#include +#include + +WifiEventsClass WifiEvents; + +void WifiEventHandler(System_Event_t* evt); + +WifiEventsClass::WifiEventsClass() +{ + wifi_set_event_handler_cb([](System_Event_t* evt) { WifiEvents.WifiEventHandler(evt); }); +} + +static String macToStr(const uint8_t mac[]) +{ + return makeHexString(mac, 6, ':'); +} + +void WifiEventsClass::WifiEventHandler(System_Event_t* evt) +{ + switch(evt->event) { + case EVENT_STAMODE_CONNECTED: + debugf("connect to ssid %s, channel %d", evt->event_info.connected.ssid, evt->event_info.connected.channel); + if(onSTAConnect) { + onSTAConnect((const char*)evt->event_info.connected.ssid, evt->event_info.connected.ssid_len, + evt->event_info.connected.bssid, evt->event_info.connected.channel); + } + break; + case EVENT_STAMODE_DISCONNECTED: + debugf("disconnect from ssid %s, reason %d", evt->event_info.disconnected.ssid, + evt->event_info.disconnected.reason); + if(onSTADisconnect) { + onSTADisconnect((const char*)evt->event_info.disconnected.ssid, evt->event_info.disconnected.ssid_len, + evt->event_info.disconnected.bssid, evt->event_info.disconnected.reason); + } + break; + case EVENT_STAMODE_AUTHMODE_CHANGE: + debugf("mode: %d -> %d", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); + if(onSTAAuthModeChange) { + onSTAAuthModeChange(evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); + } + break; + case EVENT_STAMODE_GOT_IP: { + IPAddress ip(evt->event_info.got_ip.ip); + IPAddress mask(evt->event_info.got_ip.mask); + IPAddress gw(evt->event_info.got_ip.gw); + debugf("ip: %s, mask: %s, gw: %s", ip.toString().c_str(), mask.toString().c_str(), gw.toString().c_str()); + if(onSTAGotIP) { + onSTAGotIP(ip, mask, gw); + } + break; + } + case EVENT_SOFTAPMODE_STACONNECTED: + debugf("station: %s join, AID = %d", macToStr(evt->event_info.sta_connected.mac).c_str(), + evt->event_info.sta_connected.aid); + if(onSOFTAPConnect) { + onSOFTAPConnect(evt->event_info.sta_connected.mac, evt->event_info.sta_connected.aid); + } + break; + case EVENT_SOFTAPMODE_STADISCONNECTED: + debugf("station: %s leave, AID = %d", macToStr(evt->event_info.sta_disconnected.mac), + evt->event_info.sta_disconnected.aid); + if(onSOFTAPDisconnect) { + onSOFTAPDisconnect(evt->event_info.sta_disconnected.mac, evt->event_info.sta_disconnected.aid); + } + break; + case EVENT_SOFTAPMODE_PROBEREQRECVED: + if(onSOFTAPProbeReqRecved) { + onSOFTAPProbeReqRecved(evt->event_info.ap_probereqrecved.rssi, evt->event_info.ap_probereqrecved.mac); + } + break; + default: + break; + } +} diff --git a/Sming/Arch/Host/System/include/user_config.h b/Sming/Arch/Host/System/include/user_config.h new file mode 100644 index 0000000000..8fe7d69770 --- /dev/null +++ b/Sming/Arch/Host/System/include/user_config.h @@ -0,0 +1,20 @@ +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +// UART config +#define SERIAL_BAUD_RATE COM_SPEED_SERIAL + +#include + +// Extended string conversion for compatibility +#include + +// Network base API +#include +#include +#include +#include +#include +#include + +#endif /* __USER_CONFIG_H__ */ diff --git a/Sming/Arch/Host/app.mk b/Sming/Arch/Host/app.mk new file mode 100644 index 0000000000..5a85adb981 --- /dev/null +++ b/Sming/Arch/Host/app.mk @@ -0,0 +1,195 @@ +### +# +# SMING Application Makefile for Host (Win32/Linux) platform +# +### + +##@Building + +.PHONY: all +all: libsming checkdirs app ##(default) Build application + +# +CONFIG_VARS += RBOOT_SPIFFS_0 RBOOT_SPIFFS_1 +RBOOT_SPIFFS_0 ?= 0x100000 +RBOOT_SPIFFS_1 ?= 0x300000 + +# Code compiled with application +APPCODE := + +# Where to look for libraries +LIBDIRS := $(USER_LIBDIR) $(BUILD_BASE) $(ARCH_BASE)/Compiler/ld + +# Eventually this will go, but for now we use some Esp8266 code +ESP8266_COMPONENTS := $(SMING_HOME)/Arch/Esp8266/Components + +EXTRA_INCDIR += $(ARCH_COMPONENTS)/esp_hal/include $(ESP8266_COMPONENTS)/esp8266/include \ + $(ARCH_COMPONENTS)/driver/include $(ESP8266_COMPONENTS)/driver/include \ + $(ARCH_COMPONENTS)/spi_flash/include $(ESP8266_COMPONENTS)/spi_flash/include \ + $(ARCH_COMPONENTS)/libc/include \ + $(ARCH_COMPONENTS)/heap/include \ + $(ARCH_COMPONENTS)/esp_wifi/include + +# Macro to make an optional library +# $1 -> The library to make +# $2 -> List of options to add to make command line +define MakeLibrary + $(Q) $(MAKE) -C $(SMING_HOME) $(patsubst $(SMING_HOME)/%,%,$1) $2 +endef + +# => SPIFFS +CONFIG_VARS += DISABLE_SPIFFS SPIFF_BIN_OUT +DISABLE_SPIFFS ?= 0 +SPIFF_BIN_OUT ?= spiff_rom +SPIFF_BIN_OUT := $(FW_BASE)/$(SPIFF_BIN_OUT).bin +EXTRA_INCDIR += $(ESP8266_COMPONENTS)/spiffs $(COMPONENTS)/spiffs/src +CFLAGS += -DRBOOT_SPIFFS_0=$(RBOOT_SPIFFS_0) +CFLAGS += -DRBOOT_SPIFFS_1=$(RBOOT_SPIFFS_1) +CFLAGS += -D__WORDSIZE=32 # spiffy_host.h +CUSTOM_TARGETS += $(SPIFF_BIN_OUT) +APPCODE += $(ESP8266_COMPONENTS)/rboot/appcode + +# => LWIP +LWIP_BASE := $(ARCH_COMPONENTS)/lwip +LIBS += lwip +EXTRA_INCDIR += $(LWIP_BASE) $(LWIP_BASE)/lwip/src/include +ifeq ($(UNAME),Windows) +EXTRA_INCDIR += $(LWIP_BASE)/lwip/contrib/ports/win32/include +else +EXTRA_INCDIR += $(LWIP_BASE)/lwip/contrib/ports/unix/port/include +endif + +# => WPS +CONFIG_VARS += ENABLE_WPS +ifeq ($(ENABLE_WPS),1) + CFLAGS += -DENABLE_WPS=1 + LIBS += wps +endif + +# +LIBS := $(LIBSMING) $(EXTRA_LIBS) $(LIBS) pthread + +ifeq ($(UNAME),Windows) +LIBS += wsock32 +endif + +# linker flags used to generate the main object file +LDFLAGS = -m32 -Wl,--gc-sections -Wl,-Map=$(basename $@).map + +include $(ARCH_BASE)/flash.mk + +# Executable +TARGET_OUT_0 := $(FW_BASE)/$(TARGET)$(TOOL_EXT) + +# Command-line options passed to executable +CONFIG_VARS += SMING_TARGET_OPTIONS +SMING_TARGET_OPTIONS ?= --flashfile=$(FLASH_BIN) --uart=0 --uart=1 --pause=5 +SMING_TARGET_OPTIONS += --flashsize=$(SPI_SIZE) + +# Full GDB command line +GDB := trap '' INT; $(GDB) -x $(ARCH_COMPONENTS)/gdbstub/gdbcmds --args $(TARGET_OUT_0) $(SMING_TARGET_OPTIONS) + +############# +# +# Target definitions +# +############# + +include $(SMING_HOME)/modules.mk + +# Add APPCODE objects and targets +$(call ScanModules,$(APPCODE)) + +.PHONY: app +app: $(CUSTOM_TARGETS) $(TARGET_OUT_0) + +$(TARGET_OUT_0): $(APP_AR) + $(vecho) "LD $@" + $(Q) $(LD) $(addprefix -L,$(LIBDIRS)) $(LDFLAGS) -Wl,--start-group $(APP_AR) $(addprefix -l,$(LIBS)) -Wl,--end-group -o $@ + + $(Q) $(MEMANALYZER) $@ > $(FW_MEMINFO_NEW) + + $(Q) cat $(FW_MEMINFO_NEW) + +# recreate it from 0, since you get into problems with same filenames +$(APP_AR): $(OBJ) + $(vecho) "AR $@" + $(Q) test ! -f $@ || rm $@ + $(Q) $(AR) rcsP $@ $^ + +.PHONY: libsming +libsming: $(LIBSMING_DST) ##Build the Sming framework and user libraries +$(LIBSMING_DST): + $(vecho) "(Re)compiling Sming. Enabled features: $(SMING_FEATURES). This may take some time" + $(Q) $(MAKE) -C $(SMING_HOME) clean V=$(V) ENABLE_SSL=$(ENABLE_SSL) + $(Q) $(MAKE) -C $(SMING_HOME) V=$(V) ENABLE_SSL=$(ENABLE_SSL) + +.PHONY: rebuild +rebuild: clean all ##Re-build your application + + +.PHONY: checkdirs +checkdirs: | $(BUILD_DIR) $(FW_BASE) + +$(BUILD_DIR) $(FW_BASE): + $(Q) mkdir -p $@ + +.PHONY: spiff_update +spiff_update: spiff_clean $(SPIFF_BIN_OUT) ##Rebuild the SPIFFS filesystem image + +##@Cleaning + +.PHONY: spiff_clean +spiff_clean: ##Remove SPIFFS image file + $(vecho) "Cleaning $(SPIFF_BIN_OUT)" + $(Q) rm -rf $(SPIFF_BIN_OUT) + +# Generating spiffs_bin +$(SPIFF_BIN_OUT): +ifeq ($(DISABLE_SPIFFS), 1) + $(vecho) "(!) Spiffs support disabled. Remove 'DISABLE_SPIFFS' make argument to enable spiffs." +else + $(vecho) "Checking for spiffs files" + $(Q) if [ -d "$(SPIFF_FILES)" ]; then \ + echo "$(SPIFF_FILES) directory exists. Creating $(SPIFF_BIN_OUT)"; \ + $(SPIFFY) $(SPIFF_SIZE) $(SPIFF_FILES) $(SPIFF_BIN_OUT); \ + else \ + echo "No files found in ./$(SPIFF_FILES)."; \ + echo "Creating empty $(SPIFF_BIN_OUT)"; \ + $(SPIFFY) $(SPIFF_SIZE) dummy.dir $(SPIFF_BIN_OUT); \ + fi +endif + + +##@Flashing + +.PHONY: run +run: all ##Run the application image + $(TARGET_OUT_0) $(SMING_TARGET_OPTIONS) + +.PHONY: flashfs +flashfs: libsming $(SPIFF_BIN_OUT) ##Write just the SPIFFS filesystem image +ifeq ($(DISABLE_SPIFFS), 1) + $(vecho) "SPIFFS are not enabled!" +else + $(call WriteFlashChunk,$(RBOOT_SPIFFS_0),$(SPIFF_BIN_OUT)) +endif + +.PHONY: flash +flash: all flashfs ##Write the SPIFFS filesystem image then run the application +ifeq ($(ENABLE_GDB), 1) + $(GDB) +else + $(TARGET_OUT_0) $(SMING_TARGET_OPTIONS) +endif + +.PHONY: flashinit +flashinit: ##Erase all flash memory + $(vecho) "Erase flash (creates default flash backing file)" + $(ERASE_FLASH) + +# Remove build artifacts +.PHONY: clean +clean: + $(Q) rm -rf $(BUILD_BASE) + $(Q) rm -rf $(FW_BASE) diff --git a/Sming/Arch/Host/build.mk b/Sming/Arch/Host/build.mk new file mode 100644 index 0000000000..485ad8e46c --- /dev/null +++ b/Sming/Arch/Host/build.mk @@ -0,0 +1,33 @@ +############## +# +# Host Platform build environment +# +############## + +CFLAGS += -DARCH_HOST + +TOOLSPEC := + +AS := $(TOOLSPEC)gcc +CC := $(TOOLSPEC)gcc +CXX := $(TOOLSPEC)g++ +AR := $(TOOLSPEC)ar +LD := $(TOOLSPEC)g++ +OBJCOPY := $(TOOLSPEC)objcopy +OBJDUMP := $(TOOLSPEC)objdump +GDB := $(TOOLSPEC)gdb + +CFLAGS += -m32 -Wno-deprecated-declarations + +# Keep Windows/Linux object files separate to avoid conflict +BUILD_BASE := $(BUILD_BASE)/$(UNAME) +USER_LIBDIR = $(ARCH_BASE)/Compiler/lib/$(UNAME) + +# => Tools +SPIFFY = $(ARCH_BASE)/../Esp8266/Tools/spiffy/spiffy$(TOOL_EXT) +MEMANALYZER = size + +Terminal = start telnet localhost $$((10000 + $1)) + +TERMINAL = $(call Terminal,$(COM_PORT)) +KILL_TERM := diff --git a/Sming/Arch/Host/flash.mk b/Sming/Arch/Host/flash.mk new file mode 100644 index 0000000000..a5a1a54695 --- /dev/null +++ b/Sming/Arch/Host/flash.mk @@ -0,0 +1,41 @@ +# +# Flash parameters +# + +# SPI_SIZE: 512K, 256K, 1M, 2M, 4M +SPI_SIZE ?= 512K + +ifeq ($(SPI_SIZE), 256K) + SPIFF_SIZE ?= 131072 #128K +else ifeq ($(SPI_SIZE), 1M) + SPIFF_SIZE ?= 524288 #512K +else ifeq ($(SPI_SIZE), 2M) + SPIFF_SIZE ?= 524288 #512K +else ifeq ($(SPI_SIZE), 4M) + SPIFF_SIZE ?= 524288 #512K +else + SPIFF_SIZE ?= 196608 #192K +endif + +CFLAGS += -DSPIFF_SIZE=$(SPIFF_SIZE) + + +# Use DD to update $(FW_BASE)/flash.bin + +DD := dd + +FLASH_BIN := flash.bin + +# Write data to flash +# $1 -> Start offset +# $2 -> File containing data to write +define WriteFlashChunk + $(info WriteFlash $1 -> $2) + $(Q) if [ ! -f $(FLASH_BIN) ]; then \ + $(ERASE_FLASH); \ + fi + $(Q) $(DD) if=$2 of=$(FLASH_BIN) obs=1 seek=$$(($1)) conv=notrunc +endef + +# +ERASE_FLASH := $(DD) if=/dev/zero ibs=1 count=$(SPI_SIZE) | tr "\000" "\377" > $(FLASH_BIN) diff --git a/Sming/Arch/Host/readme.md b/Sming/Arch/Host/readme.md new file mode 100644 index 0000000000..55eddd3931 --- /dev/null +++ b/Sming/Arch/Host/readme.md @@ -0,0 +1,158 @@ +# Sming Host Emulator + +## Summary + +Allows Sming applications to be built as an executable to run on the development host (Windows or Linux). + +This is a source-level emulator for developing and testing new framework code prior to flashing a real device. + +This is not a machine emulator; if you need something operating at a lower level take a look at [QEMU](https://www.qemu.org/). + +## Requirements + +`CMake` is required to build LWIP + +Ensure you are using relatively recent compilers, with 32-bit libraries available. + +For Linux, you may require the `gcc-multilib` and `g++-multilib` packages to build 32-bit executables on a 64-bit OS. + +For Windows, make sure your `MinGW` distro is up to date. If you run `gcc --version` you should get `gcc (MinGW.org GCC-6.3.0-1) 6.3.0` or later. If it's older, execute these commands: + +``` +mingw-get update +mingw-get upgrade +``` + +## Building + +Build the framework and application as usual, specifying `SMING_ARCH=Host`. For example: + +``` +cd $SMING_HOME +make SMING_ARCH=Host +cd $SMING_HOME/../samples/Basic_Serial +make SMING_ARCH=Host +``` + +This builds the application as an executable in `out/firmware/app`. +Various command-line options are supported, use `--help` for details. + +Use `make run` to execute the application. Command-line parameters are passed in `SMING_TARGET_OPTIONS` so you can customise this via environment or application makefile thus: + +`export SMING_TARGET_OPTIONS="--pause --uart=0"` + +To find out what options are in force, use `make list-config`. + +## Features + +### Flash memory + +This is emulated using a backing file. By default, it's in `flash.bin` in the current directory. + +Use `make flashinit` to clear and reset the file. +Use `make flashfs` to copy the generated SPIFFS image into the backing file. `make flash` does the same then runs the application. +Use `make flash` to do a `flashfs` then a `run` + +### UART (serial) ports + +Multiple serial terminals are supported via raw TCP network sockets. + +For example, start the `Basic_Serial` sample application we build above, with support for both UARTs using the following options: + +`out/firmware/app --pause --uart=0 --uart=1` + +Note: if you don't specify the `pause` option then the Sming application will start running immediately and any serial output will be discarded. + +In separate command windows, start two telnet sessions (a terminal for each serial port): + +``` +telnet localhost 10000 +telnet localhost 10001 +``` + +In the application window, press Enter. + +Note: For Windows users, `putty` is generally a better choice. For example, you can configure it to implicitly perform carriage-return for linefeed (i.e. "\n" -> "\r\n"). Run using: + +``` +putty telnet://localhost:10000 +``` + +Port numbers are allocated sequentially from 10000. If you want to use different port numbers, use `--uartport` option. + +### Digital I/O + +At present the emulator just writes output to the console. Inputs all return 0. + +### Network + +#### Linux + +Support is provided via TAP network interface (a virtual network layer operating at the ethernet frame level). A TAP interface must be created first, and requires root priviledge: + +``` +sudo ip tuntap add dev tap0 mode tap user `whoami` +sudo ip a a dev tap0 192.168.13.1/24 +sudo ifconfig tap0 up +``` + +This creates the `tap0` interface, and is persistent across OS reboots. The emulator will automatically select the first `tap` interface found. To override this, use the `--ifname` option. An IP address will be assigned, but can be changed using the `--ipaddr` option. + +#### Windows + +Requires [NPCAP](https://nmap.org/npcap/) library to be installed. Provided with current (3.0.2) version of [Wireshark](https://www.wireshark.org/download.html). + +By default, the first valid network adapter will be used, with address assigned via DHCP. + +If the adapter is wrong, get a list thus: + + out\firmware\app --ifname=? + + ... + + Available adapters: + - 0: {ACC6BFB2-A15B-4CF8-B93A-8D97644D0AAC} - Oracle + 192.168.56.1 / 255.255.255.0 + - 1: {A12D4DD0-0EA8-435D-985E-A1F96F781EF0} - NdisWan Adapter + - 2: {3D66A354-39DD-4C6A-B9C4-14EE223FC3D1} - MS NDIS 6.0 LoopBack Driver + 0.0.0.0 / 255.0.0.0 + - 3: {BC53D919-339E-4D70-8573-9D7A8AE303C7} - NdisWan Adapter + - 4: {3CFD43EA-9CC7-44A7-83D4-EB04DD029FE7} - NdisWan Adapter + - 5: {530640FF-A9C3-436B-9EA2-65102C788119} - Realtek PCIe GBE Family Controller + 192.168.1.70 / 255.255.255.0 + - 6: {0F649280-BAC2-4515-9CE3-F7DFBB6A1BF8} - Kaspersky Security Data Escort Adapter + 10.102.37.150 / 255.255.255.252 + +Then use the appropriate number: + + out\firmware\app --ifname=5 + +You can also specify by GUID, or a part of it: + + out\firmware\app --ifname={530640FF + +The network adapter may be autodetected from a provided ip address, but you must also give the network gateway must also be provided. For example: + + out\firmware\app --ipaddr=192.168.1.10 --gateway=192.168.1.254 + +You can find gateway addresses using the `ipconfig` command. + +We can then run using + +`out/firmware/app --ifname=4 --gateway=192.168.1.254 --ipaddr=192.168.1.10` + +To use these settings for a `make run`, do this: + +`set SMING_TARGET_OPTIONS="--ifname=4 --gateway=192.168.1.254 --ipaddr=192.168.1.10"` + +## todo + +Add passthrough support for real serial ports to permit connection of physical devices. + +Consider how this mechanism might be used to support emulation of other devices (SPI, I2C, etc). + +Development platforms with SPI or I2C (e.g. Raspberry Pi) could be supported. + +Are there any generic device emulators available? For example, to simulate specific types of SPI slave. + +All code is intended to run on either Windows (MinGW) or Linux as simply as possible, without requiring any additional dependencies. If things get more complicated then we might need to consider using external libraries, such as Boost. diff --git a/Sming/Arch/Host/sming.mk b/Sming/Arch/Host/sming.mk new file mode 100644 index 0000000000..e9fd83d4ce --- /dev/null +++ b/Sming/Arch/Host/sming.mk @@ -0,0 +1,94 @@ +# Makefile to build Sming framework under Host (Win32/Linux) environment + +EXCLUDE_LIBRARIES := Adafruit_ILI9341 Adafruit_NeoPixel Adafruit_PCD8544 Adafruit_SSD1306 \ + ArduCAM CapacitiveSensor IR MCP23S17 RF24 SDCard TFT_ILI9163C WS2812 + +ESP8266_COMPONENTS := Arch/Esp8266/Components + +# +MODULES += $(ARCH_COMPONENTS)/esp_hal +EXTRA_INCDIR += $(ARCH_COMPONENTS)/esp_hal/include $(ESP8266_COMPONENTS)/esp8266/include + +# +MODULES += $(ARCH_COMPONENTS)/driver +EXTRA_INCDIR += $(ARCH_COMPONENTS)/driver/include $(ESP8266_COMPONENTS)/driver/include + +# +MODULES += $(ARCH_COMPONENTS)/libc +MODULES += $(ARCH_COMPONENTS)/hostlib + +# +EXTRA_INCDIR += $(ARCH_COMPONENTS)/spi_flash/include $(ESP8266_COMPONENTS)/spi_flash/include + +# +MODULES += $(ARCH_COMPONENTS)/heap +EXTRA_INCDIR += $(ARCH_COMPONENTS)/heap/include + +# +MODULES += $(ARCH_COMPONENTS)/gdbstub + +# +MODULES += $(ARCH_COMPONENTS)/esp_wifi +EXTRA_INCDIR += $(ARCH_COMPONENTS)/esp_wifi/include + +# => LWIP +ENABLE_CUSTOM_LWIP ?= 2 +ifeq ($(ENABLE_CUSTOM_LWIP), 2) + LWIP_BASE := $(ARCH_COMPONENTS)/lwip + SUBMODULES += $(LWIP_BASE)/lwip + EXTRA_INCDIR += $(LWIP_BASE) $(LWIP_BASE)/lwip/src/include + LIBLWIP := lwip + LIBS += $(LIBLWIP) + ENABLE_LWIPDEBUG ?= 0 + ifeq ($(ENABLE_LWIPDEBUG), 1) + CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=Debug + else + CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=Release + endif + LWIP_BUILD_DIR := $(BUILD_BASE)/$(LWIP_BASE) + + ifeq ($(UNAME),Windows) + EXTRA_INCDIR += $(LWIP_BASE)/lwip/contrib/ports/win32/include + CMAKE_OPTIONS += -G "MSYS Makefiles" + else + EXTRA_INCDIR += $(LWIP_BASE)/lwip/contrib/ports/unix/port/include + endif + + CLEAN += lwip-clean + +$(call UserLibPath,lwip): $(LWIP_BUILD_DIR)/Makefile + $(vecho) "Building $(notdir $@)..." + $(Q) $(MAKE) -C $(LWIP_BUILD_DIR) + +$(LWIP_BUILD_DIR)/Makefile: $(LWIP_BASE)/lwip/.submodule | $(LWIP_BUILD_DIR) + $(Q) cd $(LWIP_BUILD_DIR); \ + $(CMAKE) -DUSER_LIBDIR="$(SMING_HOME)/$(USER_LIBDIR)" $(CMAKE_OPTIONS) $(SMING_HOME$)/$(LWIP_BASE)/$(UNAME) + +$(LWIP_BUILD_DIR): + mkdir -p $@ + +.PHONY: lwip-clean +lwip-clean: + -$(Q) rm -rf $(LWIP_BUILD_DIR) +endif + +# +SPIFFS_SMING := $(ESP8266_COMPONENTS)/spiffs +SPIFFS_BASE := $(COMPONENTS)/spiffs +SUBMODULES += $(SPIFFS_BASE) +MODULES += $(SPIFFS_SMING) $(SPIFFS_BASE)/src +CFLAGS += -D__WORDSIZE=32 # spiffy_host.h +EXTRA_INCDIR += $(SPIFFS_SMING) $(SPIFFS_BASE)/src +TOOLS += $(SPIFFY) +TOOLS_CLEAN += tools-clean-esp8266 + +$(SPIFFY): + $(MAKE) SMING_ARCH=Esp8266 tools + +.PHONY: tools-clean-esp8266 +tools-clean-esp8266: + $(MAKE) SMING_ARCH=Esp8266 tools-clean + + +# Not all libraries will compile (yet) +SMING_LIBRARIES := ArduinoJson diff --git a/Sming/Core/Network/Http/HttpConnection.cpp b/Sming/Core/Network/Http/HttpConnection.cpp index 9e76ba4ea5..5024536d75 100644 --- a/Sming/Core/Network/Http/HttpConnection.cpp +++ b/Sming/Core/Network/Http/HttpConnection.cpp @@ -12,10 +12,10 @@ #include "HttpConnection.h" -#ifdef __linux__ -#include "lwip/priv/tcp_priv.h" -#else +#ifdef __ets__ #include "lwip/tcp_impl.h" +#else +#include "lwip/priv/tcp_priv.h" #endif /** @brief http_parser function table diff --git a/Sming/Core/Network/NetUtils.cpp b/Sming/Core/Network/NetUtils.cpp index b30caffcc3..9139d59a84 100644 --- a/Sming/Core/Network/NetUtils.cpp +++ b/Sming/Core/Network/NetUtils.cpp @@ -12,10 +12,10 @@ #include "Data/CStringArray.h" #include "WString.h" -#ifdef __linux__ -#include "lwip/priv/tcp_priv.h" -#else +#ifdef __ets__ #include "lwip/tcp_impl.h" +#else +#include "lwip/priv/tcp_priv.h" #endif #ifdef FIX_NETWORK_ROUTING diff --git a/Sming/Core/SmingCore.h b/Sming/Core/SmingCore.h index 28099da8a6..3fbc216c99 100644 --- a/Sming/Core/SmingCore.h +++ b/Sming/Core/SmingCore.h @@ -50,9 +50,12 @@ #include "Network/TcpClient.h" #include "Network/TcpConnection.h" #include "Network/UdpConnection.h" -#include "Network/rBootHttpUpdate.h" #include "Network/Url.h" +#ifdef ARCH_ESP8266 +#include "Network/rBootHttpUpdate.h" +#endif + #include "Data/Stream/JsonObjectStream.h" #include "Data/Stream/FileStream.h" #include "Data/Stream/TemplateFileStream.h" diff --git a/Sming/System/include/gdb/gdb_hooks.h b/Sming/System/include/gdb/gdb_hooks.h index d2aa282e95..259f60e5ae 100644 --- a/Sming/System/include/gdb/gdb_hooks.h +++ b/Sming/System/include/gdb/gdb_hooks.h @@ -53,7 +53,11 @@ void gdb_enable(bool state); * @brief Break into GDB, if present */ #ifdef ENABLE_GDB +#ifdef ARCH_HOST +#define gdb_do_break() __asm__("int $0x03") +#else #define gdb_do_break() __asm__("break 0,0") +#endif #else #define gdb_do_break() \ do { \ diff --git a/Sming/System/include/stringutil.h b/Sming/System/include/stringutil.h index a30b7831b1..b5645ba13b 100644 --- a/Sming/System/include/stringutil.h +++ b/Sming/System/include/stringutil.h @@ -28,6 +28,7 @@ extern "C" { */ const char* strstri(const char* pString, const char* pToken); +#ifndef _GNU_SOURCE /** @brief A case-insensitive @code{strcmp}. @note non-ANSI GNU C library extension */ @@ -38,6 +39,7 @@ int strcasecmp(const char* s1, const char* s2); @note non-ANSI GNU C library extension */ void* memmem(const void* haystack, size_t haystacklen, const void* needle, size_t needlelen); +#endif static inline signed char hexchar(unsigned char c) { diff --git a/Sming/Wiring/IPAddress.h b/Sming/Wiring/IPAddress.h index 9ae48d5135..108a38dc19 100644 --- a/Sming/Wiring/IPAddress.h +++ b/Sming/Wiring/IPAddress.h @@ -58,11 +58,11 @@ class IPAddress : public Printable IPAddress(ip_addr address) { - this->address = address; + this->address.addr = address.addr; } #if LWIP_VERSION_MAJOR == 2 - IPAddress(ip_addr_t address); + IPAddress(ip_addr_t address) { this->address = address; } @@ -81,8 +81,8 @@ class IPAddress : public Printable // Overloaded cast operator to allow IPAddress objects to be used where a pointer // to a four-byte uint8_t array is expected operator uint32_t() const { return address.addr; } - operator ip_addr() const { return address; } - operator ip_addr*() { return &address; } + operator ip_addr() const { return {address.addr}; } + operator ip_addr*() { return reinterpret_cast(&address); } #if LWIP_VERSION_MAJOR == 2 operator ip_addr_t*() { return &address; } diff --git a/Sming/build.mk b/Sming/build.mk index fbb6f68012..f5e7c890cb 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -73,6 +73,8 @@ endif export SMING_HOME export COMPILE := gcc +CONFIG_VARS += ARCH_BASE USER_LIBDIR BUILD_BASE FW_BASE + ARCH_BASE := Arch/$(SMING_ARCH) ARCH_SYS = $(ARCH_BASE)/System ARCH_CORE = $(ARCH_BASE)/Core @@ -87,6 +89,9 @@ FW_BASE := out/firmware # Git command GIT ?= git +# CMake command +CMAKE ?= cmake + ### Debug output parameters # By default `debugf` does not print file name and line number. If you want this enabled set the directive below to 1 CONFIG_VARS += DEBUG_PRINT_FILENAME_AND_LINE @@ -143,7 +148,7 @@ CFLAGS += $(USER_CFLAGS) CONFIG_VARS += SMING_RELEASE CFLAGS += -DCUST_FILE_BASE=$$* -DDEBUG_VERBOSE_LEVEL=$(DEBUG_VERBOSE_LEVEL) -DDEBUG_PRINT_FILENAME_AND_LINE=$(DEBUG_PRINT_FILENAME_AND_LINE) -CXXFLAGS = $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11 -felide-constructors +CXXFLAGS = $(CFLAGS) -std=c++11 -felide-constructors ifneq ($(STRICT),1) CXXFLAGS += -Wno-reorder endif diff --git a/samples/HostTests/Makefile-user.mk b/samples/HostTests/Makefile-user.mk new file mode 100644 index 0000000000..d3ea297781 --- /dev/null +++ b/samples/HostTests/Makefile-user.mk @@ -0,0 +1,41 @@ +## Local build configuration +## Parameters configured here will override default and ENV values. +## Uncomment and change examples: + +## Add your source directories here separated by space +# MODULES = app +# EXTRA_INCDIR = include + +## ESP_HOME sets the path where ESP tools and SDK are located. +## Windows: +# ESP_HOME = c:/Espressif + +## MacOS / Linux: +# ESP_HOME = /opt/esp-open-sdk + +## SMING_HOME sets the path where Sming framework is located. +## Windows: +# SMING_HOME = c:/tools/sming/Sming + +## MacOS / Linux +# SMING_HOME = /opt/sming/Sming + +## COM port parameter is reqruied to flash firmware correctly. +## Windows: +# COM_PORT = COM3 + +## MacOS / Linux: +# COM_PORT = /dev/tty.usbserial + +## Com port speed +# COM_SPEED = 115200 + +## Configure flash parameters (for ESP12-E and other new boards): +# SPI_MODE = dio + +## SPIFFS options +DISABLE_SPIFFS = 1 +# SPIFF_FILES = files + +DEBUG_VERBOSE_LEVEL = 3 +SPI_SIZE = 4M diff --git a/samples/LiveDebug/app/application.cpp b/samples/LiveDebug/app/application.cpp index d967f70b1c..31a9e0407c 100644 --- a/samples/LiveDebug/app/application.cpp +++ b/samples/LiveDebug/app/application.cpp @@ -449,8 +449,10 @@ static void onOsMessage(OsMessage& msg) if(gdb_present() == eGDB_Attached) { gdb_do_break(); } else { +#ifdef ARCH_ESP8266 register uint32_t sp __asm__("a1"); debug_print_stack(sp + 0x10, 0x3fffffb0); +#endif } } } From b9c918f5bdb94c10a5ac2d5baf136470ccea5098 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Sat, 18 May 2019 17:33:04 +0100 Subject: [PATCH 07/19] Fix build conflicts * Replace `itoa` macro with fucntion definition * Rename `random()` in WMath.cpp (name conflict) * `#undef` conflicting structure member names in `gdb_syscall.h` * Fix implementation of sprintf_P() --- Sming/System/include/gdb/gdb_syscall.h | 5 +++++ Sming/System/include/stringconversion.h | 3 ++- Sming/System/stringconversion.cpp | 2 ++ Sming/Wiring/FakePgmSpace.h | 2 +- Sming/Wiring/WMath.cpp | 4 ++-- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Sming/System/include/gdb/gdb_syscall.h b/Sming/System/include/gdb/gdb_syscall.h index 4ee90ce0b7..9d87f9d500 100644 --- a/Sming/System/include/gdb/gdb_syscall.h +++ b/Sming/System/include/gdb/gdb_syscall.h @@ -39,6 +39,11 @@ #pragma pack(push, 4) +// When compiling under Linux, these get #defined and mess things up +#undef st_atime +#undef st_mtime +#undef st_ctime + /** * @brief GDB uses a specific version of the stat structure, 64 bytes in size */ diff --git a/Sming/System/include/stringconversion.h b/Sming/System/include/stringconversion.h index 3b27cea1dd..2b9a69c343 100644 --- a/Sming/System/include/stringconversion.h +++ b/Sming/System/include/stringconversion.h @@ -27,7 +27,8 @@ extern char* ultoa_wp(unsigned long val, char* buffer, unsigned int base, int wi extern char* ultoa_w(unsigned long val, char* buffer, unsigned int base, int width); extern char* ultoa(unsigned long val, char* buffer, unsigned int base); -#define itoa ltoa +extern char* itoa(int, char*, int); + extern char *dtostrf_p(double floatVar, int minStringWidthIncDecimalPoint, int numDigitsAfterDecimal, char *outputBuffer, char pad); extern char *dtostrf(double floatVar, int minStringWidthIncDecimalPoint, int numDigitsAfterDecimal, char *outputBuffer); long atol(const char *nptr); diff --git a/Sming/System/stringconversion.cpp b/Sming/System/stringconversion.cpp index b40dc380a3..2f99ef7efb 100644 --- a/Sming/System/stringconversion.cpp +++ b/Sming/System/stringconversion.cpp @@ -21,6 +21,8 @@ char* ltoa(long val, char* buffer, int base) return ltoa_w(val, buffer, base, 0); } +char* itoa (int, char*, int) __attribute__((alias("ltoa"))); + char* ltoa_w(long val, char* buffer, int base, int width) { return ltoa_wp(val, buffer, base, width, ' '); diff --git a/Sming/Wiring/FakePgmSpace.h b/Sming/Wiring/FakePgmSpace.h index b7a2d0f7df..6d75fc6305 100644 --- a/Sming/Wiring/FakePgmSpace.h +++ b/Sming/Wiring/FakePgmSpace.h @@ -191,7 +191,7 @@ extern "C" #define strcasecmp_P(a, b) strcasecmp((a), (b)) #define strcat_P(dest, src) strcat((dest), (src)) #define strstr_P(a, b) strstr((a), (b)) -#define sprintf_P(s, f, ...) m_sprintf((s), (f), ##__VA_ARGS__) +#define sprintf_P(s, f, ...) m_snprintf(s, 1024, f, ##__VA_ARGS__) #define printf_P(f, ...) m_printf((f), ##__VA_ARGS__) #endif /* ICACHE_FLASH */ diff --git a/Sming/Wiring/WMath.cpp b/Sming/Wiring/WMath.cpp index bef41bd102..d25b29aadf 100644 --- a/Sming/Wiring/WMath.cpp +++ b/Sming/Wiring/WMath.cpp @@ -29,7 +29,7 @@ void srandom(unsigned int s) seed = s; } -int random() +static int getRandom() { unsigned int next = seed; int result; @@ -65,7 +65,7 @@ long random(long howbig) if (howbig == 0) return 0; - return random() % howbig; + return getRandom() % howbig; } From fb599d78aa49c368bff1066a5219469bcf641981 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Sat, 18 May 2019 17:36:10 +0100 Subject: [PATCH 08/19] Fix `IMPORT_FSTR` for Linux/Windows host builds * `.word` only emits 2 bytes on Linux, so use `.long` which is fine for all 32-bit machines * Windows (COFF format) requires different implemention * Use `.irom0.text`, not `.irom.text` (fixes 'section changed' warning) --- Sming/Wiring/FlashString.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Sming/Wiring/FlashString.h b/Sming/Wiring/FlashString.h index 5483352ea9..c624e0bb39 100644 --- a/Sming/Wiring/FlashString.h +++ b/Sming/Wiring/FlashString.h @@ -161,15 +161,33 @@ * The file content is bound into firmware image at link time. * @note The FlashString object must be referenced or the linker won't emit it. */ +#ifdef __WIN32 #define IMPORT_FSTR(name, file) \ - __asm__(".section .irom.text\n" \ + __asm__(".section .rodata\n" \ + ".global _" #name "\n" \ + ".def _" #name "; .scl 2; .type 32; .endef\n" \ + ".align 4\n" \ + "_" #name ":\n" \ + ".long _" #name "_end - _" #name " - 4\n" \ + ".incbin \"" file "\"\n" \ + "_" #name "_end:\n"); \ + extern const __attribute__((aligned(4))) FlashString name; +#else +#ifdef ARCH_HOST +#define IROM_SECTION ".rodata" +#else +#define IROM_SECTION ".irom0.text" +#endif +#define IMPORT_FSTR(name, file) \ + __asm__(".section " IROM_SECTION "\n" \ ".global " #name "\n" \ ".type " #name ", @object\n" \ ".align 4\n" #name ":\n" \ - ".word _" #name "_end - " #name " - 4\n" \ + ".long _" #name "_end - " #name " - 4\n" \ ".incbin \"" file "\"\n" \ "_" #name "_end:\n"); \ extern const __attribute__((aligned(4))) FlashString name; +#endif /** @brief describes a counted string stored in flash memory * @note because the string length is stored there is no need to call strlen_P before reading the From ad14726960ad12e48d10880ce03dd7babf493a58 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Mon, 20 May 2019 12:08:28 +0100 Subject: [PATCH 09/19] CI updates Add `HostTests` sample * Runs some tests against ArduinoJson6 and filesystem, asserts on failure * Remove related code from `LiveDebug` sample Travis * Move script into separate `build.sh` file * Use more recent linux distro (xenial vs. trusty) with less dated GCC - resolves conflict with `std::isnan` and `std::isinf` and stdc function declarations * Build and run `HostTests` sample Appveyor * Run mingw update/upgrade - default appveyor install is 5.3.0, current is 6.3.0 * Move build script into batch file * Add basic Host build and run `HostTests` sample --- .appveyor/build.cmd | 41 +++++ .travis.yml | 56 +++--- .travis/build.sh | 41 +++++ appveyor.yml | 47 ++--- samples/HostTests/.cproject | 151 ++++++++++++++++ samples/HostTests/.project | 28 +++ samples/HostTests/Makefile | 20 +++ samples/HostTests/app/application.cpp | 16 ++ samples/HostTests/app/common.h | 15 ++ samples/HostTests/app/test-files.cpp | 105 +++++++++++ samples/HostTests/app/test-json.cpp | 243 ++++++++++++++++++++++++++ samples/LiveDebug/app/application.cpp | 152 ---------------- 12 files changed, 697 insertions(+), 218 deletions(-) create mode 100644 .appveyor/build.cmd create mode 100644 .travis/build.sh create mode 100644 samples/HostTests/.cproject create mode 100644 samples/HostTests/.project create mode 100644 samples/HostTests/Makefile create mode 100644 samples/HostTests/app/application.cpp create mode 100644 samples/HostTests/app/common.h create mode 100644 samples/HostTests/app/test-files.cpp create mode 100644 samples/HostTests/app/test-json.cpp diff --git a/.appveyor/build.cmd b/.appveyor/build.cmd new file mode 100644 index 0000000000..aeaf3b84db --- /dev/null +++ b/.appveyor/build.cmd @@ -0,0 +1,41 @@ +REM Appveyor Windows build script + +SET SMING_HOME=%APPVEYOR_BUILD_FOLDER%\Sming +SET ESP_HOME=c:\Espressif +SET PATH=%PATH%;%ESP_HOME%/utils +cd %SMING_HOME% +gcc -v + +make help +make list-config + +REM Compile the tools first +make tools V=1 || goto :error + +IF "%SDK_VERSION%" == "2.0.0" ( + REM Build Host Emulator and run basic tests + set SMING_ARCH=Host + cd %SMING_HOME% + make STRICT=1 || goto :error + make Basic_Serial || goto :error + make Basic_ProgMem || goto :error + cd %SMING_HOME%\..\samples\HostTests + make flash || goto :error +) + +REM Build library and test sample apps +set SMING_ARCH=Esp8266 +cd %SMING_HOME% +make STRICT=1 || goto :error +cd %SMING_HOME%\..\samples\Basic_Blink +make V=1 || goto :error +cd %SMING_HOME%\..\samples\Basic_Ssl +make || goto :error +cd %SMING_HOME%\..\samples\Basic_SmartConfig +make || goto :error + +goto :EOF + +:error +echo Failed with error #%errorlevel%. +exit /b %errorlevel% diff --git a/.travis.yml b/.travis.yml index 910d5d1eb9..2bef365aaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ matrix: - os: linux env: SDK_VERSION=2.0.0 - os: linux + dist: xenial env: SDK_VERSION=3.0.0 git: submodules: false @@ -28,45 +29,34 @@ addons: - graphviz - xmlstarlet - clang-format-6.0 + - gcc-multilib + - g++-multilib install: - sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-6.0 100 -- if [ "$SDK_VERSION" == "1.5.0" ] && [ "$TRAVIS_OS_NAME" == "osx" ]; then export - SDK_FILE_NAME="esp-alt-sdk-v${SDK_VERSION}.${SDK_BUILD}-macos-x86_64.zip"; fi -- if [ "$SDK_VERSION" == "1.5.0" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then export - SDK_FILE_NAME="esp-alt-sdk-v${SDK_VERSION}.${SDK_BUILD}-linux-x86_64.tar.gz"; fi +- if [ "$SDK_VERSION" == "1.5.0" ] && [ "$TRAVIS_OS_NAME" == "osx" ]; then + export SDK_FILE_NAME="esp-alt-sdk-v${SDK_VERSION}.${SDK_BUILD}-macos-x86_64.zip"; + fi +- if [ "$SDK_VERSION" == "1.5.0" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then + export SDK_FILE_NAME="esp-alt-sdk-v${SDK_VERSION}.${SDK_BUILD}-linux-x86_64.tar.gz"; + fi - mkdir -p $TRAVIS_BUILD_DIR/opt/esp-alt-sdk -- if [ "$SDK_VERSION" == "1.5.0" ]; then wget https://bintray.com/artifact/download/kireevco/generic/${SDK_FILE_NAME}; +- if [ "$SDK_VERSION" == "1.5.0" ]; then + wget https://bintray.com/artifact/download/kireevco/generic/${SDK_FILE_NAME}; + fi +- if [ "$SDK_VERSION" == "1.5.0" ]; then + bsdtar -xf ${SDK_FILE_NAME} -C $TRAVIS_BUILD_DIR/opt/esp-alt-sdk; fi -- if [ "$SDK_VERSION" == "1.5.0" ]; then bsdtar -xf ${SDK_FILE_NAME} -C $TRAVIS_BUILD_DIR/opt/esp-alt-sdk; +- if [[ "$SDK_VERSION" != "1.5.0" && "$TRAVIS_OS_NAME" == "linux" ]]; then + wget https://github.com/nodemcu/nodemcu-firmware/raw/2d958750b56fc60297f564b4ec303e47928b5927/tools/esp-open-sdk.tar.xz; + tar -Jxvf esp-open-sdk.tar.xz; ln -s `pwd`/esp-open-sdk/xtensa-lx106-elf $TRAVIS_BUILD_DIR/opt/esp-alt-sdk/.; fi -- if [[ "$SDK_VERSION" != "1.5.0" && "$TRAVIS_OS_NAME" == "linux" ]]; then wget https://github.com/nodemcu/nodemcu-firmware/raw/2d958750b56fc60297f564b4ec303e47928b5927/tools/esp-open-sdk.tar.xz; - tar -Jxvf esp-open-sdk.tar.xz; ln -s `pwd`/esp-open-sdk/xtensa-lx106-elf $TRAVIS_BUILD_DIR/opt/esp-alt-sdk/. - ; fi -- if [ "$SDK_VERSION" == "2.0.0" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then wget - https://www.espressif.com/sites/default/files/sdks/esp8266_nonos_sdk_v2.0.0_16_08_10.zip - -O sdk.zip; unzip sdk.zip; ln -s `pwd`/ESP8266_NONOS_SDK/ $TRAVIS_BUILD_DIR/opt/esp-alt-sdk/sdk; - export DEPLOY='true'; fi -script: -- env -- unset SPIFFY -- unset ESPTOOL2 - -- export SMING_HOME=$TRAVIS_BUILD_DIR/Sming -- export ESP_HOME=$TRAVIS_BUILD_DIR/opt/esp-alt-sdk -- if [ "$SDK_VERSION" == "3.0.0" ]; then export SDK_BASE=$SMING_HOME/third-party/ESP8266_NONOS_SDK; +- if [ "$SDK_VERSION" == "2.0.0" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then + wget https://www.espressif.com/sites/default/files/sdks/esp8266_nonos_sdk_v2.0.0_16_08_10.zip -O sdk.zip; + unzip sdk.zip; + ln -s `pwd`/ESP8266_NONOS_SDK/ $TRAVIS_BUILD_DIR/opt/esp-alt-sdk/sdk; + export DEPLOY='true'; fi -- export PATH=$PATH:$ESP_HOME/xtensa-lx106-elf/bin:$ESP_HOME/utils/:$SMING_HOME/../.travis/tools -- cd $SMING_HOME -- if [ "$SDK_VERSION" == "2.0.0" ]; then ../.travis/tools/clang/format-pr.sh; fi -- cd $SMING_HOME -- make help -- make list-config -- make STRICT=1 -- make samples -- make clean samples-clean -- make ENABLE_CUSTOM_HEAP=1 STRICT=1 -- make Basic_Blink ENABLE_CUSTOM_HEAP=1 DEBUG_VERBOSE_LEVEL=3 -- make dist-clean; make HttpServer_ConfigNetwork ENABLE_CUSTOM_LWIP=2 STRICT=1 +script: sh $TRAVIS_BUILD_DIR/.travis/build.sh deploy: provider: script script: sh $TRAVIS_BUILD_DIR/.travis/deploy.sh $TRAVIS_TAG diff --git a/.travis/build.sh b/.travis/build.sh new file mode 100644 index 0000000000..a95108928c --- /dev/null +++ b/.travis/build.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -e # exit with nonzero exit code if anything fails + +env +unset SPIFFY +unset ESPTOOL2 + +export SMING_HOME=$TRAVIS_BUILD_DIR/Sming +export ESP_HOME=$TRAVIS_BUILD_DIR/opt/esp-alt-sdk +if [ "$SDK_VERSION" = "3.0.0" ]; then + export SDK_BASE=$SMING_HOME/third-party/ESP8266_NONOS_SDK +fi + +cd $SMING_HOME + +export PATH=$PATH:$ESP_HOME/xtensa-lx106-elf/bin:$ESP_HOME/utils/:$SMING_HOME/../.travis/tools +if [ "$SDK_VERSION" = "2.0.0" ]; then + ../.travis/tools/clang/format-pr.sh; +fi + +if [ "$SDK_VERSION" = "3.0.0" ]; then + export SMING_ARCH=Host + export STRICT=1 + make help + make list-config + make + make Basic_Blink Basic_DateTime Basic_Delegates Basic_Interrupts Basic_ProgMem Basic_Serial Basic_Servo LiveDebug DEBUG_VERBOSE_LEVEL=3 + cd ../samples/HostTests + make flash + cd $SMING_HOME +fi + +export SMING_ARCH=Esp8266 +make help +make list-config +make STRICT=1 +make samples +make clean samples-clean +make ENABLE_CUSTOM_HEAP=1 STRICT=1 +make Basic_Blink ENABLE_CUSTOM_HEAP=1 DEBUG_VERBOSE_LEVEL=3 +make dist-clean; make HttpServer_ConfigNetwork ENABLE_CUSTOM_LWIP=2 STRICT=1 diff --git a/appveyor.yml b/appveyor.yml index cbf5aa37a0..5485759355 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,37 +16,18 @@ environment: # cache: # - src/ # preserve "packages" directory in the root of build folder but will reset it if packages.config is modified install: - - choco sources add -name sming -source 'https://www.myget.org/F/sming/' - - ps: if($env:SDK_VERSION -eq '1.5.0') { - choco install esp8266-udk --source https://www.myget.org/F/kireevco-chocolatey/; - mkdir c:\Espressif\utils\ESP8266; - cp c:\Espressif\utils\memanalyzer.exe c:\Espressif\utils\ESP8266\memanalyzer.exe; - cp c:\Espressif\utils\esptool.exe c:\Espressif\utils\ESP8266\esptool.exe; - } - else { - choco install esp8266-udk - } - - - + - ps: >- + if($env:SDK_VERSION -eq '1.5.0') { + choco install esp8266-udk --source https://www.myget.org/F/kireevco-chocolatey/ -y --no-progress + mkdir c:\Espressif\utils\ESP8266 + cp c:\Espressif\utils\memanalyzer.exe c:\Espressif\utils\ESP8266\memanalyzer.exe + cp c:\Espressif\utils\esptool.exe c:\Espressif\utils\ESP8266\esptool.exe + } + else { + choco install esp8266-udk --source https://www.myget.org/F/sming/ -y --no-progress + } + - cmd: mingw-get update + - cmd: mingw-get upgrade + build_script: - - SET SMING_HOME=%APPVEYOR_BUILD_FOLDER%\Sming - - SET ESP_HOME=c:\Espressif - - SET PATH=%PATH%;%ESP_HOME%/utils - - cd %SMING_HOME% - - gcc -v -# - - make help - - make list-config -# Compile the tools first - - make tools V=1 -# Followed by the library and test sample apps - - cd %SMING_HOME% - - make STRICT=1 - - cd %SMING_HOME%\..\samples\Basic_Blink - - make V=1 - - cd %SMING_HOME%\..\samples\Basic_Ssl - - make - - cd %SMING_HOME%\..\samples\Basic_SmartConfig - - make - + - cmd: .appveyor/build.cmd diff --git a/samples/HostTests/.cproject b/samples/HostTests/.cproject new file mode 100644 index 0000000000..67c056d24e --- /dev/null +++ b/samples/HostTests/.cproject @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make + -f ${ProjDirPath}/Makefile + all + true + true + true + + + make + -f ${ProjDirPath}/Makefile + clean + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flash + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flashonefile + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flashinit + true + true + true + + + make + -f ${ProjDirPath}/Makefile + flashboot + true + true + true + + + make + -f ${ProjDirPath}/Makefile + rebuild + true + true + true + + + + + + + + + + + + + + + + + + + + diff --git a/samples/HostTests/.project b/samples/HostTests/.project new file mode 100644 index 0000000000..e99f7089db --- /dev/null +++ b/samples/HostTests/.project @@ -0,0 +1,28 @@ + + + HostTests + + + SmingFramework + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/samples/HostTests/Makefile b/samples/HostTests/Makefile new file mode 100644 index 0000000000..77fee85347 --- /dev/null +++ b/samples/HostTests/Makefile @@ -0,0 +1,20 @@ +##################################################################### +#### Please don't change this file. Use Makefile-user.mk instead #### +##################################################################### +# Including user Makefile. +# Should be used to set project-specific parameters +include ./Makefile-user.mk + +# Important parameters check. +# We need to make sure SMING_HOME and ESP_HOME variables are set. +# You can use Makefile-user.mk in each project or use enviromental variables to set it globally. + +ifndef SMING_HOME +$(error SMING_HOME is not set. Please configure it in Makefile-user.mk) +endif +ifndef ESP_HOME +$(error ESP_HOME is not set. Please configure it in Makefile-user.mk) +endif + +# Include application Makefile +include $(SMING_HOME)/Makefile-rboot.mk \ No newline at end of file diff --git a/samples/HostTests/app/application.cpp b/samples/HostTests/app/application.cpp new file mode 100644 index 0000000000..fd8f16dac4 --- /dev/null +++ b/samples/HostTests/app/application.cpp @@ -0,0 +1,16 @@ +#include + +extern void test_json(); +extern void test_files(); + +void init() +{ + spiffs_mount(); + Serial.begin(SERIAL_BAUD_RATE); + Serial.systemDebugOutput(true); + + test_json(); + test_files(); + + system_restart(); +} diff --git a/samples/HostTests/app/common.h b/samples/HostTests/app/common.h new file mode 100644 index 0000000000..4b02bcd36f --- /dev/null +++ b/samples/HostTests/app/common.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef ARCH_HOST +#include +#else +#define hostmsg debug_i +#endif + +#define startTest(str) \ + do { \ + m_puts("\r\n"); \ + hostmsg(">> %s", PSTR(str)); \ + } while(0) diff --git a/samples/HostTests/app/test-files.cpp b/samples/HostTests/app/test-files.cpp new file mode 100644 index 0000000000..dd2e91cc43 --- /dev/null +++ b/samples/HostTests/app/test-files.cpp @@ -0,0 +1,105 @@ +#include "common.h" + +IMPORT_FSTR(testContent, "../../Readme.md"); + +void test_files() +{ + // hostmsg("testContent.length = 0x%08x", testContent.length()); + + DEFINE_FSTR_LOCAL(testFileName, "test.txt"); + spiffs_mount(); + + int res, pos, size; + + // + startTest("Initial position and size"); + res = fileSetContent(testFileName, testContent); + debug_i("fileSetContent() returned %d", res); + assert(size_t(res) == testContent.length()); + auto file = fileOpen(testFileName, eFO_ReadWrite); + size = fileSeek(file, 0, eSO_FileEnd); + pos = fileSeek(file, 100, eSO_FileStart); + debug_i("pos = %d, size = %d", pos, size); + assert(pos == 100 && size_t(size) == testContent.length()); + + startTest("Reduce file sizes"); + res = fileTruncate(file, 555); + pos = fileTell(file); + size = fileSeek(file, 0, eSO_FileEnd); + debug_i("res = %d, pos = %d, size = %d", res, pos, size); + assert(res == 0 && pos == 100 && size == 555); + + startTest("Increase file size"); + res = fileTruncate(file, 12345); + size = fileSeek(file, 0, eSO_FileEnd); + debug_i("res = %d, size = %d", res, size); + assert(res < 0 && size == 555); + + startTest("Close file"); + fileClose(file); + size = fileGetSize(testFileName); + debug_i("size = %u", size); + assert(size == 555); + + startTest("Truncate by file name, increase size"); + fileSetContent(testFileName, testContent); + res = fileTruncate(testFileName, 34500); + size = fileGetSize(testFileName); + debug_i("fileTruncate() returned %d, size = %d", res, size); + assert(res < 0 && size_t(size) == testContent.length()); + + startTest("Truncate by file name, reduce size"); + res = fileTruncate(testFileName, 345); + size = fileGetSize(testFileName); + debug_i("fileTruncate() returned %d, size = %d", res, size); + assert(res == 0 && size == 345); + + startTest("Truncate read-only file stream"); + fileSetContent(testFileName, testContent); + FileStream fs(testFileName); + res = fs.truncate(100); + pos = fs.getPos(); + size = fs.getSize(); + debug_i("fs.truncate() returned %d, pos = %d, size = %d", res, pos, size); + assert(res == false && pos == 0 && size_t(size) == testContent.length()); + fs.close(); + size = fileGetSize(testFileName); + debug_i("Actual file size = %d", size); + assert(size_t(size) == testContent.length()); + + startTest("Truncate read/write file stream"); + fs.open(testFileName, eFO_ReadWrite); + fs.seek(50); + res = fs.truncate(100); + pos = fs.getPos(); + size = fs.getSize(); + debug_i("fs.truncate() returned %d, pos = %d, size = %d", res, pos, size); + assert(res == true && pos == 50 && size == 100); + fs.close(); + size = fileGetSize(testFileName); + debug_i("Actual file size = %d", size); + assert(size == 100); + + startTest("Seek file stream past end of file"); + fs.open(testFileName, eFO_ReadWrite); + res = fs.seekFrom(101, eSO_FileStart); + pos = fs.getPos(); + size = fs.getSize(); + debug_i("fs.seekFrom() returned %d, pos = %d, size = %d", res, pos, size); + assert(res == 100 && pos == 100 && size == 100); + fs.close(); + size = fileGetSize(testFileName); + debug_i("Actual file size = %d", size); + assert(size == 100); + + // startTest("Enumerate directories"); + // filedir_t dir; + // if(fileOpenDir(nullptr, dir) == 0) { + // dirent_t entry; + // int res; + // while((res = fileReadDir(dir, entry)) == 0) { + // debug_i("\"%s\" %u", entry.name, entry.size); + // } + // } + // fileCloseDir(dir); +} diff --git a/samples/HostTests/app/test-json.cpp b/samples/HostTests/app/test-json.cpp new file mode 100644 index 0000000000..b885315b2a --- /dev/null +++ b/samples/HostTests/app/test-json.cpp @@ -0,0 +1,243 @@ +#include "common.h" + +void test_json() +{ + DEFINE_FSTR_LOCAL(flashString1, "FlashString-1"); + DEFINE_FSTR_LOCAL(flashString2, "FlashString-2"); + DEFINE_FSTR_LOCAL(formatStrings, "Compact\0Pretty\0MessagePack"); + DEFINE_FSTR_LOCAL(test_json, "test.json"); + DEFINE_FSTR_LOCAL(test_msgpack, "test.msgpack"); + + spiffs_mount(); + + StaticJsonDocument<512> doc; + doc["string1"] = "string value 1"; + doc["number2"] = 12345; + auto arr = doc.createNestedArray("arr"); + arr.add(flashString1); + doc[flashString2] = flashString1; + + startTest("serialize"); + { + DEFINE_FSTR_LOCAL(serialized1, + "{\"string1\":\"string value " + "1\",\"number2\":12345,\"arr\":[\"FlashString-1\"],\"FlashString-2\":\"FlashString-1\"}"); + + String s = Json::serialize(doc); + debug_i("Test doc: %s", s.c_str()); + assert(s == serialized1); + } + + // + startTest("Json::measure()"); + { + CStringArray formats(formatStrings); + const uint8_t sizes[] = {100, 132, 82}; + for(auto fmt = Json::Compact; fmt <= Json::MessagePack; ++fmt) { + auto len = Json::measure(doc, fmt); + debug_i("Measure(doc, %s) = %u", formats[fmt], len); + assert(len == sizes[fmt]); + } + } + + // + startTest("Json::getValue(doc[\"number2\"], value))"); + { + int value; + if(Json::getValue(doc["number2"], value)) { + debug_i("number2 = %d", value); + assert(value == 12345); + } else { + debug_e("number2 not found"); + } + } + + // + startTest("Json::getValue(doc[\"string\"], value))"); + { + String value; + if(Json::getValue(doc["string"], value)) { + debug_i("string = %d", value.c_str()); + assert(false); + } else { + debug_e("string not found"); + } + } + + // + startTest("Json::getValue(doc[\"arr\"][1], value"); + { + String value; + if(Json::getValue(doc["arr"][0], value)) { + debug_i("arr = %s", value.c_str()); + assert(value == flashString1); + } else { + debug_e("arr not found"); + assert(false); + } + } + + // Keep a reference copy for when doc gets messed up + StaticJsonDocument<512> sourceDoc = doc; + + // + startTest("Json::serialize(doc, String), then save to file"); + { + String s; + Json::serialize(doc, s); + fileSetContent(test_json, s); + } + + // + startTest("Json::saveToFile(doc, test_json, Json::Pretty)"); + bool res = Json::saveToFile(doc, test_json, Json::Pretty); + debug_i("writeToFile %s", res ? "OK" : "FAILED"); + assert(res); + + // + startTest("Json::loadFromFile(doc, test_json)"); + { + res = Json::loadFromFile(doc, test_json); + debug_i("loadFromFile %s", res ? "OK" : "FAILED"); + assert(res); + String s = fileGetContent(test_json); + Serial.println(s); + } + + // + startTest("Json::serialize(doc, MemoryDataStream*)"); + { + doc = sourceDoc; + auto stream = new MemoryDataStream; + Json::serialize(doc, stream, Json::Compact); + auto avail = stream->available(); + debug_i("serialize -> %d bytes", avail); + assert(avail == 100); + Json::deserialize(doc, stream, Json::Compact); + auto measured = Json::measure(doc); + debug_i("deserialize -> %u bytes", measured); + assert(measured == size_t(avail)); + Serial.println(Json::serialize(doc)); + delete stream; + } + + // + startTest("nullptr checks"); + { + MemoryDataStream* stream = nullptr; + auto count = Json::serialize(doc, stream); + debug_i("Json::serialize(stream = nullptr) = %u", count); + auto err = Json::deserialize(doc, stream); + debug_i("Json::deserialize(stream = nullptr) = %u", err); + debug_i("doc.memoryUsage = %u", doc.memoryUsage()); + } + + // + String serialised; + startTest("String serialisation"); + { + doc = sourceDoc; + serialised = Json::serialize(doc); + m_printHex("serialized", serialised.c_str(), serialised.length()); + String s; + Json::deserialize(doc, s); + m_printHex("de-serialized", s.c_str(), s.length()); + debug_i("doc.memoryUsage = %u", doc.memoryUsage()); + } + + // + startTest("Buffer serialisation"); + char buffer[256]; + { + doc = sourceDoc; + size_t len = Json::serialize(doc, buffer); + m_printHex("Serialised", buffer, len); + assert(len == serialised.length()); + assert(memcmp(buffer, serialised.c_str(), len) == 0); + } + + // + startTest("Buffer/Size serialisation"); + { + doc = sourceDoc; + auto len = Json::serialize(doc, buffer, sizeof(buffer)); + m_printHex("Serialised", buffer, len); + assert(len == serialised.length()); + assert(memcmp(buffer, serialised.c_str(), len) == 0); + Json::deserialize(doc, buffer, len); + m_printHex("De-serialized", buffer, len); + debug_i("doc.memoryUsage = %u", doc.memoryUsage()); + } + + // + startTest("Json::saveToFile(doc, test_msgpack, Json::MessagePack)"); + { + res = Json::saveToFile(doc, test_msgpack, Json::MessagePack); + debug_i("writeToFile(%s, MessagePack)", res ? "OK" : "FAILED"); + } + + // + startTest("Json::loadFromFile(doc, test_msgpack, Json::MessagePack)"); + { + res = Json::loadFromFile(doc, test_msgpack, Json::MessagePack); + debug_i("MsgPack::loadFromFile %s", res ? "OK" : "FAILED"); + assert(res); + String s = fileGetContent(test_msgpack); + m_printHex("MSG", s.c_str(), s.length()); + assert(s.length() == 82); + } + + // + startTest("Json::serialize(doc, Serial)"); + { + Json::serialize(doc, Serial); + Serial.println(); + Json::serialize(doc, Serial, Json::Pretty); + Serial.println(); + } + + // + startTest("Json::measure(doc2)"); + { + StaticJsonDocument<10> doc2; + auto measured = Json::measure(doc2); + debug_i("measure(doc2) = %u", measured); + assert(measured == 4); + String s; + Json::serialize(doc2, s); + m_printHex("doc2", s.c_str(), s.length()); + assert(s == "null"); + } + + // Serialization + startTest("Serialise to MemoryDataStream"); + const char jsonTest[] = "{\"key1\":\"value1\",\"key2\":\"value2\"}"; + Json::deserialize(doc, jsonTest); + { + auto stream = new MemoryDataStream; + stream->setTimeout(0); + size_t serializedLength = Json::serialize(doc, stream); + debug_i("serialized length = %u", serializedLength); + assert(serializedLength == 33); + String content = stream->readString(); + debug_i("stream->read returned %u", content.length()); + Serial.println(content); + assert(content == jsonTest); + delete stream; + } + + // De-serialisation + { + startTest("De-serialise from MemoryDataStream"); + auto stream = new MemoryDataStream; + stream->write(reinterpret_cast(jsonTest), sizeof(jsonTest)); + bool res = Json::deserialize(doc, stream); + debug_i("Json::deserialize() returned %u", res); + assert(res == true); + String s; + serializeJson(doc, s); + Serial.println(s); + assert(s == jsonTest); + delete stream; + } +} diff --git a/samples/LiveDebug/app/application.cpp b/samples/LiveDebug/app/application.cpp index 31a9e0407c..6b62c43e34 100644 --- a/samples/LiveDebug/app/application.cpp +++ b/samples/LiveDebug/app/application.cpp @@ -272,7 +272,6 @@ void fileStat(const char* filename) * This also helps to keep the code clean and easy to read. */ #define COMMAND_MAP(XX) \ - XX(jsontest, "Run some ArduinoJson V6 tests") \ XX(readfile1, "Use syscall file I/O functions to read and display a host file\n" \ "Calls are blocking so the application is paused during the entire operation") \ XX(readfile2, "Read a larger host file asynchronously\n" \ @@ -543,157 +542,6 @@ COMMAND_HANDLER(help) return true; } -COMMAND_HANDLER(jsontest) -{ - DEFINE_FSTR_LOCAL(flashString1, "FlashString-1"); - DEFINE_FSTR_LOCAL(flashString2, "FlashString-2"); - DEFINE_FSTR_LOCAL(formatStrings, "Compact\0Pretty\0MessagePack"); - DEFINE_FSTR_LOCAL(test_json, "test.json"); - DEFINE_FSTR_LOCAL(test_msgpack, "test.msgpack"); - - spiffs_mount(); - -#define startTest(s) m_printf("\r\n>> %s\n", PSTR(s)); - - StaticJsonDocument<512> doc; - doc["string1"] = "string value 1"; - doc["number2"] = 12345; - auto arr = doc["arr"].createNestedArray(); - arr.add(flashString1); - doc[flashString2] = flashString1; - - debug_i("Test doc: %s", Json::serialize(doc).c_str()); - - { - CStringArray formats(formatStrings); - - for(auto fmt = Json::Compact; fmt <= Json::MessagePack; ++fmt) { - debug_i("Measure(doc, %s) = %u", formats[fmt], Json::measure(doc, fmt)); - } - } - - // - startTest("Json::getValue(doc[\"number2\"], value))"); - int value; - if(Json::getValue(doc["number2"], value)) { - debug_i("number2 = %d", value); - } else { - debug_e("number2 not found"); - } - - // - startTest("Json::getValue(doc[\"string\"], value))"); - if(Json::getValue(doc["string"], value)) { - debug_i("string = %d", value); - } else { - debug_e("string not found"); - } - - // - startTest("Json::getValue(doc[\"arr\"][1], value"); - if(Json::getValue(doc["arr"][1], value)) { - debug_i("arr = %d", value); - } else { - debug_e("arr not found"); - } - - // Keep a reference copy for when doc gets messed up - StaticJsonDocument<512> sourceDoc = doc; - - // - startTest("Json::serialize(doc, String), then save to file"); - String s; - Json::serialize(doc, s); - fileSetContent(test_json, s); - - // - startTest("Json::saveToFile(doc, test_json, Json::Pretty)"); - bool res = Json::saveToFile(doc, test_json, Json::Pretty); - debug_i("writeToFile %s", res ? "OK" : "FAILED"); - - // - startTest("Json::loadFromFile(doc, test_json)"); - res = Json::loadFromFile(doc, test_json); - debug_i("loadFromFile %s", res ? "OK" : "FAILED"); - s = fileGetContent(test_json); - m_nputs(s.c_str(), s.length()); - m_putc('\n'); - - // - startTest("Json::serialize(doc, MemoryDataStream*)"); - doc = sourceDoc; - auto stream = new MemoryDataStream; - Json::serialize(doc, stream); - debug_i("stream contains %d bytes", stream->available()); - Json::deserialize(doc, stream); - debug_i("doc contains %u bytes", Json::measure(doc)); - - // - startTest("nullptr checks"); - delete stream; - stream = nullptr; - auto err = Json::deserialize(doc, stream); - debug_i("deserializeJson(stream = nullptr) = %u", err); - debug_i("doc.memoryUsage = %u", doc.memoryUsage()); - - // - startTest("String serialisation"); - doc = sourceDoc; - s = Json::serialize(doc); - m_printHex("serialized", s.c_str(), s.length()); - Json::deserialize(doc, s); - m_printHex("de-serialized", s.c_str(), s.length()); - debug_i("doc.memoryUsage = %u", doc.memoryUsage()); - - // - startTest("Buffer serialisation"); - doc = sourceDoc; - char buffer[256]; - size_t len = Json::serialize(doc, buffer); - m_printHex("Serialised", buffer, len); - Json::deserialize(doc, buffer, len); - m_printHex("De-serialized", buffer, len); - debug_i("doc.memoryUsage = %u", doc.memoryUsage()); - - // - startTest("Buffer/Size serialisation"); - doc = sourceDoc; - len = Json::serialize(doc, buffer, sizeof(buffer)); - m_printHex("Serialised", buffer, len); - Json::deserialize(doc, buffer, len); - m_printHex("De-serialized", buffer, len); - debug_i("doc.memoryUsage = %u", doc.memoryUsage()); - - // - startTest("Json::saveToFile(doc, test_msgpack, Json::MessagePack)"); - res = Json::saveToFile(doc, test_msgpack, Json::MessagePack); - debug_i("writeToFile(%s, MessagePack)", res ? "OK" : "FAILED"); - - // - startTest("Json::loadFromFile(doc, test_msgpack, Json::MessagePack)"); - res = Json::loadFromFile(doc, test_msgpack, Json::MessagePack); - debug_i("MsgPack::loadFromFile %s", res ? "OK" : "FAILED"); - s = fileGetContent(test_msgpack); - m_printHex("MSG", s.c_str(), s.length()); - - // - startTest("Json::serialize(doc, Serial)"); - Json::serialize(doc, Serial); - Serial.println(); - Json::serialize(doc, Serial, Json::Pretty); - Serial.println(); - - // - startTest("Json::measure(doc2)"); - StaticJsonDocument<10> doc2; - debug_i("measure(doc2) = %u", Json::measure(doc2)); - s = nullptr; - Json::serialize(doc2, s); - m_printHex("doc2", s.c_str(), s.length()); - - return true; -} - /** * @brief User typed a command. Deal with it. * @retval bool true to continue reading another command From 6ac082ee33f8bd75dfeb718e547952581debc942 Mon Sep 17 00:00:00 2001 From: mikee47 Date: Thu, 30 May 2019 12:02:55 +0100 Subject: [PATCH 10/19] Update Host readme.md --- Sming/Arch/Host/readme.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Sming/Arch/Host/readme.md b/Sming/Arch/Host/readme.md index 55eddd3931..e9d11e1957 100644 --- a/Sming/Arch/Host/readme.md +++ b/Sming/Arch/Host/readme.md @@ -90,14 +90,25 @@ At present the emulator just writes output to the console. Inputs all return 0. Support is provided via TAP network interface (a virtual network layer operating at the ethernet frame level). A TAP interface must be created first, and requires root priviledge: -``` -sudo ip tuntap add dev tap0 mode tap user `whoami` -sudo ip a a dev tap0 192.168.13.1/24 -sudo ifconfig tap0 up -``` + sudo ip tuntap add dev tap0 mode tap user `whoami` + sudo ip a a dev tap0 192.168.13.1/24 + sudo ifconfig tap0 up This creates the `tap0` interface, and is persistent across OS reboots. The emulator will automatically select the first `tap` interface found. To override this, use the `--ifname` option. An IP address will be assigned, but can be changed using the `--ipaddr` option. +If your application needs to access the internet, additional setup is required: + + sudo sysctl net.ipv4.ip_forward=1 + sudo sysctl net.ipv6.conf.default.forwarding=1 + sudo sysctl net.ipv6.conf.all.forwarding=1 + + export INTERNET_IF=wlan0 #