diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 42715605c1..2bbe2f933b 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -22,7 +22,7 @@ #include "flash_utils.h" #include "eboot_command.h" #include -#include "interrupts.h" +#include #include "MD5Builder.h" #include "umm_malloc/umm_malloc.h" #include "cont.h" @@ -165,6 +165,7 @@ void EspClass::restart(void) uint16_t EspClass::getVcc(void) { InterruptLock lock; + (void)lock; return system_get_vdd33(); } diff --git a/cores/esp8266/FSImpl.h b/cores/esp8266/FSImpl.h index e5694b5f68..cf84be6a6e 100644 --- a/cores/esp8266/FSImpl.h +++ b/cores/esp8266/FSImpl.h @@ -62,6 +62,7 @@ class DirImpl { class FSImpl { public: + virtual ~FSImpl () { } virtual bool begin() = 0; virtual void end() = 0; virtual bool format() = 0; diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index c82f368c6b..c4fdb5a67f 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -1,8 +1,8 @@ #include "Updater.h" #include "Arduino.h" #include "eboot_command.h" -#include "interrupts.h" -#include "esp8266_peri.h" +#include +#include //#define DEBUG_UPDATER Serial @@ -84,21 +84,21 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) { wifi_set_sleep_type(NONE_SLEEP_T); - uint32_t updateStartAddress = 0; + uintptr_t updateStartAddress = 0; if (command == U_FLASH) { //size of current sketch rounded to a sector - uint32_t currentSketchSize = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); + size_t currentSketchSize = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); //address of the end of the space available for sketch and update - uint32_t updateEndAddress = (uint32_t)&_SPIFFS_start - 0x40200000; + uintptr_t updateEndAddress = (uintptr_t)&_SPIFFS_start - 0x40200000; //size of the update rounded to a sector - uint32_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); + size_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); //address where we will start writing the update updateStartAddress = (updateEndAddress > roundedSize)? (updateEndAddress - roundedSize) : 0; #ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("[begin] roundedSize: 0x%08X (%d)\n", roundedSize, roundedSize); - DEBUG_UPDATER.printf("[begin] updateEndAddress: 0x%08X (%d)\n", updateEndAddress, updateEndAddress); - DEBUG_UPDATER.printf("[begin] currentSketchSize: 0x%08X (%d)\n", currentSketchSize, currentSketchSize); + DEBUG_UPDATER.printf("[begin] roundedSize: 0x%08zX (%zd)\n", roundedSize, roundedSize); + DEBUG_UPDATER.printf("[begin] updateEndAddress: 0x%08zX (%zd)\n", updateEndAddress, updateEndAddress); + DEBUG_UPDATER.printf("[begin] currentSketchSize: 0x%08zX (%zd)\n", currentSketchSize, currentSketchSize); #endif //make sure that the size of both sketches is less than the total space (updateEndAddress) @@ -108,7 +108,7 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) { } } else if (command == U_SPIFFS) { - updateStartAddress = (uint32_t)&_SPIFFS_start - 0x40200000; + updateStartAddress = (uintptr_t)&_SPIFFS_start - 0x40200000; } else { // unknown command @@ -133,7 +133,7 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) { #ifdef DEBUG_UPDATER DEBUG_UPDATER.printf("[begin] _startAddress: 0x%08X (%d)\n", _startAddress, _startAddress); DEBUG_UPDATER.printf("[begin] _currentAddress: 0x%08X (%d)\n", _currentAddress, _currentAddress); - DEBUG_UPDATER.printf("[begin] _size: 0x%08X (%d)\n", _size, _size); + DEBUG_UPDATER.printf("[begin] _size: 0x%08zX (%zd)\n", _size, _size); #endif _md5.begin(); @@ -159,7 +159,7 @@ bool UpdaterClass::end(bool evenIfRemaining){ if(hasError() || (!isFinished() && !evenIfRemaining)){ #ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("premature end: res:%u, pos:%u/%u\n", getError(), progress(), _size); + DEBUG_UPDATER.printf("premature end: res:%u, pos:%zu/%zu\n", getError(), progress(), _size); #endif _reset(); @@ -199,10 +199,10 @@ bool UpdaterClass::end(bool evenIfRemaining){ eboot_command_write(&ebcmd); #ifdef DEBUG_UPDATER - DEBUG_UPDATER.printf("Staged: address:0x%08X, size:0x%08X\n", _startAddress, _size); + DEBUG_UPDATER.printf("Staged: address:0x%08X, size:0x%08zX\n", _startAddress, _size); } else if (_command == U_SPIFFS) { - DEBUG_UPDATER.printf("SPIFFS: address:0x%08X, size:0x%08X\n", _startAddress, _size); + DEBUG_UPDATER.printf("SPIFFS: address:0x%08X, size:0x%08zX\n", _startAddress, _size); #endif } diff --git a/cores/esp8266/spiffs_api.cpp b/cores/esp8266/spiffs_api.cpp index 390a6412fd..a8e522f038 100644 --- a/cores/esp8266/spiffs_api.cpp +++ b/cores/esp8266/spiffs_api.cpp @@ -109,6 +109,7 @@ bool isSpiffsFilenameValid(const char* name) } // these symbols should be defined in the linker script for each flash layout +#ifndef CORE_MOCK #ifdef ARDUINO extern "C" uint32_t _SPIFFS_start; extern "C" uint32_t _SPIFFS_end; @@ -131,6 +132,7 @@ FS SPIFFS = FS(FSImplPtr(new SPIFFSImpl( SPIFFS_PHYS_PAGE, SPIFFS_PHYS_BLOCK, SPIFFS_MAX_OPEN_FILES))); -#endif +#endif // ARDUINO +#endif // !CORE_MOCK #endif diff --git a/cores/esp8266/spiffs_api.h b/cores/esp8266/spiffs_api.h index 4ce8d3e6ba..3a0cb032e1 100644 --- a/cores/esp8266/spiffs_api.h +++ b/cores/esp8266/spiffs_api.h @@ -220,7 +220,7 @@ class SPIFFSImpl : public FSImpl size_t cacheBufSize = SPIFFS_buffer_bytes_for_cache(&_fs, _maxOpenFds); if (!_workBuf) { - DEBUGV("SPIFFSImpl: allocating %d+%d+%d=%d bytes\r\n", + DEBUGV("SPIFFSImpl: allocating %zd+%zd+%zd=%zd bytes\r\n", workBufSize, fdsBufSize, cacheBufSize, workBufSize + fdsBufSize + cacheBufSize); _workBuf.reset(new uint8_t[workBufSize]); diff --git a/libraries/DNSServer/src/DNSServer.cpp b/libraries/DNSServer/src/DNSServer.cpp index e75af30cd7..5e1382bcd1 100644 --- a/libraries/DNSServer/src/DNSServer.cpp +++ b/libraries/DNSServer/src/DNSServer.cpp @@ -10,7 +10,7 @@ DNSServer::DNSServer() { - _ttl = htonl(60); + _ttl = lwip_htonl(60); _errorReplyCode = DNSReplyCode::NonExistentDomain; } @@ -35,7 +35,7 @@ void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) void DNSServer::setTTL(const uint32_t &ttl) { - _ttl = htonl(ttl); + _ttl = lwip_htonl(ttl); } void DNSServer::stop() @@ -81,7 +81,7 @@ void DNSServer::processNextRequest() bool DNSServer::requestIncludesOnlyOneQuestion(const DNSHeader* dnsHeader) { - return ntohs(dnsHeader->QDCount) == 1 && + return lwip_ntohs(dnsHeader->QDCount) == 1 && dnsHeader->ANCount == 0 && dnsHeader->NSCount == 0 && dnsHeader->ARCount == 0; diff --git a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp index ecac309384..a3fbdd9b24 100644 --- a/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp +++ b/libraries/ESP8266HTTPClient/src/ESP8266HTTPClient.cpp @@ -734,7 +734,7 @@ int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) free(buff); if(size && (int) size != bytesWritten) { - DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload bytesWritten %d and size %d mismatch!.\n", bytesWritten, size); + DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload bytesWritten %d and size %zd mismatch!.\n", bytesWritten, size); DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] ERROR SEND PAYLOAD FAILED!"); return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); } else { diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index aec3f732d6..6e8cc0a5de 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -438,12 +438,9 @@ void ESP8266WebServer::sendContent(const String& content) { const char * footer = "\r\n"; size_t len = content.length(); if(_chunked) { - char * chunkSize = (char *)malloc(11); - if(chunkSize){ - sprintf(chunkSize, "%x%s", len, footer); - _currentClientWrite(chunkSize, strlen(chunkSize)); - free(chunkSize); - } + char chunkSize[11]; + sprintf(chunkSize, "%zx\r\n", len); + _currentClientWrite(chunkSize, strlen(chunkSize)); } _currentClientWrite(content.c_str(), len); if(_chunked){ @@ -461,12 +458,9 @@ void ESP8266WebServer::sendContent_P(PGM_P content) { void ESP8266WebServer::sendContent_P(PGM_P content, size_t size) { const char * footer = "\r\n"; if(_chunked) { - char * chunkSize = (char *)malloc(11); - if(chunkSize){ - sprintf(chunkSize, "%x%s", size, footer); - _currentClientWrite(chunkSize, strlen(chunkSize)); - free(chunkSize); - } + char chunkSize[11]; + sprintf(chunkSize, "%zx\r\n", size); + _currentClientWrite(chunkSize, strlen(chunkSize)); } _currentClientWrite_P(content, size); if(_chunked){ diff --git a/libraries/ESP8266WiFi/examples/udp/udp.ino b/libraries/ESP8266WiFi/examples/udp/udp.ino new file mode 100644 index 0000000000..5759905bd2 --- /dev/null +++ b/libraries/ESP8266WiFi/examples/udp/udp.ino @@ -0,0 +1,80 @@ +/* + UDPSendReceive.pde: + This sketch receives UDP message strings, prints them to the serial port + and sends an "acknowledge" string back to the sender + + A Processing sketch is included at the end of file that can be used to send + and received messages for testing with a computer. + + created 21 Aug 2010 + by Michael Margolis + + This code is in the public domain. + + adapted from Ethernet library examples +*/ + + +#include +#include + +#define SSID "ssid" +#define PSK "psk" + +unsigned int localPort = 8888; // local port to listen on + +// buffers for receiving and sending data +char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, +char ReplyBuffer[] = "acknowledged\r\n"; // a string to send back + +WiFiUDP Udp; + +void setup() { + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(SSID, PSK); + while (WiFi.status() != WL_CONNECTED) { + Serial.print('.'); + delay(500); + } + Serial.print("Connected! IP address: "); + Serial.println(WiFi.localIP()); + Serial.printf("UDP server on port %d\n", localPort); + Udp.begin(localPort); +} + +void loop() { + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) { + Serial.print("Received packet of size "); + Serial.println(packetSize); + Serial.print("From "); + IPAddress remote = Udp.remoteIP(); + for (int i = 0; i < 4; i++) { + Serial.print(remote[i], DEC); + if (i < 3) { + Serial.print("."); + } + } + Serial.print(", port "); + Serial.println(Udp.remotePort()); + + // read the packet into packetBufffer + Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE); + Serial.println("Contents:"); + Serial.println(packetBuffer); + + // send a reply, to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); + } + delay(10); +} + +/* + test (shell/netcat): + --------------- + nc -u 192.168.esp.address 8888 +*/ diff --git a/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp b/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp index 16cf99f3b1..024938d213 100644 --- a/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp +++ b/libraries/ESP8266WiFi/src/BearSSLHelpers.cpp @@ -826,6 +826,8 @@ bool X509List::append(const uint8_t *derCert, size_t derLen) { return true; } +#if !CORE_MOCK + // Second stack thunked helpers make_stack_thunk(br_ssl_engine_recvapp_ack); make_stack_thunk(br_ssl_engine_recvapp_buf); @@ -836,4 +838,6 @@ make_stack_thunk(br_ssl_engine_sendapp_buf); make_stack_thunk(br_ssl_engine_sendrec_ack); make_stack_thunk(br_ssl_engine_sendrec_buf); +#endif + }; \ No newline at end of file diff --git a/libraries/ESP8266WiFi/src/WiFiClient.cpp b/libraries/ESP8266WiFi/src/WiFiClient.cpp index 6bb79a4a9b..9ba168e742 100644 --- a/libraries/ESP8266WiFi/src/WiFiClient.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClient.cpp @@ -38,7 +38,7 @@ extern "C" #include "lwip/tcp.h" #include "lwip/inet.h" #include "lwip/netif.h" -#include "include/ClientContext.h" +#include #include "c_types.h" uint16_t WiFiClient::_localPort = 0; diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp index f4589e9e32..fe11be8f39 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp @@ -40,10 +40,12 @@ extern "C" { #include "lwip/tcp.h" #include "lwip/inet.h" #include "lwip/netif.h" -#include "include/ClientContext.h" +#include #include "c_types.h" #include "coredecls.h" +#if !CORE_MOCK + // The BearSSL thunks in use for now #define br_ssl_engine_recvapp_ack thunk_br_ssl_engine_recvapp_ack #define br_ssl_engine_recvapp_buf thunk_br_ssl_engine_recvapp_buf @@ -54,6 +56,8 @@ extern "C" { #define br_ssl_engine_sendrec_ack thunk_br_ssl_engine_sendrec_ack #define br_ssl_engine_sendrec_buf thunk_br_ssl_engine_sendrec_buf +#endif + namespace BearSSL { void WiFiClientSecure::_clear() { @@ -1377,6 +1381,21 @@ bool WiFiClientSecure::loadPrivateKey(Stream& stream, size_t size) { // SSL debugging which should focus on the WiFiClientBearSSL objects. extern "C" { + +#if CORE_MOCK + + void br_esp8266_stack_proxy_init(uint8_t *space, uint16_t size) { + (void)space; + (void)size; + } + void _BearSSLCheckStack(const char *fcn, const char *file, int line) { + (void)fcn; + (void)file; + (void)line; + } + +#else // !CORE_MOCK + extern size_t br_esp8266_stack_proxy_usage(); void _BearSSLCheckStack(const char *fcn, const char *file, int line) { @@ -1386,7 +1405,7 @@ extern "C" { int freeheap = ESP.getFreeHeap(); static int laststack, lastheap, laststack2; if ((laststack != freestack) || (lastheap != freeheap) || (laststack2 != (int)br_esp8266_stack_proxy_usage())) { - Serial.printf("%s:%s(%d): FREESTACK=%d, STACK2USAGE=%d, FREEHEAP=%d\n", file, fcn, line, freestack, br_esp8266_stack_proxy_usage(), freeheap); + Serial.printf("%s:%s(%d): FREESTACK=%d, STACK2USAGE=%zd, FREEHEAP=%d\n", file, fcn, line, freestack, br_esp8266_stack_proxy_usage(), freeheap); if (freestack < 256) { Serial.printf("!!! Out of main stack space\n"); } @@ -1405,6 +1424,8 @@ extern "C" { } } +#endif // !CORE_MOCK + void _BearSSLSerialPrint(const char *str) { static int cnt = 0; Serial.printf("%s", str); diff --git a/libraries/ESP8266WiFi/src/WiFiServer.cpp b/libraries/ESP8266WiFi/src/WiFiServer.cpp index d1178d52d9..9e63da5054 100644 --- a/libraries/ESP8266WiFi/src/WiFiServer.cpp +++ b/libraries/ESP8266WiFi/src/WiFiServer.cpp @@ -35,7 +35,7 @@ extern "C" { #include "lwip/opt.h" #include "lwip/tcp.h" #include "lwip/inet.h" -#include "include/ClientContext.h" +#include WiFiServer::WiFiServer(IPAddress addr, uint16_t port) : _port(port) diff --git a/libraries/ESP8266WiFi/src/WiFiServerSecureBearSSL.cpp b/libraries/ESP8266WiFi/src/WiFiServerSecureBearSSL.cpp index 31d7536bb3..bea13dda01 100644 --- a/libraries/ESP8266WiFi/src/WiFiServerSecureBearSSL.cpp +++ b/libraries/ESP8266WiFi/src/WiFiServerSecureBearSSL.cpp @@ -34,7 +34,7 @@ extern "C" { #include "lwip/opt.h" #include "lwip/tcp.h" #include "lwip/inet.h" -#include "include/ClientContext.h" +#include #include "WiFiServerSecureBearSSL.h" namespace BearSSL { diff --git a/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/libraries/ESP8266WiFi/src/WiFiUdp.cpp index 5e42473089..9be50c1342 100644 --- a/libraries/ESP8266WiFi/src/WiFiUdp.cpp +++ b/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -38,7 +38,7 @@ extern "C" #include "lwip/inet.h" #include "lwip/igmp.h" #include "lwip/mem.h" -#include "include/UdpContext.h" +#include template<> @@ -106,7 +106,9 @@ uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, ui _ctx = new UdpContext; _ctx->ref(); - if (!_ctx->listen(*IP_ADDR_ANY, port)) { + ip_addr_t addr; + addr.addr = INADDR_ANY; + if (!_ctx->listen(addr, port)) { return 0; } @@ -284,7 +286,7 @@ uint16_t WiFiUDP::localPort() void WiFiUDP::stopAll() { for (WiFiUDP* it = _s_first; it; it = it->_next) { - DEBUGV("%s %08x %08x\n", __func__, (uint32_t) it, (uint32_t) _s_first); + DEBUGV("%s %p %p\n", __func__, it, _s_first); it->stop(); } } @@ -292,7 +294,7 @@ void WiFiUDP::stopAll() void WiFiUDP::stopAllExcept(WiFiUDP * exC) { for (WiFiUDP* it = _s_first; it; it = it->_next) { if (it->_ctx != exC->_ctx) { - DEBUGV("%s %08x %08x\n", __func__, (uint32_t) it, (uint32_t) _s_first); + DEBUGV("%s %p %p\n", __func__, it, _s_first); it->stop(); } } diff --git a/libraries/ESP8266WiFi/src/include/SSLContext.h b/libraries/ESP8266WiFi/src/include/SSLContext.h index 4e8cfe11f0..006fcd8743 100644 --- a/libraries/ESP8266WiFi/src/include/SSLContext.h +++ b/libraries/ESP8266WiFi/src/include/SSLContext.h @@ -37,7 +37,7 @@ extern "C" #include "lwip/tcp.h" #include "lwip/inet.h" #include "lwip/netif.h" -#include "include/ClientContext.h" +#include #include "c_types.h" namespace axTLS { diff --git a/libraries/ESP8266WiFi/src/include/UdpContext.h b/libraries/ESP8266WiFi/src/include/UdpContext.h index 2a6310a76e..6503affad0 100644 --- a/libraries/ESP8266WiFi/src/include/UdpContext.h +++ b/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -174,7 +174,7 @@ class UdpContext return 0; udp_hdr* udphdr = GET_UDP_HDR(_rx_buf); - return ntohs(udphdr->src); + return lwip_ntohs(udphdr->src); } uint32_t getDestAddress() @@ -252,6 +252,7 @@ class UdpContext void flush() { + //XXX this does not follow Arduino's flush definition if (!_rx_buf) return; diff --git a/libraries/ESP8266mDNS/ESP8266mDNS.cpp b/libraries/ESP8266mDNS/ESP8266mDNS.cpp index c754a2b8cf..9662b8bb8e 100644 --- a/libraries/ESP8266mDNS/ESP8266mDNS.cpp +++ b/libraries/ESP8266mDNS/ESP8266mDNS.cpp @@ -431,11 +431,11 @@ MDNSTxt * MDNSResponder::_getServiceTxt(char *name, char *proto){ for (servicePtr = _services; servicePtr; servicePtr = servicePtr->_next) { if(servicePtr->_port > 0 && strcmp(servicePtr->_name, name) == 0 && strcmp(servicePtr->_proto, proto) == 0){ if (servicePtr->_txts == 0) - return false; + return nullptr; return servicePtr->_txts; } } - return 0; + return nullptr; } uint16_t MDNSResponder::_getServiceTxtLen(char *name, char *proto){ diff --git a/tests/common.sh b/tests/common.sh index c9e48309e2..dbbb070e1a 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -134,7 +134,7 @@ function build_docs() function run_host_tests() { pushd host - make + make FORCE32=0 OPTZ=-O0 CI make clean-objects popd } diff --git a/tests/host/Makefile b/tests/host/Makefile index 036ed18fcc..667fc15336 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -1,7 +1,12 @@ -BINARY_DIRECTORY := bin +BINDIR := bin LCOV_DIRECTORY := lcov -OUTPUT_BINARY := $(BINARY_DIRECTORY)/host_tests +OUTPUT_BINARY := $(BINDIR)/host_tests CORE_PATH := ../../cores/esp8266 +FORCE32 ?= 1 +OPTZ ?= -Os +V ?= 0 + +MAKEFILE = $(word 1, $(MAKEFILE_LIST)) # I wasn't able to build with clang when -coverage flag is enabled, forcing GCC on OS X ifeq ($(shell uname -s),Darwin) @@ -13,6 +18,36 @@ VALGRIND ?= valgrind LCOV ?= lcov GENHTML ?= genhtml +ifeq ($(FORCE32),1) +ABILITY32 = $(shell echo 'int main(){return sizeof(long);}'|$(CXX) -m32 -x c++ - -o sizeoflong 2>/dev/null && ./sizeoflong; echo $$?; rm -f sizeoflong;) +ifneq ($(ABILITY32),4) +$(warning Cannot compile in 32 bit mode, switching to native mode) +else +N32 = 32 +M32 = -m32 +endif +endif + +ifeq ($(N32),32) +$(warning compiling in 32 bits mode) +else +$(warning compiling in native mode) +endif + +ifeq ($(V), 0) +VERBC = @echo "C $@"; +VERBCXX = @echo "C++ $@"; +VERBLD = @echo "LD $@"; +VERBAR = @echo "AR $@"; +else +VERBC = +VERBCXX = +VERBLD = +VERBAR = +endif + +$(shell mkdir -p $(BINDIR)) + CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\ StreamString.cpp \ Stream.cpp \ @@ -31,12 +66,24 @@ CORE_C_FILES := $(addprefix $(CORE_PATH)/,\ spiffs/spiffs_gc.c \ spiffs/spiffs_hydrogen.c \ spiffs/spiffs_nucleus.c \ + libb64/cencode.c \ ) -MOCK_CPP_FILES := $(addprefix common/,\ +MOCK_CPP_FILES_COMMON := $(addprefix common/,\ Arduino.cpp \ spiffs_mock.cpp \ WMath.cpp \ + MockSerial.cpp \ + MockTools.cpp \ +) + +MOCK_CPP_FILES := $(MOCK_CPP_FILES_COMMON) $(addprefix common/,\ + ArduinoCatch.cpp \ +) + +MOCK_CPP_FILES_EMU := $(MOCK_CPP_FILES_COMMON) $(addprefix common/,\ + ArduinoMain.cpp \ + user_interface.cpp \ ) MOCK_C_FILES := $(addprefix common/,\ @@ -44,21 +91,40 @@ MOCK_C_FILES := $(addprefix common/,\ noniso.c \ ) -INC_PATHS += $(addprefix -I, \ +INC_PATHS := $(addprefix -I,\ common \ $(CORE_PATH) \ ) +INC_PATHS += $(addprefix -I,\ + $(shell echo ../../libraries/*/src) \ + $(shell echo ../../libraries/*) \ + ../../tools/sdk/include \ + ../../tools/sdk/lwip2/include \ +) + TEST_CPP_FILES := \ fs/test_fs.cpp \ core/test_pgmspace.cpp \ core/test_md5builder.cpp \ core/test_string.cpp -CXXFLAGS += -std=c++11 -Wall -Werror -coverage -O0 -fno-common -g -CFLAGS += -std=c99 -Wall -Werror -coverage -O0 -fno-common -g -LDFLAGS += -coverage -O0 +PREINCLUDES := \ + -include common/mock.h \ + -include common/c_types.h \ + +ifneq ($(D),) +OPTZ=-O0 +DEBUG += -DDEBUG_ESP_PORT=Serial +DEBUG += -DDEBUG_ESP_SSL -DDEBUG_ESP_TLS_MEM -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_ESP_MDNS +endif + +CXXFLAGS += $(DEBUG) -std=c++11 -Wall -Werror -coverage $(OPTZ) -fno-common -g $(M32) +CFLAGS += -std=c99 -Wall -Werror -coverage $(OPTZ) -fno-common -g $(M32) +LDFLAGS += -coverage $(OPTZ) -g $(M32) VALGRINDFLAGS += --leak-check=full --track-origins=yes --error-limit=no --show-leak-kinds=all --error-exitcode=999 +CXXFLAGS += -Wno-error=format-security # cores/esp8266/Print.cpp:42:24: error: format not a string literal and no format arguments [-Werror=format-security] -- (os_printf_plus(not_the_best_way)) +#CXXFLAGS += -Wno-format-security # cores/esp8266/Print.cpp:42:40: warning: format not a string literal and no format arguments [-Wformat-security] -- (os_printf_plus(not_the_best_way)) remduplicates = $(strip $(if $1,$(firstword $1) $(call remduplicates,$(filter-out $(firstword $1),$1)))) @@ -74,21 +140,23 @@ CPP_OBJECTS = $(CPP_OBJECTS_CORE) $(CPP_OBJECTS_TESTS) OBJECTS = $(C_OBJECTS) $(CPP_OBJECTS) COVERAGE_FILES = $(OBJECTS:.o=.gc*) -all: build-info $(OUTPUT_BINARY) valgrind test gcov +all: help + +CI: build-info $(OUTPUT_BINARY) valgrind test gcov # run CI -test: $(OUTPUT_BINARY) +test: $(OUTPUT_BINARY) # run host test for CI $(OUTPUT_BINARY) -clean: clean-objects clean-coverage - rm -rf $(BINARY_DIRECTORY) +clean: clean-objects clean-coverage # clean everything + rm -rf $(BINDIR) clean-objects: - rm -rf $(OBJECTS) + rm -rf $(C_OBJECTS) $(CPP_OBJECTS_CORE) $(CPP_OBJECTS_CORE_EMU) $(CPP_OBJECTS_TESTS) clean-coverage: rm -rf $(COVERAGE_FILES) $(LCOV_DIRECTORY) *.gcov -gcov: test +gcov: test # run coverage for CI find $(CORE_PATH) -name "*.gcno" -exec $(GCOV) -r -pb {} + valgrind: $(OUTPUT_BINARY) @@ -98,7 +166,7 @@ valgrind: $(OUTPUT_BINARY) $(LCOV) --directory $(CORE_PATH) --capture --output-file $(LCOV_DIRECTORY)/app.info $(GENHTML) $(LCOV_DIRECTORY)/app.info -o $(LCOV_DIRECTORY) -build-info: +build-info: # show toolchain version @echo "-------- build tools info --------" @echo "CC: " $(CC) $(CC) -v @@ -108,18 +176,147 @@ build-info: $(GCOV) -v @echo "----------------------------------" -$(BINARY_DIRECTORY): - mkdir -p $@ +-include $(BINDIR)/.*.d +.SUFFIXES: -$(C_OBJECTS): %.c.o: %.c - $(CC) $(CFLAGS) $(INC_PATHS) -c -o $@ $< +%.c.o: %.c + $(VERBC) $(CC) $(PREINCLUDES) $(CFLAGS) $(INC_PATHS) -MD -MF $(BINDIR)/.$(notdir $<).d -c -o $@ $< -$(CPP_OBJECTS): %.cpp.o: %.cpp - $(CXX) $(CXXFLAGS) $(INC_PATHS) -c -o $@ $< +.PRECIOUS: %.cpp.o +%.cpp.o: %.cpp + $(VERBCXX) $(CXX) $(PREINCLUDES) $(CXXFLAGS) $(INC_PATHS) -MD -MF $(BINDIR)/.$(notdir $<).d -c -o $@ $< -$(BINARY_DIRECTORY)/core.a: $(C_OBJECTS) $(CPP_OBJECTS_CORE) - ar -rcu $@ $(C_OBJECTS) $(CPP_OBJECTS_CORE) +$(BINDIR)/core.a: $(C_OBJECTS) $(CPP_OBJECTS_CORE) + ar -rcu $@ $^ ranlib -c $@ -$(OUTPUT_BINARY): $(BINARY_DIRECTORY) $(CPP_OBJECTS_TESTS) $(BINARY_DIRECTORY)/core.a - $(CXX) $(LDFLAGS) $(CPP_OBJECTS_TESTS) $(BINARY_DIRECTORY)/core.a $(LIBS) -o $(OUTPUT_BINARY) +$(OUTPUT_BINARY): $(CPP_OBJECTS_TESTS) $(BINDIR)/core.a + $(VERBLD) $(CXX) $(LDFLAGS) $^ -o $@ + +################################################# +# building ino sources + +ARDUINO_LIBS := \ + $(addprefix $(CORE_PATH)/,\ + IPAddress.cpp \ + Updater.cpp \ + ) \ + $(addprefix ../../libraries/,\ + $(addprefix ESP8266WiFi/src/,\ + ESP8266WiFi.cpp \ + ESP8266WiFiAP.cpp \ + ESP8266WiFiGeneric.cpp \ + ESP8266WiFiMulti.cpp \ + ESP8266WiFiSTA-WPS.cpp \ + ESP8266WiFiSTA.cpp \ + ESP8266WiFiScan.cpp \ + WiFiClient.cpp \ + WiFiUdp.cpp \ + WiFiClientSecureBearSSL.cpp \ + WiFiServerSecureBearSSL.cpp \ + BearSSLHelpers.cpp \ + CertStoreBearSSL.cpp \ + ) \ + $(addprefix ESP8266WebServer/src/,\ + ESP8266WebServer.cpp \ + Parsing.cpp \ + detail/mimetable.cpp \ + ) \ + ESP8266mDNS/ESP8266mDNS.cpp \ + ArduinoOTA/ArduinoOTA.cpp \ + DNSServer/src/DNSServer.cpp \ + ESP8266AVRISP/src/ESP8266AVRISP.cpp \ + ESP8266HTTPClient/src/ESP8266HTTPClient.cpp \ + ) \ + +MOCK_ARDUINO_LIBS := \ + common/ClientContextSocket.cpp \ + common/ClientContextTools.cpp \ + common/MockWiFiServerSocket.cpp \ + common/MockWiFiServer.cpp \ + common/UdpContextSocket.cpp \ + common/HostWiring.cpp \ + common/MockEsp.cpp \ + common/MockEEPROM.cpp \ + common/MockSPI.cpp \ + +CPP_SOURCES_CORE_EMU = \ + $(MOCK_CPP_FILES_EMU) \ + $(CORE_CPP_FILES) \ + $(MOCK_ARDUINO_LIBS) \ + $(ARDUINO_LIBS) \ + + +LIBSSLFILE = ../../tools/sdk/ssl/bearssl/build$(N32)/libbearssl.a +ifeq (,$(wildcard $(LIBSSLFILE))) +LIBSSL = +else +LIBSSL = $(LIBSSLFILE) +endif +ssl: # download source and build BearSSL + cd ../../tools/sdk/ssl && make native$(N32) + +ULIBPATHS = $(shell echo $(ULIBDIRS) | sed 's,:, ,g') +USERLIBDIRS = $(shell test -z "$(ULIBPATHS)" || for d in $(ULIBPATHS); do for dd in $$d $$d/src; do test -d $$dd && { echo -I$$dd; echo "userlib: using directory '$$dd'" 1>&2; } done; done) +USERLIBSRCS = $(shell test -z "$(ULIBPATHS)" || for d in $(ULIBPATHS); do for ss in $$d/*.cpp $$d/src/*.cpp; do test -r $$ss && echo $$ss; done; done) +INC_PATHS += $(USERLIBDIRS) +CPP_OBJECTS_CORE_EMU = $(CPP_SOURCES_CORE_EMU:.cpp=.cpp.o) $(USERLIBSRCS:.cpp=.cpp.o) + +bin/fullcore.a: $(C_OBJECTS) $(CPP_OBJECTS_CORE_EMU) + $(VERBAR) ar -rcu $@ $^ + $(VERBAR) ranlib -c $@ + +%: %.ino.cpp.o bin/fullcore.a + $(VERBLD) $(CXX) $(LDFLAGS) $< bin/fullcore.a $(LIBSSL) -o $@ + @echo "----> $@ <----" + +################################################# +# are we in primary make call ? +ifeq ($(INO),) + +%: %.ino + @# recursive 'make' with paths + $(MAKE) -f $(MAKEFILE) INODIR=$(dir $@) INO=$(notdir $@) $(BINDIR)/$(notdir $@)/$(notdir $@) + @# see below the new build rule with fixed output path outside from core location + +##################### +# recursive call on ino targer +else + +$(BINDIR)/$(INO)/$(INO).ino.cpp: + @# arduino builder would come around here (.ino -> .ino.cpp) + @mkdir -p $(BINDIR)/$(INO); \ + ( \ + echo "#include \"$(INODIR)/$(INO).ino\""; \ + for i in $(INODIR)/*.ino; do \ + test "$$i" = $(INODIR)/$(INO).ino || echo "#include \"$$i\""; \ + done; \ + ) > $(BINDIR)/$(INO)/$(INO).ino.cpp + +endif # recursive +##################### + +################################################# + +.PHONY: list +list: # show core example list + @for dir in ../../libraries/*/examples; do \ + exampledir=$${dir%/*}; \ + exampledirname=$${exampledir##*/}; \ + for subdir in $$dir/*; do \ + exname=$${subdir##*/}; \ + echo "$$subdir/$$exname"; \ + done; \ + done; \ + +################################################# +# help + +.PHONY: help +help: + @cat README.txt + @echo "" + @echo "Make rules:" + @echo "" + @sed -rne 's,([^: \t]*):[^=#]*#[\t ]*(.*),\1 - \2,p' $(MAKEFILE) + @echo "" diff --git a/tests/host/README.txt b/tests/host/README.txt new file mode 100644 index 0000000000..8bc0dac85c --- /dev/null +++ b/tests/host/README.txt @@ -0,0 +1,96 @@ + +Host Tests for Continuous Integration +------------------------------------- + + make FORCE32=0 OPTZ=-O0 CI + + (FORCE32=0: https://bugs.launchpad.net/ubuntu/+source/valgrind/+bug/948004) + +Sketch emulation on host +------------------------ + +This environment let compile esp8266/Arduino sketches into native +environment. Network (tcp, udp, including ssl and multicast) is linked to +local host interfaces. WiFi is trivialy emulated and reported as "just" +already connected and usable. + +Currently network emulation is a complete rewrite of +WiFiClient+WiFiServer/ClientContext and WifiUdp/UdpContext using socket +posix API. Further work will optionally propose native lwIP library +instead. + +How to compile and run a sketch +------------------------------- + +All results are stored in ./bin/ . + +Show the core example list: + make list + + +Build one example + make D=1 ../../libraries/esp8266/examples/Blink/Blink +run it: + ./bin/Blink/Blink -h + + +Optional 'V=1' enables makefile verbosity +Optional 'D=1' enables core debug (same as IDE's tools menu) +Optional 'OPTZ=-O2' will update gcc -O option (default is -Os, D=1 implies -O0) +Optional 'FORCE32=0' will use native/default gcc (default is FORCE32=1 unless gcc-multilib is not detected) + + +Non exhaustive list of working examples: + make D=1 ../../libraries/ESP8266WiFi/examples/udp/udp + make D=1 ../../libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient + make D=1 ../../libraries/ESP8266WebServer/examples/HelloServer/HelloServer + make D=1 ../../libraries/ESP8266WebServer/examples/AdvancedWebServer/AdvancedWebServer + make D=1 ../../libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server + make D=1 ../../libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation + +Compile other sketches: +- library paths are specified using ULIBDIRS variable, separated by ':' +- call 'make path-to-the-sketch-file' to build (without its '.ino' extension): +- CAVEAT: functions must be declared *before* being called (arduino builder is not around) + + make D=1 ULIBDIRS=/path/to/your/arduino/libraries/lib1:/path/to/another/place/lib2 /path/to/your/sketchdir/sketch/sketch + or: + ULIBDIRS=/path/to/your/arduino/libraries/lib1:/path/to/another/place/lib2 make D=1 /path/to/your/sketchdir/sketch/sketch + + or (preferred): + export ULIBDIRS=/path/to/your/arduino/libraries/lib1:/path/to/another/place/lib2 + export D=1 + export OPTZ=-O2 + make clean + make /path/to/your/sketchdir/sketch/sketch + ./bin/sketch/sketch + + +Executable location is always in bin/. Once a sketch is compiled, just run it: + bin/sketch/sketch + +Options are available: + -h + -i eth0 bind servers to this interface (WIP) + -l bind Multicast to the above interface (WIP) + -f no throttle (possibly 100%CPU) + +TODO +---- +A lot. +Make fun, propose PRs. + +- replace some "fprintf(stderr" with redirectable log functions +- spiffs in a file (done, need to initialize and check) +- EEPROM in a file (partly done) +- SDCARD on Host filesystem ? or in an image ? +- nice curses interface to display/change gpios ? +- display device emulation (like ssd1306) +- optionaly use arduino-builder ? +- store sketch objects and binaries outside from the source directories (done for sketches) +- compile and use lwIP on host +- easily debug HTTP classes +- https://github.com/esp8266/Arduino/issues/1715 +- gpio, currently: + read as 0(digital) or 512(analog). + output is printed on console. diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp index c1b141bc73..b758ec7201 100644 --- a/tests/host/common/Arduino.cpp +++ b/tests/host/common/Arduino.cpp @@ -13,11 +13,10 @@ all copies or substantial portions of the Software. */ -#define CATCH_CONFIG_MAIN -#include #include #include "Arduino.h" +#include extern "C" unsigned long millis() { @@ -26,11 +25,22 @@ extern "C" unsigned long millis() return (time.tv_sec * 1000) + (time.tv_usec / 1000); } +extern "C" unsigned long micros() +{ + timeval time; + gettimeofday(&time, NULL); + return (time.tv_sec * 1000000) + time.tv_usec; +} + extern "C" void yield() { } +extern "C" void esp_yield() +{ +} + extern "C" void __panic_func(const char* file, int line, const char* func) { abort(); @@ -38,4 +48,10 @@ extern "C" void __panic_func(const char* file, int line, const char* func) { extern "C" void delay(unsigned long ms) { + usleep(ms * 1000); +} + +extern "C" void delayMicroseconds(unsigned int us) +{ + usleep(us); } diff --git a/tests/host/common/Arduino.h b/tests/host/common/Arduino.h index e68565ee82..34b6dc2402 100644 --- a/tests/host/common/Arduino.h +++ b/tests/host/common/Arduino.h @@ -20,6 +20,8 @@ #ifndef Arduino_h #define Arduino_h +#define MOCK "mock: " + #ifdef __cplusplus extern "C" { #endif diff --git a/tests/host/common/ArduinoCatch.cpp b/tests/host/common/ArduinoCatch.cpp new file mode 100644 index 0000000000..6a1e3cca23 --- /dev/null +++ b/tests/host/common/ArduinoCatch.cpp @@ -0,0 +1,20 @@ +/* + Arduino.cpp - Mocks for common Arduino APIs + Copyright © 2016 Ivan Grokhotkov + + Permission is hereby granted, 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. +*/ + +#define CATCH_CONFIG_MAIN +#include +#include +#include "Arduino.h" + diff --git a/tests/host/common/ArduinoMain.cpp b/tests/host/common/ArduinoMain.cpp new file mode 100644 index 0000000000..900b865aef --- /dev/null +++ b/tests/host/common/ArduinoMain.cpp @@ -0,0 +1,143 @@ +/* + Arduino emulator main loop + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include +#include // wifi_get_ip_info() + +#include +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include +#include + +#include // usleep +#include + +#include + +#if 0 +#include "../common/spiffs_mock.h" +#include +SPIFFS_MOCK_DECLARE(/*size_kb*/1024, /(blovk_kb*/8, /*page_b*/512); +#endif + +std::map udps; + +void register_udp (int sock, UdpContext* udp) +{ + if (udp) + udps[sock] = udp; + else + udps.erase(sock); +} + +const char* host_interface = nullptr; + +void help (const char* argv0, int exitcode) +{ + printf( + "%s - compiled with esp8266/arduino emulator\n" + "options:\n" + " -h\n" + " -i - use this interface for IP address\n" + " -l - bind tcp/udp servers to interface only (not 0.0.0.0)\n" + " -f - no throttle (possibly 100%%CPU)\n" + , argv0); + exit(exitcode); +} + +static struct option options[] = +{ + { "help", no_argument, NULL, 'h' }, + { "fast", no_argument, NULL, 'f' }, + { "local", no_argument, NULL, 'l' }, + { "interface", required_argument, NULL, 'i' }, +}; + +int main (int argc, char* const argv []) +{ + bool fast = false; + + for (;;) + { + int n = getopt_long(argc, argv, "hlfi:", options, NULL); + if (n < 0) + break; + switch (n) + { + case 'h': + help(argv[0], EXIT_SUCCESS); + break; + case 'i': + host_interface = optarg; + break; + case 'l': + global_ipv4_netfmt = NO_GLOBAL_BINDING; + break; + case 'f': + fast = true; + break; + default: + fprintf(stderr, MOCK "bad option '%c'\n", n); + exit(EXIT_FAILURE); + } + } + + // setup global global_ipv4_netfmt + wifi_get_ip_info(0, nullptr); + + setup(); + while (true) + { + if (!fast) + usleep(10000); // not 100% cpu + + loop(); + + // check incoming udp + for (auto& udp: udps) + { + pollfd p; + p.fd = udp.first; + p.events = POLLIN; + if (poll(&p, 1, 0) && p.revents == POLLIN) + { + fprintf(stderr, MOCK "UDP poll(%d) -> cb\r", p.fd); + udp.second->mock_cb(); + } + } + } + return 0; +} + diff --git a/tests/host/common/ClientContextSocket.cpp b/tests/host/common/ClientContextSocket.cpp new file mode 100644 index 0000000000..b2b6906fd0 --- /dev/null +++ b/tests/host/common/ClientContextSocket.cpp @@ -0,0 +1,151 @@ + +/* + Arduino emulation - socket part of ClientContext + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ +// separated from lwIP to avoid type conflicts + +#include +#include +#include +#include +#include +#include +#include + +int mockConnect (uint32_t ipv4, int& sock, int port) +{ + struct sockaddr_in server; + if ((sock = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + perror(MOCK "ClientContext:connect: ::socket()"); + return 0; + } + server.sin_family = AF_INET; + server.sin_port = htons(port); + memcpy(&server.sin_addr, &ipv4, 4); + if (::connect(sock, (struct sockaddr*)&server, sizeof(server)) == -1) + { + perror(MOCK "ClientContext::connect: ::connect()"); + return 0; + } + + if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) + { + fprintf(stderr, MOCK "ClientContext::connect: fcntl(O_NONBLOCK): %s\n", strerror(errno)); + close(sock); + return 0; + } + + return 1; +} + +size_t mockFillInBuf (int sock, char* ccinbuf, size_t& ccinbufsize) +{ + size_t maxread = CCBUFSIZE - ccinbufsize; + ssize_t ret = ::read(sock, ccinbuf + ccinbufsize, maxread); + if (ret == -1) + { + if (errno != EAGAIN) + fprintf(stderr, MOCK "ClientContext::(read/peek): filling buffer for %zd bytes: %s\n", maxread, strerror(errno)); + ret = 0; + } + return ccinbufsize += ret; +} + +size_t mockPeekBytes (int sock, char* dst, size_t usersize, int timeout_ms, char* ccinbuf, size_t& ccinbufsize) +{ + if (usersize > CCBUFSIZE) + fprintf(stderr, MOCK "CCBUFSIZE(%d) should be increased by %zd bytes (-> %zd)\n", CCBUFSIZE, usersize - CCBUFSIZE, usersize); + + struct pollfd p; + size_t retsize = 0; + do + { + if (usersize <= ccinbufsize) + { + // data already buffered + retsize = usersize; + break; + } + + // check incoming data data + mockFillInBuf(sock, ccinbuf, ccinbufsize); + if (usersize <= ccinbufsize) + { + // data just received + retsize = usersize; + break; + } + + // wait for more data until timeout + p.fd = sock; + p.events = POLLIN; + } while (poll(&p, 1, timeout_ms) == 1); + + memcpy(dst, ccinbuf, retsize); + return retsize; +} + +size_t mockRead (int sock, char* dst, size_t size, int timeout_ms, char* ccinbuf, size_t& ccinbufsize) +{ + size_t copied = mockPeekBytes(sock, dst, size, timeout_ms, ccinbuf, ccinbufsize); + // swallow (XXX use a circular buffer) + memmove(ccinbuf, ccinbuf + copied, ccinbufsize - copied); + ccinbufsize -= copied; + return copied; +} + +size_t mockWrite (int sock, const uint8_t* data, size_t size, int timeout_ms) +{ + struct pollfd p; + p.fd = sock; + p.events = POLLOUT; + int ret = poll(&p, 1, timeout_ms); + if (ret == -1) + { + fprintf(stderr, MOCK "ClientContext::write: poll(%d): %s\n", sock, strerror(errno)); + return 0; + } + if (ret) + { + ret = ::write(sock, data, size); + if (ret == -1) + { + fprintf(stderr, MOCK "ClientContext::read: write(%d): %s\n", sock, strerror(errno)); + return 0; + } + if (ret != (int)size) + { + fprintf(stderr, MOCK "ClientContext::write: short write (%d < %zd) (TODO)\n", ret, size); + exit(EXIT_FAILURE); + } + } + return ret; +} diff --git a/tests/host/common/ClientContextTools.cpp b/tests/host/common/ClientContextTools.cpp new file mode 100644 index 0000000000..ccc06b56d9 --- /dev/null +++ b/tests/host/common/ClientContextTools.cpp @@ -0,0 +1,57 @@ +/* + Arduino emulation - part of ClientContext + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#include // gethostbyname + +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg) +{ + (void)callback_arg; + (void)found; + struct hostent* hbn = gethostbyname(hostname); + if (!hbn) + return ERR_TIMEOUT; + addr->addr = *(uint32_t*)hbn->h_addr_list[0]; + return ERR_OK; +} + +static struct tcp_pcb mock_tcp_pcb; +tcp_pcb* tcp_new (void) +{ + // this is useless + // ClientContext is setting the source port and we don't care here + return &mock_tcp_pcb; +} diff --git a/tests/host/common/EEPROM.h b/tests/host/common/EEPROM.h new file mode 100644 index 0000000000..a1e47546de --- /dev/null +++ b/tests/host/common/EEPROM.h @@ -0,0 +1,81 @@ +/* + Arduino EEPROM emulation + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#ifndef EEPROM_MOCK +#define EEPROM_MOCK + +class EEPROMClass { +public: + EEPROMClass(uint32_t sector); + EEPROMClass(void); + ~EEPROMClass(); + + void begin(size_t size); + uint8_t read(int address); + void write(int address, uint8_t val); + bool commit(); + void end(); + + template + T& get(int const address, T& t) + { + if (address < 0 || address + sizeof(T) > _size) + return t; + for (size_t i = 0; i < sizeof(T); i++) + ((uint8_t*)&t)[i] = read(i); + return t; + } + + template + const T& put(int const address, const T& t) + { + if (address < 0 || address + sizeof(T) > _size) + return t; + for (size_t i = 0; i < sizeof(T); i++) + write(i, ((uint8_t*)&t)[i]); + return t; + } + + size_t length() { return _size; } + + //uint8_t& operator[](int const address) { return read(address); } + uint8_t operator[] (int address) { return read(address); } + +protected: + size_t _size = 0; + int _fd = -1; +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) +extern EEPROMClass EEPROM; +#endif + +#endif diff --git a/tests/host/common/HostWiring.cpp b/tests/host/common/HostWiring.cpp new file mode 100644 index 0000000000..3d82cc7959 --- /dev/null +++ b/tests/host/common/HostWiring.cpp @@ -0,0 +1,71 @@ +/* + Arduino: wire emulation + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include + +void pinMode (uint8_t pin, uint8_t mode) +{ + #define xxx(mode) case mode: m=STRHELPER(mode); break + const char* m; + switch (mode) + { + case INPUT: m="INPUT"; break; + case OUTPUT: m="OUTPUT"; break; + case INPUT_PULLUP: m="INPUT_PULLUP"; break; + case OUTPUT_OPEN_DRAIN: m="OUTPUT_OPEN_DRAIN"; break; + case INPUT_PULLDOWN_16: m="INPUT_PULLDOWN_16"; break; + case WAKEUP_PULLUP: m="WAKEUP_PULLUP"; break; + case WAKEUP_PULLDOWN: m="WAKEUP_PULLDOWN"; break; + default: m="(special)"; + } + fprintf(stderr, MOCK "gpio%d: mode='%s'\n", pin, m); +} + +void digitalWrite(uint8_t pin, uint8_t val) +{ + fprintf(stderr, MOCK "digitalWrite(pin=%d val=%d)\n", pin, val); +} + +void analogWrite(uint8_t pin, int val) +{ + fprintf(stderr, MOCK "analogWrite(pin=%d, val=%d\n", pin, val); +} + +int analogRead(uint8_t pin) +{ + (void)pin; + return 512; +} + +void analogWriteRange(uint32_t range) +{ + fprintf(stderr, MOCK "analogWriteRange(range=%d)\n", range); +} diff --git a/tests/host/common/MockEEPROM.cpp b/tests/host/common/MockEEPROM.cpp new file mode 100644 index 0000000000..6357c73dd2 --- /dev/null +++ b/tests/host/common/MockEEPROM.cpp @@ -0,0 +1,97 @@ +/* + Arduino emulation - EEPROM + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#ifndef __EEPROM_H +#define __EEPROM_H + +#include + +#include +#include +#include +#include +#include + +#define EEPROM_FILE_NAME "eeprom" + +EEPROMClass::EEPROMClass () +{ +} + +EEPROMClass::~EEPROMClass () +{ + if (_fd >= 0) + close(_fd); +} + +void EEPROMClass::begin(size_t size) +{ + _size = size; + if ( (_fd = open(EEPROM_FILE_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1 + || ftruncate(_fd, size) == -1) + { + fprintf(stderr, MOCK "EEPROM: cannot open/create '%s' for r/w: %s\n\r", EEPROM_FILE_NAME, strerror(errno)); + _fd = -1; + } +} + +void EEPROMClass::end() +{ + if (_fd != -1) + close(_fd); +} + +bool EEPROMClass::commit() +{ + return true; +} + +uint8_t EEPROMClass::read (int x) +{ + char c = 0; + if (pread(_fd, &c, 1, x) != 1) + fprintf(stderr, MOCK "eeprom: %s\n\r", strerror(errno)); + return c; +} + +void EEPROMClass::write (int x, uint8_t c) +{ + if (x > (int)_size) + fprintf(stderr, MOCK "### eeprom beyond\r\n"); + else if (pwrite(_fd, &c, 1, x) != 1) + fprintf(stderr, MOCK "eeprom: %s\n\r", strerror(errno)); +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) +EEPROMClass EEPROM; +#endif + +#endif diff --git a/tests/host/common/MockEsp.cpp b/tests/host/common/MockEsp.cpp new file mode 100644 index 0000000000..12cb37686f --- /dev/null +++ b/tests/host/common/MockEsp.cpp @@ -0,0 +1,183 @@ +/* + Arduino emulation - esp8266's core + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include +#include + +#include + +unsigned long long operator"" _kHz(unsigned long long x) { + return x * 1000; +} + +unsigned long long operator"" _MHz(unsigned long long x) { + return x * 1000 * 1000; +} + +unsigned long long operator"" _GHz(unsigned long long x) { + return x * 1000 * 1000 * 1000; +} + +unsigned long long operator"" _kBit(unsigned long long x) { + return x * 1024; +} + +unsigned long long operator"" _MBit(unsigned long long x) { + return x * 1024 * 1024; +} + +unsigned long long operator"" _GBit(unsigned long long x) { + return x * 1024 * 1024 * 1024; +} + +unsigned long long operator"" _kB(unsigned long long x) { + return x * 1024; +} + +unsigned long long operator"" _MB(unsigned long long x) { + return x * 1024 * 1024; +} + +unsigned long long operator"" _GB(unsigned long long x) { + return x * 1024 * 1024 * 1024; +} + +uint32_t _SPIFFS_start; + +void eboot_command_write (struct eboot_command* cmd) +{ + (void)cmd; +} + +EspClass ESP; + +void EspClass::restart () +{ + fprintf(stderr, MOCK "Esp.restart(): exiting\n"); + exit(EXIT_SUCCESS); +} + +uint32_t EspClass::getChipId() +{ + return 0xee1337; +} + +bool EspClass::checkFlashConfig(bool needsEquals) +{ + return true; +} + +uint32_t EspClass::getSketchSize() +{ + return 400000; +} + +uint32_t EspClass::getFreeHeap() +{ + return 30000; +} + +bool EspClass::flashEraseSector(uint32_t sector) +{ + return true; +} + +FlashMode_t EspClass::getFlashChipMode() +{ + return FM_DOUT; +} + +FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) +{ + return FM_DOUT; +} + +bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) +{ + (void)offset; + (void)data; + (void)size; + return true; +} + +bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size) +{ + (void)offset; + (void)data; + (void)size; + return true; +} + +uint32_t EspClass::magicFlashChipSize(uint8_t byte) { + switch(byte & 0x0F) { + case 0x0: // 4 Mbit (512KB) + return (512_kB); + case 0x1: // 2 MBit (256KB) + return (256_kB); + case 0x2: // 8 MBit (1MB) + return (1_MB); + case 0x3: // 16 MBit (2MB) + return (2_MB); + case 0x4: // 32 MBit (4MB) + return (4_MB); + case 0x8: // 64 MBit (8MB) + return (8_MB); + case 0x9: // 128 MBit (16MB) + return (16_MB); + default: // fail? + return 0; + } +} + +uint32_t EspClass::getFlashChipRealSize(void) +{ + return magicFlashChipSize(4); +} + +uint32_t EspClass::getFlashChipSize(void) +{ + return magicFlashChipSize(4); +} + +String EspClass::getFullVersion () +{ + return "host-emulation"; +} + +uint32_t EspClass::getFreeContStack() +{ + return 4000; +} + +void EspClass::resetFreeContStack() +{ +} + diff --git a/tests/host/common/MockSPI.cpp b/tests/host/common/MockSPI.cpp new file mode 100644 index 0000000000..251cad914a --- /dev/null +++ b/tests/host/common/MockSPI.cpp @@ -0,0 +1,63 @@ +/* + Arduino emulation - spi + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPI) +SPIClass SPI; +#endif + +SPIClass::SPIClass () +{ +} + +uint8_t SPIClass::transfer(uint8_t data) +{ + return data; +} + +void SPIClass::begin() +{ +} + +void SPIClass::end() +{ +} + +void SPIClass::setFrequency(uint32_t freq) +{ + (void)freq; +} + +void SPIClass::setHwCs(bool use) +{ + (void)use; +} diff --git a/tests/host/common/MockSerial.cpp b/tests/host/common/MockSerial.cpp new file mode 100644 index 0000000000..4aa097a0cd --- /dev/null +++ b/tests/host/common/MockSerial.cpp @@ -0,0 +1,112 @@ +/* + Arduino Hardware Serial emulation + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include + +#include // write + +HardwareSerial Serial(UART0); + +HardwareSerial::HardwareSerial (int uart_nr) +{ + if (uart_nr != 0) + fprintf(stderr, MOCK "FIXME HardwareSerial::HardwareSerial(%d)\n", uart_nr); +} + +void HardwareSerial::begin (unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) +{ + if (config != SERIAL_8N1 || mode != SERIAL_FULL || tx_pin != 1) + fprintf(stderr, MOCK "FIXME HardwareSerial::begin(baud=%ld config=0x%x mode=0x%x)\n", baud, (int)config, (int)mode); +} + +void HardwareSerial::setDebugOutput (bool on) +{ + (void)on; +} + +int HardwareSerial::available (void) +{ + printf(MOCK "TODO HardwareSerial::available\n"); + return 0; +} + +void HardwareSerial::flush () +{ + //XXXTODO + fflush(stdout); +} + +// uart.c + +extern "C" +{ + +size_t uart_write_char (uart_t* uart, char c) +{ + //XXXTODO + (void)uart; + return write(1, &c, 1); +} + +int uart_peek_char (uart_t* uart) +{ + ///XXXTODO + static bool notimpl = false; + if (!notimpl) + { + notimpl = true; + fprintf(stderr, MOCK "FIXME uart_peek_char\n"); + } + (void)uart; + return -1; +} + +int uart_read_char (uart_t* uart) +{ + ///XXXTODO + static bool notimpl = false; + if (!notimpl) + { + notimpl = true; + fprintf(stderr, MOCK "FIXME uart_read_char\n"); + } + (void)uart; + return -1; +} + +size_t uart_write (uart_t* uart, const char* buf, size_t size) +{ + ///XXXTODO + (void)uart; + return write(1, buf, size); +} + +} // extern "C" diff --git a/tests/host/common/MockTools.cpp b/tests/host/common/MockTools.cpp new file mode 100644 index 0000000000..ca257891b2 --- /dev/null +++ b/tests/host/common/MockTools.cpp @@ -0,0 +1,79 @@ +/* + Arduino emulation - tools + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include +#include + +extern "C" +{ + +uint32_t lwip_htonl (uint32_t hostlong) { return htonl(hostlong); } +uint16_t lwip_htons (uint16_t hostshort) { return htons(hostshort); } +uint32_t lwip_ntohl (uint32_t netlong) { return ntohl(netlong); } +uint16_t lwip_ntohs (uint16_t netshort) { return ntohs(netshort); } + +char* ets_strcpy (char* d, const char* s) { return strcpy(d, s); } +size_t ets_strlen (const char* s) { return strlen(s); } + +int ets_printf (const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int len = vprintf(fmt, ap); + va_end(ap); + return len; +} + +extern "C" void configTime(long timezone, int daylightOffset_sec, + const char* server1, const char* server2, const char* server3) +{ + (void)server1; + (void)server2; + (void)server3; + + fprintf(stderr, MOCK "configTime: TODO (tz=%ldH offset=%dS) (time will be host's)\n", timezone, daylightOffset_sec); +} + +void stack_thunk_add_ref() { } +void stack_thunk_del_ref() { } +void stack_thunk_repaint() { } + +uint32_t stack_thunk_get_refcnt() { return 0; } +uint32_t stack_thunk_get_stack_top() { return 0; } +uint32_t stack_thunk_get_stack_bot() { return 0; } +uint32_t stack_thunk_get_cont_sp() { return 0; } +uint32_t stack_thunk_get_max_usage() { return 0; } +void stack_thunk_dump_stack() { } + +// Thunking macro +#define make_stack_thunk(fcnToThunk) + +}; diff --git a/tests/host/common/MockWiFiServer.cpp b/tests/host/common/MockWiFiServer.cpp new file mode 100644 index 0000000000..5a03f8d87d --- /dev/null +++ b/tests/host/common/MockWiFiServer.cpp @@ -0,0 +1,82 @@ +/* + Arduino emulation - WiFiServer + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include +#include + +#include +#include + +#include + +extern "C" const ip_addr_t ip_addr_any = IPADDR4_INIT(IPADDR_ANY); + +#define int2pcb(x) ((tcp_pcb*)(intptr_t)(x)) +#define pcb2int(x) ((int)(intptr_t)(x)) + +// lwIP API side of WiFiServer + +WiFiServer::WiFiServer (IPAddress addr, uint16_t port) +{ + (void)addr; + if (port < 1024) + { + int newport = port + 9000; + fprintf(stderr, MOCK "WiFiServer port: %d -> %d\n", port, newport); + port = newport; + } + _port = port; +} + +WiFiServer::WiFiServer (uint16_t port) +{ + if (port < 1024) + { + int newport = port + 9000; + fprintf(stderr, MOCK "WiFiServer port: %d -> %d\n", port, newport); + port = newport; + } + _port = port; +} + +WiFiClient WiFiServer::available (uint8_t* status) +{ + (void)status; + if (hasClient()) + return WiFiClient(new ClientContext(serverAccept(pcb2int(_pcb)))); + return WiFiClient(); +} + +// static declaration + +#include +uint32_t UdpContext::staticMCastAddr = 0; + diff --git a/tests/host/common/MockWiFiServerSocket.cpp b/tests/host/common/MockWiFiServerSocket.cpp new file mode 100644 index 0000000000..37ace3bf4c --- /dev/null +++ b/tests/host/common/MockWiFiServerSocket.cpp @@ -0,0 +1,127 @@ +/* + Arduino emulation - WiFiServer socket side + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include + +#include +#include +#include +#include +#include + +#define int2pcb(x) ((tcp_pcb*)(intptr_t)(x)) +#define pcb2int(x) ((int)(intptr_t)(x)) + +// host socket internal side of WiFiServer + +int serverAccept (int srvsock) +{ + int clisock; + socklen_t n; + struct sockaddr_in client; + n = sizeof(client); + if ((clisock = accept(srvsock, (struct sockaddr*)&client, &n)) == -1) + { + perror("accept()"); + exit(EXIT_FAILURE); + } + return clisock; +} + +void WiFiServer::begin (uint16_t port) +{ + _port = port; + return begin(); +} + +void WiFiServer::begin () +{ + int sock; + struct sockaddr_in server; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + perror(MOCK "socket()"); + exit(EXIT_FAILURE); + } + + int optval = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) == -1) + { + perror(MOCK "reuseport"); + exit(EXIT_FAILURE); + } + + server.sin_family = AF_INET; + server.sin_port = htons(_port); + server.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(sock, (struct sockaddr*)&server, sizeof(server)) == -1) + { + perror(MOCK "bind()"); + exit(EXIT_FAILURE); + } + + if (listen(sock, 1) == -1) + { + perror(MOCK "listen()"); + exit(EXIT_FAILURE); + } + + + // store int into pointer + _pcb = int2pcb(sock); +} + +bool WiFiServer::hasClient () +{ + struct pollfd p; + p.fd = pcb2int(_pcb); + p.events = POLLIN; + return poll(&p, 1, 0) && p.revents == POLLIN; +} + +size_t WiFiServer::write (uint8_t c) +{ + return write(&c, 1); +} + +size_t WiFiServer::write (const uint8_t *buf, size_t size) +{ + fprintf(stderr, MOCK "todo: WiFiServer::write(%p, %zd)\n", buf, size); + return 0; +} + +void WiFiServer::close () +{ + if (pcb2int(_pcb) >= 0) + ::close(pcb2int(_pcb)); + _pcb = int2pcb(-1); +} diff --git a/tests/host/common/UdpContextSocket.cpp b/tests/host/common/UdpContextSocket.cpp new file mode 100644 index 0000000000..d30a6c1246 --- /dev/null +++ b/tests/host/common/UdpContextSocket.cpp @@ -0,0 +1,182 @@ +/* + Arduino emulation - UdpContext emulation - socket part + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +int mockUDPSocket () +{ + int s; + if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1 || fcntl(s, F_SETFL, O_NONBLOCK) == -1) + { + fprintf(stderr, MOCK "UDP socket: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + return s; +} + +bool mockUDPListen (int sock, uint32_t dstaddr, uint16_t port, uint32_t mcast) +{ + int optval = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) == -1) + fprintf(stderr, MOCK "SO_REUSEPORT failed\n"); + optval = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) + fprintf(stderr, MOCK "SO_REUSEADDR failed\n"); + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + + // Filling server information + servaddr.sin_family = AF_INET; + //servaddr.sin_addr.s_addr = global_ipv4_netfmt?: dstaddr; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(port); + + // Bind the socket with the server address + if (bind(sock, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) + { + fprintf(stderr, MOCK "UDP bind on port %d failed: %s\n", port, strerror(errno)); + return false; + } + else + fprintf(stderr, MOCK "UDP server on port %d (sock=%d)\n", (int)port, sock); + + if (mcast) + { + // https://web.cs.wpi.edu/~claypool/courses/4514-B99/samples/multicast.c + // https://stackoverflow.com/questions/12681097/c-choose-interface-for-udp-multicast-socket + + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = mcast; + //mreq.imr_interface.s_addr = global_ipv4_netfmt?: htonl(INADDR_ANY); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (global_ipv4_netfmt) + { + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, host_interface, strlen(host_interface)) == -1) + fprintf(stderr, MOCK "UDP multicast: can't setup bind/output on interface %s: %s\n", host_interface, strerror(errno)); + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreq.imr_interface, sizeof(struct in_addr)) == -1) + fprintf(stderr, MOCK "UDP multicast: can't setup bind/input on interface %s: %s\n", host_interface, strerror(errno)); + } + + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + fprintf(stderr, MOCK "can't join multicast group addr %08x\n", (int)mcast); + return false; + } + } + + return true; +} + + +size_t mockUDPFillInBuf (int sock, char* ccinbuf, size_t& ccinbufsize, uint8_t& addrsize, uint8_t addr[16], uint16_t& port) +{ + struct sockaddr_storage addrbuf; + socklen_t addrbufsize = std::min((socklen_t)sizeof(addrbuf), (socklen_t)16); + + size_t maxread = CCBUFSIZE - ccinbufsize; + ssize_t ret = ::recvfrom(sock, ccinbuf + ccinbufsize, maxread, 0/*flags*/, (sockaddr*)&addrbuf, &addrbufsize); + if (ret == -1) + { + if (errno != EAGAIN) + fprintf(stderr, MOCK "UDPContext::(read/peek): filling buffer for %zd bytes: %s\n", maxread, strerror(errno)); + ret = 0; + } + + if (ret > 0) + { + port = ntohs(((sockaddr_in*)&addrbuf)->sin_port); + if (addrbuf.ss_family == AF_INET) + memcpy(&addr[0], &(((sockaddr_in*)&addrbuf)->sin_addr.s_addr), addrsize = 4); + else + { + fprintf(stderr, MOCK "TODO UDP+IPv6\n"); + exit(EXIT_FAILURE); + } + } + + return ccinbufsize += ret; +} + +size_t mockUDPPeekBytes (int sock, char* dst, size_t usersize, int timeout_ms, char* ccinbuf, size_t& ccinbufsize) +{ + if (usersize > CCBUFSIZE) + fprintf(stderr, MOCK "CCBUFSIZE(%d) should be increased by %zd bytes (-> %zd)\n", CCBUFSIZE, usersize - CCBUFSIZE, usersize); + + size_t retsize = 0; + if (ccinbufsize) + { + // data already buffered + retsize = usersize; + if (retsize > ccinbufsize) + retsize = ccinbufsize; + } + memcpy(dst, ccinbuf, retsize); + return retsize; +} + +size_t mockUDPRead (int sock, char* dst, size_t size, int timeout_ms, char* ccinbuf, size_t& ccinbufsize) +{ + size_t copied = mockUDPPeekBytes(sock, dst, size, timeout_ms, ccinbuf, ccinbufsize); + // swallow (XXX use a circular buffer?) + memmove(ccinbuf, ccinbuf + copied, ccinbufsize - copied); + ccinbufsize -= copied; + return copied; +} + +size_t mockUDPWrite (int sock, const uint8_t* data, size_t size, int timeout_ms, uint32_t ipv4, uint16_t port) +{ + // Filling server information + struct sockaddr_in peer; + peer.sin_family = AF_INET; + peer.sin_addr.s_addr = ipv4; //XXFIXME should use lwip_htonl? + peer.sin_port = htons(port); + int ret = ::sendto(sock, data, size, 0/*flags*/, (const sockaddr*)&peer, sizeof(peer)); + if (ret == -1) + { + fprintf(stderr, MOCK "UDPContext::write: write(%d): %s\n", sock, strerror(errno)); + return 0; + } + if (ret != (int)size) + { + fprintf(stderr, MOCK "UDPContext::write: short write (%d < %zd) (TODO)\n", ret, size); + exit(EXIT_FAILURE); + } + + return ret; +} diff --git a/tests/host/common/WMath.cpp b/tests/host/common/WMath.cpp index d564ea8e97..4fdf07fa2e 100644 --- a/tests/host/common/WMath.cpp +++ b/tests/host/common/WMath.cpp @@ -25,6 +25,7 @@ extern "C" { #include +#include } void randomSeed(unsigned long seed) { @@ -52,10 +53,10 @@ long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } -unsigned int makeWord(unsigned int w) { +uint16_t makeWord(unsigned int w) { return w; } -unsigned int makeWord(unsigned char h, unsigned char l) { +uint16_t makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } diff --git a/tests/host/common/c_types.h b/tests/host/common/c_types.h new file mode 100644 index 0000000000..765e307a95 --- /dev/null +++ b/tests/host/common/c_types.h @@ -0,0 +1,115 @@ + +// This is a copy of SDK's "c_type.h" +// with conflicting declarations commented out +// (search CONFLICT in this file) + +// diff -u common/c_types.h ../../tools/sdk/include/c_types.h + +/* + * 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 _C_TYPES_H_ +#define _C_TYPES_H_ +#include +#include +#include +#include + +typedef signed char sint8_t; +typedef signed short sint16_t; +typedef signed long sint32_t; +typedef signed long long sint64_t; +// CONFLICT typedef unsigned long long u_int64_t; +typedef float real32_t; +typedef double real64_t; + +typedef unsigned char uint8; +typedef unsigned char u8; +typedef signed char sint8; +typedef signed char int8; +typedef signed char s8; +typedef unsigned short uint16; +typedef unsigned short u16; +typedef signed short sint16; +typedef signed short s16; +typedef unsigned int uint32; +typedef unsigned int u_int; +typedef unsigned int u32; +typedef signed int sint32; +typedef signed int s32; +typedef int int32; +typedef signed long long sint64; +typedef unsigned long long uint64; +typedef unsigned long long u64; +typedef float real32; +typedef double real64; + +#define __le16 u16 + +#define LOCAL static + +#ifndef NULL +#define NULL (void *)0 +#endif /* NULL */ + +/* probably should not put STATUS here */ +typedef enum { + OK = 0, + FAIL, + PENDING, + BUSY, + CANCEL, +} STATUS; + +#define BIT(nr) (1UL << (nr)) + +#define REG_SET_BIT(_r, _b) (*(volatile uint32_t*)(_r) |= (_b)) +#define REG_CLR_BIT(_r, _b) (*(volatile uint32_t*)(_r) &= ~(_b)) + +#define DMEM_ATTR __attribute__((section(".bss"))) +#define SHMEM_ATTR + +#ifdef ICACHE_FLASH +#define __ICACHE_STRINGIZE_NX(A) #A +#define __ICACHE_STRINGIZE(A) __ICACHE_STRINGIZE_NX(A) +#define ICACHE_FLASH_ATTR __attribute__((section("\".irom0.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) +#define ICACHE_RAM_ATTR __attribute__((section("\".iram.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) +#define ICACHE_RODATA_ATTR __attribute__((section("\".irom.text." __FILE__ "." __ICACHE_STRINGIZE(__LINE__) "." __ICACHE_STRINGIZE(__COUNTER__) "\""))) +#else +#define ICACHE_FLASH_ATTR +#define ICACHE_RAM_ATTR +#define ICACHE_RODATA_ATTR +#endif /* ICACHE_FLASH */ + +#define STORE_ATTR __attribute__((aligned(4))) + +#ifndef __cplusplus +#define BOOL bool +#define TRUE true +#define FALSE false + + +#endif /* !__cplusplus */ + +#endif /* _C_TYPES_H_ */ diff --git a/tests/host/common/esp8266_peri.h b/tests/host/common/esp8266_peri.h new file mode 100644 index 0000000000..b7b17675b8 --- /dev/null +++ b/tests/host/common/esp8266_peri.h @@ -0,0 +1,7 @@ + +#ifndef FAKE_ESP8266_PERI_H +#define FAKE_ESP8266_PERI_H + +const int GPI = 0; + +#endif \ No newline at end of file diff --git a/tests/host/common/include/ClientContext.h b/tests/host/common/include/ClientContext.h new file mode 100644 index 0000000000..ee88258431 --- /dev/null +++ b/tests/host/common/include/ClientContext.h @@ -0,0 +1,286 @@ +/* + ClientContext.h - emulation of TCP connection handling on top of lwIP + + 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 + */ +#ifndef CLIENTCONTEXT_H +#define CLIENTCONTEXT_H + +class ClientContext; +class WiFiClient; + +extern "C" void esp_yield(); +extern "C" void esp_schedule(); + +#include + +bool getDefaultPrivateGlobalSyncValue (); + +typedef void (*discard_cb_t)(void*, ClientContext*); + +class ClientContext +{ +public: + ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg) : + _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0), + _sync(::getDefaultPrivateGlobalSyncValue()), _sock(-1) + { + (void)pcb; + } + + ClientContext (int sock) : + _discard_cb(nullptr), _discard_cb_arg(nullptr), _refcnt(0), _next(nullptr), + _sync(::getDefaultPrivateGlobalSyncValue()), _sock(sock) + { + } + + err_t abort() + { + if (_sock >= 0) + ::close(_sock); + _sock = -1; + return ERR_ABRT; + } + + err_t close() + { + abort(); + return ERR_OK; + } + + ~ClientContext() + { + abort(); + } + + ClientContext* next() const + { + return _next; + } + + ClientContext* next(ClientContext* new_next) + { + _next = new_next; + return _next; + } + + void ref() + { + ++_refcnt; + DEBUGV(":ref %d\r\n", _refcnt); + } + + void unref() + { + DEBUGV(":ur %d\r\n", _refcnt); + if(--_refcnt == 0) { + discard_received(); + close(); + if (_discard_cb) + _discard_cb(_discard_cb_arg, this); + DEBUGV(":del\r\n"); + delete this; + } + } + + int connect(ip_addr_t* addr, uint16_t port) + { + return mockConnect(addr->addr, _sock, port); + } + + size_t availableForWrite() + { + // XXXFIXME be smarter + return 512; + } + + void setNoDelay(bool nodelay) + { + fprintf(stderr, MOCK "TODO setNoDelay(%d)\n", (int)nodelay); + } + + bool getNoDelay() const + { + fprintf(stderr, MOCK "TODO getNoDelay()\n"); + return false; + } + + void setTimeout(int timeout_ms) + { + _timeout_ms = timeout_ms; + } + + int getTimeout() const + { + return _timeout_ms; + } + + uint32_t getRemoteAddress() const + { + fprintf(stderr, MOCK "TODO getRemoteAddress()\n"); + return 0; + } + + uint16_t getRemotePort() const + { + fprintf(stderr, MOCK "TODO getRemotePort()\n"); + return 0; + } + + uint32_t getLocalAddress() const + { + fprintf(stderr, MOCK "TODO getLocalAddress()\n"); + return 0; + } + + uint16_t getLocalPort() const + { + fprintf(stderr, MOCK "TODO getLocalPort()\n"); + return 0; + } + + size_t getSize() + { + return _inbufsize?: mockFillInBuf(_sock, _inbuf, _inbufsize); + } + + int read() + { + char c; + return read(&c, 1)? c: -1; + } + + size_t read (char* dst, size_t size) + { + return mockRead(_sock, dst, size, 0, _inbuf, _inbufsize); + } + + int peek() + { + char c; + return peekBytes(&c, 1)? c: -1; + } + + size_t peekBytes(char *dst, size_t size) + { + return mockPeekBytes(_sock, dst, size, _timeout_ms, _inbuf, _inbufsize); + } + + void discard_received() + { + fprintf(stderr, MOCK "TODO: ClientContext::discard_received()\n"); + } + + bool wait_until_sent(int max_wait_ms = WIFICLIENT_MAX_FLUSH_WAIT_MS) + { + return true; + } + + uint8_t state() const + { + return _sock >= 0? ESTABLISHED: CLOSED; + } + + size_t write(const uint8_t* data, size_t size) + { + return mockWrite(_sock, data, size, _timeout_ms); + } + + size_t write(Stream& stream) + { + size_t avail = stream.available(); + uint8_t buf [avail]; + avail = stream.readBytes(buf, avail); + size_t totwrote = 0; + uint8_t* w = buf; + while (avail) + { + size_t wrote = write(w, avail); + w += wrote; + avail -= wrote; + totwrote += wrote; + } + return totwrote; + } + + size_t write_P(PGM_P buf, size_t size) + { + return write((const uint8_t*)buf, size); + } + + void keepAlive (uint16_t idle_sec = TCP_DEFAULT_KEEPALIVE_IDLE_SEC, uint16_t intv_sec = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC, uint8_t count = TCP_DEFAULT_KEEPALIVE_COUNT) + { + fprintf(stderr, MOCK "TODO ClientContext::keepAlive()\n"); + } + + bool isKeepAliveEnabled () const + { + fprintf(stderr, MOCK "TODO ClientContext::isKeepAliveEnabled()\n"); + return false; + } + + uint16_t getKeepAliveIdle () const + { + fprintf(stderr, MOCK "TODO ClientContext::getKeepAliveIdle()\n"); + return 0; + } + + uint16_t getKeepAliveInterval () const + { + fprintf(stderr, MOCK "TODO ClientContext::getKeepAliveInternal()\n"); + return 0; + } + + uint8_t getKeepAliveCount () const + { + fprintf(stderr, MOCK "TODO ClientContext::getKeepAliveCount()\n"); + return 0; + } + + bool getSync () const + { + fprintf(stderr, MOCK "TODO ClientContext::getSync()\n"); + return _sync; + } + + void setSync (bool sync) + { + fprintf(stderr, MOCK "TODO ClientContext::setSync()\n"); + _sync = sync; + } + +private: + + discard_cb_t _discard_cb = nullptr; + void* _discard_cb_arg = nullptr; + + int8_t _refcnt; + ClientContext* _next; + + bool _sync; + + // MOCK + + int _sock = -1; + int _timeout_ms = 5000; + + char _inbuf [CCBUFSIZE]; + size_t _inbufsize = 0; +}; + +#endif //CLIENTCONTEXT_H diff --git a/tests/host/common/include/UdpContext.h b/tests/host/common/include/UdpContext.h new file mode 100644 index 0000000000..3ea6f3c67f --- /dev/null +++ b/tests/host/common/include/UdpContext.h @@ -0,0 +1,254 @@ +/* + UdpContext.h - emulation of UDP connection handling on top of lwIP + + 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 +*/ +#ifndef UDPCONTEXT_H +#define UDPCONTEXT_H + +#include + +class UdpContext; + +#define GET_IP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN - IP_HLEN); +#define GET_UDP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN); + +class UdpContext +{ +public: + + typedef std::function rxhandler_t; + + UdpContext(): _on_rx(nullptr), _refcnt(0) + { + _sock = mockUDPSocket(); + } + + ~UdpContext() + { + } + + void ref() + { + ++_refcnt; + } + + void unref() + { + if(--_refcnt == 0) { + delete this; + } + } + + bool connect (ip_addr_t addr, uint16_t port) + { + _dst = addr; + _dstport = port; + return true; + } + + bool listen(ip_addr_t addr, uint16_t port) + { + bool ret = mockUDPListen(_sock, addr.addr, port, staticMCastAddr); + register_udp(_sock, this); + return ret; + } + + void disconnect() + { + if (_sock >= 0) + { + close(_sock); + register_udp(_sock, nullptr); + } + _sock = -1; + } + + void setMulticastInterface(const ip_addr_t& addr) + { + // user multicast, and this is how it works with posix: send to multicast address: + _dst.addr = staticMCastAddr; + } + + void setMulticastTTL(int ttl) + { + //fprintf(stderr, MOCK "TODO: UdpContext::setMulticastTTL\n"); + } + + // warning: handler is called from tcp stack context + // esp_yield and non-reentrant functions which depend on it will fail + void onRx(rxhandler_t handler) { + _on_rx = handler; + } + + size_t getSize() + { + return _inbufsize; + } + + size_t tell() const + { + return 0; + } + + void seek(const size_t pos) + { + fprintf(stderr, MOCK "TODO: implement UDP offset\n"); + if (!isValidOffset(pos)) + { + fprintf(stderr, MOCK "UDPContext::seek too far (%zd >= %zd)\n", pos, _inbufsize); + exit(EXIT_FAILURE); + } + } + + bool isValidOffset(const size_t pos) const { + return pos <= _inbufsize; + } + + uint32_t getRemoteAddress() + { + return _dst.addr; + } + + uint16_t getRemotePort() + { + return _dstport; + } + + uint32_t getDestAddress() + { + fprintf(stderr, MOCK "TODO: implement UDP getDestAddress\n"); + return 0; //ip_hdr* iphdr = GET_IP_HDR(_rx_buf); + } + + uint16_t getLocalPort() + { + fprintf(stderr, MOCK "TODO: implement UDP getLocalPort\n"); + return 0; // + } + + bool next() + { + _inbufsize = 0; + mockUDPFillInBuf(_sock, _inbuf, _inbufsize, addrsize, addr, _dstport); + if (_inbufsize > 0) + { + translate_addr(); + return true; + } + return false; + } + + int read() + { + char c; + return read(&c, 1)? c: -1; + } + + size_t read(char* dst, size_t size) + { + return mockUDPRead(_sock, dst, size, _timeout_ms, _inbuf, _inbufsize); + } + + int peek() + { + char c; + return mockUDPPeekBytes(_sock, &c, 1, _timeout_ms, _inbuf, _inbufsize)?: -1; + } + + void flush() + { + //fprintf(stderr, MOCK "UdpContext::flush() does not follow arduino's flush concept\n"); + //exit(EXIT_FAILURE); + // would be: + _inbufsize = 0; + } + + size_t append (const char* data, size_t size) + { + if (size + _outbufsize > sizeof _outbuf) + { + fprintf(stderr, MOCK "UdpContext::append: increase CCBUFSIZE (%d -> %zd)\n", CCBUFSIZE, (size + _outbufsize)); + exit(EXIT_FAILURE); + } + + memcpy(_outbuf + _outbufsize, data, size); + _outbufsize += size; + return size; + } + + bool send (ip_addr_t* addr = 0, uint16_t port = 0) + { + uint32_t dst = addr? addr->addr: _dst.addr; + uint16_t dstport = port?: _dstport; + size_t ret = mockUDPWrite(_sock, (const uint8_t*)_outbuf, _outbufsize, _timeout_ms, dst, dstport); + _outbufsize = 0; + return ret > 0; + } + + void mock_cb (void) + { + if (_on_rx) _on_rx(); + } + +public: + + static uint32_t staticMCastAddr; + +private: + + void translate_addr () + { + if (addrsize == 4) + { + uint32_t ipv4; + memcpy(&ipv4, addr, 4); + ip4_addr_set_u32(&ip_2_ip4(_dst), ipv4); + // ^ this is a workaround for "type-punned pointer" with "*(uint32*)addr" + //ip4_addr_set_u32(&ip_2_ip4(_dst), *(uint32_t*)addr); + } + else + fprintf(stderr, MOCK "TODO unhandled udp address of size %d\n", (int)addrsize); + } + + int _sock = -1; + rxhandler_t _on_rx; + int _refcnt = 0; + + ip_addr_t _dst; + uint16_t _dstport; + + char _inbuf [CCBUFSIZE]; + size_t _inbufsize = 0; + char _outbuf [CCBUFSIZE]; + size_t _outbufsize = 0; + + int _timeout_ms = 0; + + uint8_t addrsize; + uint8_t addr[16]; +}; + +inline err_t igmp_joingroup (const ip4_addr_t *ifaddr, const ip4_addr_t *groupaddr) +{ + (void)ifaddr; + UdpContext::staticMCastAddr = groupaddr->addr; + return ERR_OK; +} + +#endif//UDPCONTEXT_H diff --git a/tests/host/common/interrupts.h b/tests/host/common/interrupts.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/host/common/machine/ansi.h b/tests/host/common/machine/ansi.h new file mode 100644 index 0000000000..737b6d0666 --- /dev/null +++ b/tests/host/common/machine/ansi.h @@ -0,0 +1 @@ +/* dummy header file to support BSD compiler */ diff --git a/tests/host/common/mock.h b/tests/host/common/mock.h new file mode 100644 index 0000000000..5ef1d89924 --- /dev/null +++ b/tests/host/common/mock.h @@ -0,0 +1,121 @@ +/* + Arduino emulation - common to all emulated code + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +// include host's STL before any other include file +// because core definition like max() is in the way + +#ifdef __cplusplus +#include +#endif + +// exotic typedefs used in the sdk + +#include +typedef uint8_t uint8; +typedef uint32_t uint32; + +// + +#include + +// + +#include +#define RANDOM_REG32 ((uint32_t)random()) + +// net tweak + +// htontoh code in common/MockTools.cpp +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS +#undef INADDR_NONE + +// + +#ifdef __cplusplus +extern "C" { +#endif +int ets_printf (const char* fmt, ...) __attribute__ ((format (printf, 1, 2))); +#define os_printf_plus printf + +extern const char* host_interface; // cmdline parameter + +#define NO_GLOBAL_BINDING 0xffffffff +extern uint32_t global_ipv4_netfmt; // selected interface addresse to bind to + +#ifdef __cplusplus +} +#endif + +// + +#ifdef __cplusplus + +#ifndef CCBUFSIZE +#define CCBUFSIZE 8192 +#endif + +// tcp +int mockConnect (uint32_t addr, int& sock, int port); +size_t mockFillInBuf (int sock, char* ccinbuf, size_t& ccinbufsize); +size_t mockPeekBytes (int sock, char* dst, size_t size, int timeout_ms, char* buf, size_t& bufsize); +size_t mockRead (int sock, char* dst, size_t size, int timeout_ms, char* buf, size_t& bufsize); +size_t mockWrite (int sock, const uint8_t* data, size_t size, int timeout_ms); +int serverAccept (int sock); + +// udp +int mockUDPSocket (); +bool mockUDPListen (int sock, uint32_t dstaddr, uint16_t port, uint32_t mcast = 0); +size_t mockUDPFillInBuf (int sock, char* ccinbuf, size_t& ccinbufsize, uint8_t& addrsize, uint8_t addr[16], uint16_t& port); +size_t mockUDPPeekBytes (int sock, char* dst, size_t usersize, int timeout_ms, char* ccinbuf, size_t& ccinbufsize); +size_t mockUDPRead (int sock, char* dst, size_t size, int timeout_ms, char* ccinbuf, size_t& ccinbufsize); +size_t mockUDPWrite (int sock, const uint8_t* data, size_t size, int timeout_ms, uint32_t ipv4, uint16_t port); + +class UdpContext; +void register_udp (int sock, UdpContext* udp = nullptr); + +class InterruptLock { }; + +// + +#define CORE_MOCK 1 + +#define ARDUINO 267 +#define ESP8266 1 +#define A0 0 +#define LED_BUILTIN 0 +#define F_CPU 80000000 +#define LWIP_OPEN_SRC +#define TCP_MSS 536 +#define LWIP_FEATURES 1 + +// + +#endif // __cplusplus diff --git a/tests/host/common/queue.h b/tests/host/common/queue.h new file mode 100644 index 0000000000..af637ca030 --- /dev/null +++ b/tests/host/common/queue.h @@ -0,0 +1,471 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.48 2002/04/17 14:00:37 tmm Exp $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#include /* for __offsetof */ + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_REVERSE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) + + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#ifdef __GNUC__ + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !__GNUC__ */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/tests/host/common/spiffs_mock.cpp b/tests/host/common/spiffs_mock.cpp index 46ea855c4c..e63abae179 100644 --- a/tests/host/common/spiffs_mock.cpp +++ b/tests/host/common/spiffs_mock.cpp @@ -1,14 +1,14 @@ /* spiffs_mock.cpp - SPIFFS HAL mock for host side testing Copyright © 2016 Ivan Grokhotkov - + Permission is hereby granted, 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. */ @@ -22,6 +22,13 @@ #include +#include +#include +#include +#include + +#define SPIFFS_FILE_NAME "spiffs.bin" + extern "C" { static uint32_t s_phys_addr = 0; @@ -33,32 +40,89 @@ extern "C" FS SPIFFS(nullptr); -SpiffsMock::SpiffsMock(size_t fs_size, size_t fs_block, size_t fs_page) +SpiffsMock::SpiffsMock(size_t fs_size, size_t fs_block, size_t fs_page, bool storage) { - m_fs.resize(fs_size, 0xff); + fprintf(stderr, "SPIFFS: %zd bytes\n", fs_size); + + m_storage = storage; + m_fs = new uint8_t[m_fs_size = fs_size]; + memset(&m_fs[0], 0xff, m_fs_size); + s_phys_addr = 0; s_phys_size = static_cast(fs_size); s_phys_page = static_cast(fs_page); s_phys_block = static_cast(fs_block); - s_phys_data = m_fs.data(); + s_phys_data = &m_fs[0]; reset(); } void SpiffsMock::reset() { SPIFFS = FS(FSImplPtr(new SPIFFSImpl(0, s_phys_size, s_phys_page, s_phys_block, 5))); + if (m_storage) + load(); } - + SpiffsMock::~SpiffsMock() { + if (m_storage) + save(); s_phys_addr = 0; s_phys_size = 0; s_phys_page = 0; s_phys_block = 0; s_phys_data = nullptr; + delete [] m_fs; + m_fs = nullptr; + m_fs_size = 0; SPIFFS = FS(FSImplPtr(nullptr)); } +void SpiffsMock::load () +{ + if (!m_fs_size) + return; + + const char* fname = getenv("SPIFFS_PATH"); + if (!fname) + fname = DEFAULT_SPIFFS_FILE_NAME; + int fs = ::open(SPIFFS_FILE_NAME, O_RDONLY); + if (fs == -1) + { + fprintf(stderr, "SPIFFS: loading '%s': %s\n", fname, strerror(errno)); + return; + } + fprintf(stderr, "SPIFFS: loading %zi bytes from '%s'\n", m_fs_size, fname); + if (::read(fs, &m_fs[0], m_fs_size) != (ssize_t)m_fs_size) + fprintf(stderr, "SPIFFS: reading %zi bytes: %s\n", m_fs_size, strerror(errno)); + ::close(fs); +} + +void SpiffsMock::save () +{ + if (!m_fs_size) + return; + + const char* fname = getenv("SPIFFS_PATH"); + if (!fname) + fname = DEFAULT_SPIFFS_FILE_NAME; + int fs = ::open(SPIFFS_FILE_NAME, O_CREAT | O_TRUNC | O_WRONLY, 0644); + if (fs == -1) + { + fprintf(stderr, "SPIFFS: saving '%s': %s\n", fname, strerror(errno)); + return; + } + fprintf(stderr, "SPIFFS: saving %zi bytes to '%s'\n", m_fs_size, fname); + +// this can be a valgrind error, I don't understand how it happens +//for (size_t i = 0; i < m_fs_size; i++) printf("\r%zd:%d ", i, (int)m_fs[i]); + + if (::write(fs, &m_fs[0], m_fs_size) != (ssize_t)m_fs_size) + fprintf(stderr, "SPIFFS: writing %zi bytes: %s\n", m_fs_size, strerror(errno)); + if (::close(fs) == -1) + fprintf(stderr, "SPIFFS: closing %s: %s\n", fname, strerror(errno)); +} + int32_t spiffs_hal_read(uint32_t addr, uint32_t size, uint8_t *dst) { memcpy(dst, s_phys_data + addr, size); return SPIFFS_OK; diff --git a/tests/host/common/spiffs_mock.h b/tests/host/common/spiffs_mock.h index d54bc6df23..6b0c2c5102 100644 --- a/tests/host/common/spiffs_mock.h +++ b/tests/host/common/spiffs_mock.h @@ -21,17 +21,32 @@ #include #include +#define DEFAULT_SPIFFS_FILE_NAME "spiffs.bin" + class SpiffsMock { public: - SpiffsMock(size_t fs_size, size_t fs_block, size_t fs_page); + SpiffsMock(size_t fs_size, size_t fs_block, size_t fs_page, bool storage = true); void reset(); ~SpiffsMock(); protected: - std::vector m_fs; + void load (); + void save (); + + // it was a vector, but CI tests & valgrind complain with: + // Syscall param write(buf) points to uninitialised byte(s) + // by 0x43E9FF: SpiffsMock::save() (spiffs_mock.cpp:116) + // = if (::write(fs, &m_fs[0], m_fs_size) != (ssize_t)m_fs_size) + // so switched to a regular array + // and that bug is still here + // XXXWIPTODO + + uint8_t* m_fs; + size_t m_fs_size; + bool m_storage; }; -#define SPIFFS_MOCK_DECLARE(size_kb, block_kb, page_b) SpiffsMock spiffs_mock(size_kb * 1024, block_kb * 1024, page_b) +#define SPIFFS_MOCK_DECLARE(size_kb, block_kb, page_b, storage) SpiffsMock spiffs_mock(size_kb * 1024, block_kb * 1024, page_b, storage) #define SPIFFS_MOCK_RESET() spiffs_mock.reset() diff --git a/tests/host/common/user_interface.cpp b/tests/host/common/user_interface.cpp new file mode 100644 index 0000000000..42bafb3fc4 --- /dev/null +++ b/tests/host/common/user_interface.cpp @@ -0,0 +1,458 @@ +/* + Arduino emulation - espressif sdk host implementation + Copyright (c) 2018 david gauchard. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal with 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: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + - The names of its contributors may not be used to endorse or promote + products derived from this Software without specific prior written + permission. + + 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 CONTRIBUTORS 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 WITH THE SOFTWARE. +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + + +extern "C" +{ + +#include + +uint8 wifi_get_opmode(void) +{ + return STATION_MODE; +} + +phy_mode_t wifi_get_phy_mode(void) +{ + return PHY_MODE_11N; +} + +uint8 wifi_get_channel (void) +{ + return 1; +} + +uint8 wifi_station_get_current_ap_id (void) +{ + return 0; +} + +station_status_t wifi_station_get_connect_status (void) +{ + return STATION_GOT_IP; +} + +uint8 wifi_station_get_auto_connect (void) +{ + return 1; +} + +bool wifi_station_get_config (struct station_config *config) +{ + strcpy((char*)config->ssid, "emulated-ssid"); + strcpy((char*)config->password, "emulated-ssid-password"); + config->bssid_set = 0; + for (int i = 0; i < 6; i++) + config->bssid[i] = i; + config->threshold.rssi = 1; + config->threshold.authmode = AUTH_WPA_PSK; + config->open_and_wep_mode_disable = true; + return true; +} + +void wifi_fpm_close(void) +{ +} + +sint8 wifi_fpm_do_sleep (uint32 sleep_time_in_us) +{ + usleep(sleep_time_in_us); + return 1; +} + +void wifi_fpm_do_wakeup (void) +{ +} + +void wifi_fpm_open (void) +{ +} + +void wifi_fpm_set_sleep_type (sleep_type_t type) +{ + (void)type; +} + +uint32_t global_ipv4_netfmt = 0; // global binding + +bool wifi_get_ip_info (uint8 if_index, struct ip_info *info) +{ + struct ifaddrs * ifAddrStruct = NULL, * ifa = NULL; + uint32_t ipv4 = lwip_htonl(0x7f000001); + uint32_t mask = lwip_htonl(0xff000000); + + if (getifaddrs(&ifAddrStruct) != 0) + { + perror("getifaddrs"); + exit(EXIT_FAILURE); + } + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) + { + if ( ifa->ifa_addr + && ifa->ifa_addr->sa_family == AF_INET // ip_info is IPv4 only + ) + { + if (lwip_ntohl(*(uint32_t*)&((struct sockaddr_in*) ifa->ifa_netmask)->sin_addr) != 0xff000000) + { + if (ipv4 == lwip_htonl(0x7f000001)) + { + // take the first by default + ipv4 = *(uint32_t*)&((struct sockaddr_in*)ifa->ifa_addr)->sin_addr; + mask = *(uint32_t*)&((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr; + } + if (host_interface && strcmp(ifa->ifa_name, host_interface) == 0) + { + // .. or the one specified by user on cmdline + ipv4 = *(uint32_t*)&((struct sockaddr_in*)ifa->ifa_addr)->sin_addr; + mask = *(uint32_t*)&((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr; + break; + } + } + } + } + if (ifAddrStruct != NULL) + freeifaddrs(ifAddrStruct); + + (void)if_index; + //if (if_index != STATION_IF) + // fprintf(stderr, "we are not AP"); + + if (global_ipv4_netfmt == NO_GLOBAL_BINDING) + global_ipv4_netfmt = ipv4; + + if (info) + { + info->ip.addr = ipv4; + info->netmask.addr = mask; + info->gw.addr = ipv4; + } + + return true; +} + +uint8 wifi_get_listen_interval (void) +{ + return 1; +} + +bool wifi_get_macaddr(uint8 if_index, uint8 *macaddr) +{ + macaddr[0] = 0xde; + macaddr[1] = 0xba; + macaddr[2] = 0x7a; + macaddr[3] = 0xb1; + macaddr[4] = 0xe0; + macaddr[5] = 0x42; + return true; +} + +uint8 wifi_get_opmode_default (void) +{ + return STATION_MODE; +} + +sleep_level_t wifi_get_sleep_level (void) +{ + return MIN_SLEEP_T; +} + +sleep_type_t wifi_get_sleep_type (void) +{ + return NONE_SLEEP_T; +} + +bool wifi_set_channel (uint8 channel) +{ + (void)channel; + return true; +} + +wifi_event_handler_cb_t wifi_event_handler_cb_emu = nullptr; +void wifi_set_event_handler_cb (wifi_event_handler_cb_t cb) +{ + wifi_event_handler_cb_emu = cb; + fprintf(stderr, MOCK "TODO: wifi_set_event_handler_cb set\n"); +} + +bool wifi_set_ip_info (uint8 if_index, struct ip_info *info) +{ + (void)if_index; + (void)info; + return false; +} + +bool wifi_set_listen_interval (uint8 interval) +{ + (void)interval; + return true; +} + +bool wifi_set_opmode (uint8 opmode) +{ + return opmode == STATION_MODE || opmode == STATIONAP_MODE; +} + +bool wifi_set_opmode_current (uint8 opmode) +{ + return opmode == STATION_MODE || opmode == STATIONAP_MODE; +} + +bool wifi_set_phy_mode (phy_mode_t mode) +{ + return true; +} + +bool wifi_set_sleep_level (sleep_level_t level) +{ + (void)level; + return true; +} + +bool wifi_set_sleep_type (sleep_type_t type) +{ + (void)type; + return true; +} + +bool wifi_station_connect (void) +{ + return true; +} + +bool wifi_station_dhcpc_start (void) +{ + return true; +} + +bool wifi_station_dhcpc_stop (void) +{ + return true; +} + +bool wifi_station_disconnect (void) +{ + return true; +} + +bool wifi_station_get_config_default (struct station_config *config) +{ + return wifi_station_get_config(config); +} + +char wifi_station_get_hostname_str [128]; +char* wifi_station_get_hostname (void) +{ + return strcpy(wifi_station_get_hostname_str, "esposix"); +} + +bool wifi_station_get_reconnect_policy () +{ + return true; +} + +sint8 wifi_station_get_rssi (void) +{ + return 5; +} + +bool wifi_station_set_auto_connect (uint8 set) +{ + return set != 0; +} + +bool wifi_station_set_config (struct station_config *config) +{ + (void)config; + return true; +} + +bool wifi_station_set_config_current (struct station_config *config) +{ + (void)config; + return true; +} + +bool wifi_station_set_hostname (char *name) +{ + (void)name; + return true; +} + +bool wifi_station_set_reconnect_policy (bool set) +{ + (void)set; + return true; +} + +void system_phy_set_max_tpw (uint8 max_tpw) +{ + (void)max_tpw; +} + +bool wifi_softap_dhcps_start(void) +{ + return true; +} + +enum dhcp_status wifi_softap_dhcps_status(void) +{ + return DHCP_STARTED; +} + +bool wifi_softap_dhcps_stop(void) +{ + return true; +} + +bool wifi_softap_get_config(struct softap_config *config) +{ + strcpy((char*)config->ssid, "apssid"); + strcpy((char*)config->password, "appasswd"); + config->ssid_len = strlen("appasswd"); + config->channel = 1; + config->authmode = AUTH_WPA2_PSK; + config->ssid_hidden = 0; + config->max_connection = 4; + config->beacon_interval = 100; + return true; +} + +bool wifi_softap_get_config_default(struct softap_config *config) +{ + return wifi_softap_get_config(config); +} + +uint8 wifi_softap_get_station_num(void) +{ + return 2; +} + +bool wifi_softap_set_config(struct softap_config *config) +{ + (void)config; + return true; +} + +bool wifi_softap_set_config_current(struct softap_config *config) +{ + (void)config; + return true; +} + +bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please) +{ + (void)please; + return true; +} + +bool wifi_softap_set_dhcps_lease_time(uint32 minute) +{ + (void)minute; + return true; +} + +bool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg) +{ + (void)level; + (void)optarg; + return true; +} + +bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb) +{ + cb(nullptr, FAIL); + return false; +} + +uint32_t core_version = 1; + +/////////////////////////////////////// +// not user_interface + +void ets_isr_mask (int intr) +{ + (void)intr; +} + +void ets_isr_unmask (int intr) +{ + (void)intr; +} + +void esp_schedule (void) +{ +} + +void optimistic_yield (uint32_t ms) +{ + usleep(ms * 1000); +} + +void dns_setserver (u8_t numdns, ip_addr_t *dnsserver) +{ + (void)numdns; + (void)dnsserver; +} + +ip_addr_t dns_getserver (u8_t numdns) +{ + ip_addr_t addr = { 0x7f000001 }; + return addr; +} + + +#include +bool smartconfig_start (sc_callback_t cb, ...) +{ + //XXXFIXME ... -> ptr + cb(SC_STATUS_LINK, NULL); + return true; +} + +bool smartconfig_stop (void) +{ + return true; +} + + + + +} // extern "C" diff --git a/tests/host/fs/test_fs.cpp b/tests/host/fs/test_fs.cpp index 6e14af84f2..c97e0f718b 100644 --- a/tests/host/fs/test_fs.cpp +++ b/tests/host/fs/test_fs.cpp @@ -50,25 +50,25 @@ static std::set listDir (const char* path) TEST_CASE("FS can begin","[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); } TEST_CASE("FS can't begin with zero size","[fs]") { - SPIFFS_MOCK_DECLARE(0, 8, 512); + SPIFFS_MOCK_DECLARE(0, 8, 512, false); REQUIRE_FALSE(SPIFFS.begin()); } TEST_CASE("Before begin is called, open will fail","[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE_FALSE(SPIFFS.open("/foo", "w")); } TEST_CASE("FS can create file","[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); createFile("/test", ""); REQUIRE(SPIFFS.exists("/test")); @@ -76,7 +76,7 @@ TEST_CASE("FS can create file","[fs]") TEST_CASE("Files can be written and appended to","[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); { File f = SPIFFS.open("config1.txt", "w"); @@ -100,7 +100,7 @@ TEST_CASE("Files can be written and appended to","[fs]") TEST_CASE("Files persist after reset", "[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); createFile("config1.txt", "file 1"); @@ -112,7 +112,7 @@ TEST_CASE("Files persist after reset", "[fs]") TEST_CASE("Filesystem is empty after format", "[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.format()); REQUIRE(SPIFFS.begin()); createFile("/1", "first"); @@ -128,7 +128,7 @@ TEST_CASE("Filesystem is empty after format", "[fs]") TEST_CASE("Dir lists all files", "[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); createFile("/empty", ""); createFile("/not_empty", "some text"); @@ -146,7 +146,7 @@ TEST_CASE("Dir lists all files", "[fs]") TEST_CASE("File names which are too long are rejected", "[fs]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); const char* emptyName = ""; const char* longName_31 = "/234567890123456789012345678901"; @@ -164,7 +164,7 @@ TEST_CASE("File names which are too long are rejected", "[fs]") TEST_CASE("#1685 Duplicate files", "[fs][bugreport]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); createFile("/config", "some text"); createFile("/data", ""); @@ -175,7 +175,7 @@ TEST_CASE("#1685 Duplicate files", "[fs][bugreport]") TEST_CASE("#1819 Can list all files with openDir(\"\")", "[fs][bugreport]") { - SPIFFS_MOCK_DECLARE(64, 8, 512); + SPIFFS_MOCK_DECLARE(64, 8, 512, false); REQUIRE(SPIFFS.begin()); createFile("/file1", "some text"); createFile("/file2", "other text"); diff --git a/tools/sdk/ssl/Makefile b/tools/sdk/ssl/Makefile index bc9126f9ff..c84d0451cf 100644 --- a/tools/sdk/ssl/Makefile +++ b/tools/sdk/ssl/Makefile @@ -11,7 +11,7 @@ install: all version-header bearssl/README.txt: git submodule update --init --recursive bearssl - cd bearssl && git remote add bearssl https://www.bearssl.org/git/BearSSL + cd bearssl && (git remote add bearssl https://www.bearssl.org/git/BearSSL || true) merge-upstream: cd bearssl && git pull bearssl master @@ -20,3 +20,9 @@ version-header: echo "// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile" > $(VER_H) echo -n "#define BEARSSL_GIT " >> $(VER_H) cd bearssl && git rev-parse --short HEAD >> ../$(VER_H) + +native: bearssl/README.txt + cd bearssl && make + +native32: bearssl/README.txt + cd bearssl && make CONF=Unix32