From 12de405b8670631b9708ef924c2d6f74d6876e4e Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 25 Jul 2017 10:14:10 +0200 Subject: [PATCH 01/33] Preparation for the final 3.3.0 release. (#1202) This version includes: - Refactored HttpClient and HttpServer - Support for SSL session resumption in TcpConnection and TcpServer. - Removed deprecated Station::waitConnection. - Custom PWM is enabled by default. - Multiple fixes to issues reported from Codacy's Vera++ and CppCheck reports. --- Readme.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 5acd9f49d6..5063811398 100644 --- a/Readme.md +++ b/Readme.md @@ -43,7 +43,7 @@ SDK = Software Development Kit n/a = The selected SDK is not available on that OS ## Latest Stable Release -- [Sming V3.2.0](https://github.com/SmingHub/Sming/releases/tag/3.2.0) +- [Sming V3.3.0](https://github.com/SmingHub/Sming/releases/tag/3.3.0) ## Getting started - [Windows](https://github.com/SmingHub/Sming/wiki/Windows-Quickstart) @@ -64,7 +64,7 @@ n/a = The selected SDK is not available on that OS - Custom PWM: (default: ON) If you don't want to use the [open PWM implementation](https://github.com/StefanBruens/ESP8266_new_pwm) then compile your application with `ENABLE_CUSTOM_PWM=0`. There is no need to recompile the Sming library. - Custom serial baud rate: (default: OFF) The default serial baud rate is 115200. If you want to change it to a higher baud rate you can recompile Sming and your application changing the `COM_SPEED_SERIAL` directive. For example `COM_SPEED_SERIAL=921600`. - Custom heap allocation: (default: OFF) If your application is experiencing heap fragmentation then you can try the [umm_malloc](https://github.com/rhempel/umm_malloc) heap allocation. To enable it compile Sming with `ENABLE_CUSTOM_HEAP=1`. In order to use it in your sample/application make sure to compile the sample with `ENABLE_CUSTOM_HEAP=1`. **Do not enable custom heap allocation and -mforce-l32 compiler flag together**. -- Debug information log level and format: There are four debug levels: debug=3, info=2, warn=1, error=0. Using `DEBUG_VERBOSE_LEVEL` you can set the desired level (0-3). For example `DEBUG_VERBOSE_LEVEL=2` will show only info messages and above. Another make directive is `DEBUG_PRINT_FILENAME_AND_LINE=1` which enables printing the filename and line number of every debug line. This will require extra space on flash. Note: you can compile the Sming library with a set of debug directives and your project with another settings, this way you can control debugging sepparately for sming and your application code. +- Debug information log level and format: There are four debug levels: debug=3, info=2, warn=1, error=0. Using `DEBUG_VERBOSE_LEVEL` you can set the desired level (0-3). For example `DEBUG_VERBOSE_LEVEL=2` will show only info messages and above. Another make directive is `DEBUG_PRINT_FILENAME_AND_LINE=1` which enables printing the filename and line number of every debug line. This will require extra space on flash. Note: you can compile the Sming library with a set of debug directives and your project with another settings, this way you can control debugging separately for Sming and your application code. - Debug information for custom LWIP: If you use custom LWIP (see above) some debug information will be printed for critical errors and situations. You can enable debug information printing altogether using `ENABLE_LWIPDEBUG=1`. To increase debugging for certain areas you can modify debug options in `third-party/esp-open-lwip/include/lwipopts.h`. - CommandExecutor feature: (default: ON) This feature enables execution of certain commands by registering token handlers for text received via serial, websocket or telnet connection. If this feature is not used additional RAM/Flash can be obtained by setting `ENABLE_CMD_EXECUTOR=0`. This will save ~1KB RAM and ~3KB of flash memory. @@ -74,6 +74,7 @@ n/a = The selected SDK is not available on that OS See the getting started page for your respective operating system. You can find more information about compilation and flashing process by reading esp8266.com forum discussion thread. +Official ESP8266 documentation can be found in the [Espressif website](https://espressif.com/en/support/download/documents?keys=&field_type_tid%5B%5D=14). ## Examples More information at **[Wiki Examples](https://github.com/SmingHub/Sming/wiki/examples)** page. From a789c2092486372cb66cd2bca23f12ce2686c8c5 Mon Sep 17 00:00:00 2001 From: slaff Date: Wed, 26 Jul 2017 14:03:03 +0200 Subject: [PATCH 02/33] Small fixes before the final 3.3.0 (#1203) * Pass the fingerprints and certification pairs by reference. * Replace the external GNU find with GNU makefile standard functions: dir, wildcard and sort. --- Readme.md | 1 + Sming/Makefile | 4 +- Sming/SmingCore/Network/Http/HttpRequest.cpp | 4 +- Sming/SmingCore/Network/Http/HttpRequest.h | 4 +- samples/Basic_Debug/README.md | 84 +++++++++++++------- 5 files changed, 62 insertions(+), 35 deletions(-) diff --git a/Readme.md b/Readme.md index 5063811398..4d2ef01ecf 100644 --- a/Readme.md +++ b/Readme.md @@ -66,6 +66,7 @@ n/a = The selected SDK is not available on that OS - Custom heap allocation: (default: OFF) If your application is experiencing heap fragmentation then you can try the [umm_malloc](https://github.com/rhempel/umm_malloc) heap allocation. To enable it compile Sming with `ENABLE_CUSTOM_HEAP=1`. In order to use it in your sample/application make sure to compile the sample with `ENABLE_CUSTOM_HEAP=1`. **Do not enable custom heap allocation and -mforce-l32 compiler flag together**. - Debug information log level and format: There are four debug levels: debug=3, info=2, warn=1, error=0. Using `DEBUG_VERBOSE_LEVEL` you can set the desired level (0-3). For example `DEBUG_VERBOSE_LEVEL=2` will show only info messages and above. Another make directive is `DEBUG_PRINT_FILENAME_AND_LINE=1` which enables printing the filename and line number of every debug line. This will require extra space on flash. Note: you can compile the Sming library with a set of debug directives and your project with another settings, this way you can control debugging separately for Sming and your application code. - Debug information for custom LWIP: If you use custom LWIP (see above) some debug information will be printed for critical errors and situations. You can enable debug information printing altogether using `ENABLE_LWIPDEBUG=1`. To increase debugging for certain areas you can modify debug options in `third-party/esp-open-lwip/include/lwipopts.h`. +- Interactive debugging on the device: (default: OFF) In order to be able to debug live directly on the ESP8266 microcontroller you should re-compile your application and the Sming library with `ENABLE_GDB=1` directive. See [Basic_Debug](https://github.com/SmingHub/Sming/tree/develop/samples/Basic_Debug) sample for more details. - CommandExecutor feature: (default: ON) This feature enables execution of certain commands by registering token handlers for text received via serial, websocket or telnet connection. If this feature is not used additional RAM/Flash can be obtained by setting `ENABLE_CMD_EXECUTOR=0`. This will save ~1KB RAM and ~3KB of flash memory.

diff --git a/Sming/Makefile b/Sming/Makefile index 49fbf68dfa..28e4ba65fc 100644 --- a/Sming/Makefile +++ b/Sming/Makefile @@ -152,7 +152,9 @@ TARGET = app CUSTOM_TARGETS ?= # which modules (subdirectories) of the project to include in compiling -MODULES = system system/helpers Wiring appinit $(shell find SmingCore -type d) $(filter %/, $(wildcard Services/*/)) $(filter %/, $(wildcard Libraries/*/)) +MODULES = system system/helpers Wiring appinit \ + $(sort $(dir $(wildcard SmingCore/*/ SmingCore/*/*/ SmingCore/*/*/*/))) \ + $(filter %/, $(wildcard Services/*/)) $(filter %/, $(wildcard Libraries/*/)) EXTRA_INCDIR = include system/include Wiring Libraries SmingCore $(SDK_BASE)/../include # Place a file that should exist in a submodule that is fetched separately diff --git a/Sming/SmingCore/Network/Http/HttpRequest.cpp b/Sming/SmingCore/Network/Http/HttpRequest.cpp index 614c3b7f35..26cd7607d6 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.cpp +++ b/Sming/SmingCore/Network/Http/HttpRequest.cpp @@ -185,12 +185,12 @@ uint32_t HttpRequest::getSslOptions() { return sslOptions; } -HttpRequest* HttpRequest::pinCertificate(SSLFingerprints fingerprints) { +HttpRequest* HttpRequest::pinCertificate(const SSLFingerprints& fingerprints) { sslFingerprint = fingerprints; return this; } -HttpRequest* HttpRequest::setSslClientKeyCert(SSLKeyCertPair clientKeyCert) { +HttpRequest* HttpRequest::setSslClientKeyCert(const SSLKeyCertPair& clientKeyCert) { this->sslClientKeyCert = clientKeyCert; return this; } diff --git a/Sming/SmingCore/Network/Http/HttpRequest.h b/Sming/SmingCore/Network/Http/HttpRequest.h index 35f7807c1b..23aac97ae3 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.h +++ b/Sming/SmingCore/Network/Http/HttpRequest.h @@ -94,7 +94,7 @@ class HttpRequest { * * @return bool true of success, false or failure */ - HttpRequest* pinCertificate(SSLFingerprints fingerprints); + HttpRequest* pinCertificate(const SSLFingerprints& fingerprints); /** * @brief Sets client private key, certificate and password from memory @@ -103,7 +103,7 @@ class HttpRequest { * * @return HttpRequest pointer */ - HttpRequest* setSslClientKeyCert(SSLKeyCertPair clientKeyCert); + HttpRequest* setSslClientKeyCert(const SSLKeyCertPair& clientKeyCert); #endif HttpRequest* setBody(const String& body); diff --git a/samples/Basic_Debug/README.md b/samples/Basic_Debug/README.md index 10ca427d7d..3d42e0deec 100644 --- a/samples/Basic_Debug/README.md +++ b/samples/Basic_Debug/README.md @@ -3,32 +3,64 @@ It relies on the GDBStub project to do the heavy-lifting. Exception Handling ------------------ -If there is an exception in your code usually ESP prints a message like the following one: +Sming comes with a built-in exception handling that takes care to display the stack trace +leading to the issue. Usually it looks like this ``` -Fatal exception (0): -epc1=0x4020997c, epc2=0x00000000, epc3=0x00000000, excvaddr=0x00000000, depc=0x00000000 +***** Fatal exception 28 +pc=0x40100e96 sp=0x3ffff640 excvaddr=0x000015b8 +ps=0x00000033 sar=0x00000018 vpri=0x000000f0 +r00: 0x40100d69=1074793833 r01: 0x3ffff640=1073739328 r02: 0x3fff3900=1073690880 +r03: 0x2b265ed4= 723934932 r04: 0x3fffbff0=1073725424 r05: 0x000015b8= 5560 +r06: 0x000015b8= 5560 r07: 0x14a8433b= 346571579 r08: 0x00000008= 8 +r09: 0x14a842f3= 346571507 r10: 0x3fff22d0=1073685200 r11: 0x00000003= 3 +r12: 0x00000048= 72 r13: 0x3fff38c0=1073690816 r14: 0x3ffe9da0=1073651104 +r15: 0x3fff1138=1073680696 + +Stack dump: +To decode the stack dump call from command line: + python $SMING_HOME/../tools/decode-stacktrace.py out/build/app.out +and copy & paste the text enclosed in '===='. +================================================================ +3ffff640: 40100e96 00000033 00000018 000000f0 +3ffff650: 40100d69 3fff3900 2b265ed4 3fffbff0 +3ffff660: 000015b8 000015b8 14a8433b 00000008 +3ffff670: 14a842f3 3fff22d0 00000003 00000048 +3ffff680: 3fff38c0 3ffe9da0 3fff1138 0000001c +3ffff690: 002222fb c0fb5c01 0bc10000 facfd1fb +3ffff6a0: 620020c0 6162802d 0020c004 59062c52 +3ffff6b0: 0020c051 61492c48 210020c0 7c38fb50 +... + +================================================================ ``` -That information can help you discover the function call that caused the exception. -Using the value of epc1 and executing a command like the one below: +With the help of `decode-stacktrace.py` you can decode the stack trace to something readable like: -```bash -xtensa-lx106-elf-objdump -dtr out/build/app.out | grep 4020997c -``` - -can give you an idea about the function. In my test case this is: ``` -4020997c: fffe61 l32r a6, 40209974 +0x40100e96: pvPortRealloc at ??: ? +0x40100d69: pvPortMalloc at ??:? +0x402455f0: ax_port_malloc at C:\tools\Sming-3.1.2\Sming/third-party/axtls-8266/ replacements/mem.c:51 +0x4024561a: ax_port_calloc at C:\tools\Sming-3.1.2\Sming/third-party/axtls-8266/ replacements/mem.c:63 +0x40230acc: x509_new at c:\tools\Sming-3.1.2\Sming\third-party\axtls-8266/ssl/x5 09.c:81 +0x4023d3e4: m_vsnprintf at C:\tools\Sming-3.1.2\Sming/system/m_printf.cpp:69 +0x4023d4a6: m_vprintf at C:\tools\Sming-3.1.2\Sming/system/m_printf.cpp:83 +0x40000a39: ?? ??:0 +0x4021418a: pp_attach at ??:? +0x40221d60: pbuf_alloc at ??:? +0x40221f0a: pbuf_copy at ??:? +0x4023d3e4: m_vsnprintf at C:\tools\Sming-3.1.2\Sming/system/m_printf.cpp:69 ``` -But that information might not be enough to find the issue. And finding the +Using the information about the type of the exception (ex: `***** Fatal exception 28`) +and the sequence of commands might help us figure out the issue. + +But that information might not be enough. And finding the root cause may take quite some time. GDB Debugging ------------- -Debugging is a powerful technique giving better understanding of the code and -the things that went wrong. +Debugging is a powerful technique allowing you to interactively run your code and be able to see much more information about the things that went wrong. There is already existing GDBStub that tries to make it easier to use software debugger. And this project is an example of what you need to do in order to @@ -36,25 +68,17 @@ integrate it. Here are the commands that you need to execute: -1. Fetch the [GDBStub](https://github.com/espressif/esp-gdbstub) by -executing the following commands ( usually needs to be done only once). - -```bash -git submodule init -git submodule update --recursive -``` - -2. You will need a version of the sming library with enabled GDBStub functionality. +1. You will need a version of the Sming library with enabled GDBStub functionality. For that purpose you should compile Sming with ENABLE_GDB flag. Under Linux you should do the following: ```bash -cd /Sming -make clean +cd $SMING_HOME +make dist-clean ENABLE_GDB=1 make ``` -3. In you project inside of you Makefile-user.mk file you should add the following +2. In your project inside of your Makefile-user.mk file you should add the following variable: ```make @@ -64,13 +88,13 @@ ENABLE_GDB=1 If you are looking for an example then take a look at the Makefile-user.mk file that is in the same directory as this README.md file. -4. Now compile your project and flash it to the board. +3. Now compile your project and flash it to the board. ```bash -make +make ENABLE_GDB=1 make flash ``` -5. Run gdb immediately after resetting the board or after it has run into an exception. +4. Run gdb immediately after resetting the board or after it has run into an exception. The easiest way to do it is to use the provided script: ```bash xtensa-lx106-elf-gdb -x /Basic_Debug/gdbcmds -b 115200 @@ -79,7 +103,7 @@ xtensa-lx106-elf-gdb -x /Basic_Debug/gdbcmds -b 115200 115200 stands for the baud rate your program is using. Change it accordingly. You may also need to change the gdbcmds script to fit the configuration of your hardware and build environment. -6. Software breakpoints ('br') only work on code that is in RAM. During development you can use the GDB_IRAM_ATTR attribute in your function declarations. +5. Software breakpoints ('br') only work on code that is in RAM. During development you can use the GDB_IRAM_ATTR attribute in your function declarations. Code in flash can only have a hardware breakpoint ('hbr'). Read the [Notes](https://github.com/espressif/esp-gdbstub#notes) for more information. From 50df3f026f8862c5395f68a1a716ee555b9b5b32 Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 27 Jul 2017 09:30:29 +0200 Subject: [PATCH 03/33] Better Arduino compatability: Changed to order of the Wire.begin and Wire.pins parameters to (#1193) match the [Arduino order](samples/DS3232RTC_NTP_Setter/app/application.cpp). Related to #1179 and #1061. Warning: this is a backward incompatible change. --- Sming/SmingCore/Wire.cpp | 6 +++--- Sming/SmingCore/Wire.h | 4 ++-- samples/Accelerometer_MMA7455/app/application.cpp | 2 +- samples/Arducam/app/application.cpp | 2 +- samples/Basic_ScannerI2C/app/application.cpp | 4 ++-- samples/DS3232RTC_NTP_Setter/app/application.cpp | 2 +- samples/Humidity_AM2321/app/application.cpp | 2 +- samples/Humidity_SI7021/app/application.cpp | 2 +- samples/MeteoControl_mqtt/app/application.cpp | 2 +- samples/PortExpander_MCP23017/app/application.cpp | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Sming/SmingCore/Wire.cpp b/Sming/SmingCore/Wire.cpp index 36e3c2c932..bdec5b1a19 100644 --- a/Sming/SmingCore/Wire.cpp +++ b/Sming/SmingCore/Wire.cpp @@ -54,20 +54,20 @@ TwoWire::TwoWire(){} // Public Methods ////////////////////////////////////////////////////////////// -void TwoWire::begin(int scl, int sda){ +void TwoWire::begin(int sda, int scl){ default_sda_pin = sda; default_scl_pin = scl; twi_init(sda, scl); flush(); } -void TwoWire::pins(int scl, int sda){ +void TwoWire::pins(int sda, int scl){ default_sda_pin = sda; default_scl_pin = scl; } void TwoWire::begin(void){ - begin(default_scl_pin, default_sda_pin); + begin(default_sda_pin, default_scl_pin); } void TwoWire::begin(uint8_t address){ diff --git a/Sming/SmingCore/Wire.h b/Sming/SmingCore/Wire.h index f2ca80880d..e69604e35b 100644 --- a/Sming/SmingCore/Wire.h +++ b/Sming/SmingCore/Wire.h @@ -48,8 +48,8 @@ class TwoWire : public Stream static void onReceiveService(uint8_t*, int); public: TwoWire(); - void begin(int scl, int sda); - void pins(int scl, int sda); + void begin(int sda, int scl); + void pins(int sda, int scl); void begin(); void begin(uint8_t); void begin(int); diff --git a/samples/Accelerometer_MMA7455/app/application.cpp b/samples/Accelerometer_MMA7455/app/application.cpp index e3773672da..605755eb74 100644 --- a/samples/Accelerometer_MMA7455/app/application.cpp +++ b/samples/Accelerometer_MMA7455/app/application.cpp @@ -29,7 +29,7 @@ void init() Serial.println("Starting..."); // You can change pins: - //Wire.pins(12, 14); // SCL, SDA + //Wire.pins(14, 12); // SDA, SCL Wire.begin(); // Select the Working Mode diff --git a/samples/Arducam/app/application.cpp b/samples/Arducam/app/application.cpp index 397704c6ba..53fbfca837 100644 --- a/samples/Arducam/app/application.cpp +++ b/samples/Arducam/app/application.cpp @@ -75,7 +75,7 @@ void initCam() { Serial.printf("ArduCAM init!"); // initialize I2C - Wire.pins(CAM_SCL, CAM_SDA); + Wire.pins(CAM_SDA, CAM_SCL); Wire.begin(); //Check if the camera module type is OV2640 diff --git a/samples/Basic_ScannerI2C/app/application.cpp b/samples/Basic_ScannerI2C/app/application.cpp index 889e24d298..58d820748c 100644 --- a/samples/Basic_ScannerI2C/app/application.cpp +++ b/samples/Basic_ScannerI2C/app/application.cpp @@ -81,10 +81,10 @@ void init() WDT.enable(false); // First (but not the best) option: fully disable watch dog timer - // Default I2C pins (SCL:0 , SDA: 2) + // Default I2C pins (SDA: 2, SCL:0) // You can change pins: - //Wire.pins(12, 14); // SCL, SDA + //Wire.pins(14, 12); // SDA, SCL Wire.begin(); procTimer.initializeMs(3000, scanBus).start(); diff --git a/samples/DS3232RTC_NTP_Setter/app/application.cpp b/samples/DS3232RTC_NTP_Setter/app/application.cpp index b0f07492e0..4f2d43b23d 100644 --- a/samples/DS3232RTC_NTP_Setter/app/application.cpp +++ b/samples/DS3232RTC_NTP_Setter/app/application.cpp @@ -41,7 +41,7 @@ void init() { Serial.begin(SERIAL_BAUD_RATE); Serial.println("Sming DSRTC_NTP_SETTER started!"); - Wire.pins(0, 2); //Change to your SCL - 0,SDA - 2 GPIO pin number + Wire.pins(2, 0); //Change to your SDA - 2, SCL - 0 GPIO pin number Wire.begin(); // Station - WiFi client diff --git a/samples/Humidity_AM2321/app/application.cpp b/samples/Humidity_AM2321/app/application.cpp index fd3afb8f8e..5949c3d1e9 100644 --- a/samples/Humidity_AM2321/app/application.cpp +++ b/samples/Humidity_AM2321/app/application.cpp @@ -31,7 +31,7 @@ void init() delay(500); // Apply I2C pins - Wire.pins(SCL, SDA); + Wire.pins(SDA, SCL); Wire.begin(); am2321.begin(); // REQUIRED. Call it after choosing I2C pins. diff --git a/samples/Humidity_SI7021/app/application.cpp b/samples/Humidity_SI7021/app/application.cpp index dd0b1772da..eb4ed1383e 100644 --- a/samples/Humidity_SI7021/app/application.cpp +++ b/samples/Humidity_SI7021/app/application.cpp @@ -84,7 +84,7 @@ void init() Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Allow debug output to serial Serial.print("Start I2c"); - Wire.pins(I2C_SCL, I2C_SDA); // SCL, SDA + Wire.pins(I2C_SDA, I2C_SCL); // SDA, SCL Wire.begin(); procTimer_ht.initializeMs(10000, si_read_ht).start(); procTimer_olt.initializeMs(15000, si_read_olt).start(); diff --git a/samples/MeteoControl_mqtt/app/application.cpp b/samples/MeteoControl_mqtt/app/application.cpp index aa81e93e43..b73c03dd57 100644 --- a/samples/MeteoControl_mqtt/app/application.cpp +++ b/samples/MeteoControl_mqtt/app/application.cpp @@ -14,7 +14,7 @@ void init() { Serial.begin(SERIAL_BAUD_RATE); // 115200 by default - Wire.pins(5, 4); // SCL, SDA + Wire.pins(4, 5); // SDA, SCL Wire.begin(); // initialization config diff --git a/samples/PortExpander_MCP23017/app/application.cpp b/samples/PortExpander_MCP23017/app/application.cpp index 6810c50b23..e42d3680d1 100644 --- a/samples/PortExpander_MCP23017/app/application.cpp +++ b/samples/PortExpander_MCP23017/app/application.cpp @@ -18,7 +18,7 @@ void init() Serial.begin(115200); // You can select ESP I2C pins here: - //Wire.pins(4, 5); // SCL, SDA + //Wire.pins(5, 4); // SDA, SCL mcp.begin(0); // 0 - for default mcp address, possible values: 0..7 From 7aa3d4c2837ad122ca4e3124566f3a9a11938cbd Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 27 Jul 2017 15:31:45 +0200 Subject: [PATCH 04/33] Added Gitter Notifications. (#1205) --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index c5cd0aa543..2d6c6ba0e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,3 +64,10 @@ deploy: on: tags: true condition: $DEPLOY == true + +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/c1a5e8bc97d3794a0417 + on_success: always # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always From c6df682a127b22550a1471f89d4c5680b039b050 Mon Sep 17 00:00:00 2001 From: slaff Date: Sat, 29 Jul 2017 10:12:04 +0200 Subject: [PATCH 05/33] Added dynamic recalculation of image offsets to prever rom overlapping. (#1208) --- Sming/Makefile-project.mk | 42 ++++++++++++++++++++++++++++++--------- samples/.gitignore | 1 + 2 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 samples/.gitignore diff --git a/Sming/Makefile-project.mk b/Sming/Makefile-project.mk index 03e7b76c53..3d2e4ab568 100644 --- a/Sming/Makefile-project.mk +++ b/Sming/Makefile-project.mk @@ -41,10 +41,10 @@ SPIFFY ?= $(SMING_HOME)/spiffy/spiffy #ESPTOOL2 config to generate rBootLESS images IMAGE_MAIN ?= 0x00000.bin -IMAGE_SDK ?= 0x0a000.bin # The name must match the starting address of the irom0 section - # in the LD file ($SMING_HOME/compiler/ld/standalone.rom.ld). - # To calculate the value do the following: x = irom0_0_seg.org - 0x40200000 - # Example: 0x4020a000 - 0x40200000 = 0x0a000 +IMAGE_SDK_OFFSET = $(shell printf '0x%x\n' $$(( ($$($(GET_FILESIZE) $(FW_BASE)/$(IMAGE_MAIN)) + 0x1000 + $(basename $(IMAGE_MAIN))) & (0xFFFFF000) )) ) +IMAGE_SDK ?= $(IMAGE_SDK_OFFSET).bin +IROM0_ORG0 = $(shell printf '0x%x\n' $$(( 0x40200000 + $(IMAGE_SDK_OFFSET))) ) + INIT_BIN_ADDR = 0x7c000 BLANK_BIN_ADDR = 0x4b000 @@ -55,6 +55,9 @@ ESPTOOL2_SECTS ?= .text .data .rodata ESPTOOL2_MAIN_ARGS ?= -quiet -bin -boot0 ESPTOOL2_SDK_ARGS ?= -quiet -lib +# SED path +SED ?= sed + ## ESP_HOME sets the path where ESP tools and SDK are located. ## Windows: # ESP_HOME = c:/Espressif @@ -259,6 +262,8 @@ LDFLAGS = -nostdlib -u call_user_start -Wl,-static -Wl,--gc-sections -Wl,-Map=$ # linker script used for the above linkier step LD_PATH = $(SMING_HOME)/compiler/ld +PROJECT_LD_PATH=ld + LD_SCRIPT = standalone.rom.ld ifeq ($(SPI_SPEED), 26) @@ -367,9 +372,28 @@ all: $(USER_LIBDIR)/lib$(LIBSMING).a checkdirs $(TARGET_OUT) $(SPIFF_BIN_OUT) $( spiff_update: spiff_clean $(SPIFF_BIN_OUT) -$(TARGET_OUT): $(APP_AR) - $(vecho) "LD $@" - $(Q) $(LD) -L$(USER_LIBDIR) -L$(SDK_LIBDIR) -L$(LD_PATH) -T$(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ +$(PROJECT_LD_PATH)/$(LD_SCRIPT): + $(Q) mkdir -p $(PROJECT_LD_PATH) + $(Q) cp $(LD_PATH)/$(LD_SCRIPT) $@ + +$(FW_BASE)/$(IMAGE_MAIN): $(APP_AR) +# Pass 1: Generate rom0 to be able to check its size + $(Q) $(LD) -L$(USER_LIBDIR) -L$(SDK_LIBDIR) -L$(LD_PATH) -T$(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $(TARGET_OUT).tmp + + $(Q) $(STRIP) $(TARGET_OUT).tmp + + $(Q) $(ESPTOOL2) $(ESPTOOL2_MAIN_ARGS) $(TARGET_OUT).tmp $@ $(ESPTOOL2_SECTS) + + $(Q) rm $(TARGET_OUT).tmp + +$(TARGET_OUT): $(FW_BASE)/$(IMAGE_MAIN) $(PROJECT_LD_PATH)/$(LD_SCRIPT) + $(vecho) "LD $@" + +# Readjust linker + $(Q) $(SED) -r "s/(^\s*irom0_0_seg *: *).*/\\1org = $(IROM0_ORG0), len = \(1M - $(IMAGE_SDK_OFFSET)\)/" $(LD_PATH)/$(LD_SCRIPT) > $(PROJECT_LD_PATH)/$(LD_SCRIPT) + +# Pass 2: Generate roms with correct offsets + $(Q) $(LD) -L$(USER_LIBDIR) -L$(SDK_LIBDIR) -L$(PROJECT_LD_PATH) -L$(LD_PATH) -T$(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ $(Q) $(STRIP) $@ @@ -454,9 +478,9 @@ flash: all $(vecho) "Killing Terminal to free $(COM_PORT)" -$(Q) $(KILL_TERM) ifeq ($(DISABLE_SPIFFS), 1) - $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) $(basename $(IMAGE_MAIN)) $(FW_BASE)/$(IMAGE_MAIN) $(basename $(IMAGE_SDK)) $(FW_BASE)/$(IMAGE_SDK) + $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) $(basename $(IMAGE_MAIN)) $(FW_BASE)/$(IMAGE_MAIN) $(IMAGE_SDK_OFFSET) $(FW_BASE)/$(IMAGE_SDK) else - $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) $(basename $(IMAGE_MAIN)) $(FW_BASE)/$(IMAGE_MAIN) $(basename $(IMAGE_SDK)) $(FW_BASE)/$(IMAGE_SDK) $(SPIFF_START_OFFSET) $(SPIFF_BIN_OUT) + $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) $(basename $(IMAGE_MAIN)) $(FW_BASE)/$(IMAGE_MAIN) $(IMAGE_SDK_OFFSET) $(FW_BASE)/$(IMAGE_SDK) $(SPIFF_START_OFFSET) $(SPIFF_BIN_OUT) endif $(TERMINAL) diff --git a/samples/.gitignore b/samples/.gitignore new file mode 100644 index 0000000000..003e406d3d --- /dev/null +++ b/samples/.gitignore @@ -0,0 +1 @@ +**/ld/standalone.rom.ld From b1bb00538bc1b8f9f8dfe4d04aa1e39610c2c473 Mon Sep 17 00:00:00 2001 From: slaff Date: Sat, 29 Jul 2017 10:13:24 +0200 Subject: [PATCH 06/33] Appvoyer CI will use the updated choco packages. (#1210) * Move to using the update choco repository. * Build with SDK 1.5.0 and SDK 2.0.0 --- appveyor.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0810e32159..2ab96b8a4c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,15 +10,28 @@ environment: build_compiler: "mingw" build_bindings: 1 SDK_VERSION: 2.0.0 + - build_platform: "x86" + build_compiler: "mingw" + build_bindings: 1 + SDK_VERSION: 1.5.0 + # cache: # - src/ # preserve "packages" directory in the root of build folder but will reset it if packages.config is modified install: - - choco sources add -name kireevco -source 'https://www.myget.org/F/kireevco-chocolatey/' - - choco install -y esp8266-udk wget curl -# - C:\MinGW\bin\mingw-get install - - mkdir c:\Espressif\utils\ESP8266 - - cp c:\Espressif\utils\memanalyzer.exe c:\Espressif\utils\ESP8266\memanalyzer.exe - - cp c:\Espressif\utils\esptool.exe c:\Espressif\utils\ESP8266\esptool.exe + - choco sources add -name sming -source 'https://www.myget.org/F/sming/' + - ps: if($env:SDK_VERSION -eq '1.5.0') { + choco install esp8266-udk --source https://www.myget.org/F/kireevco-chocolatey/; + mkdir c:\Espressif\utils\ESP8266; + cp c:\Espressif\utils\memanalyzer.exe c:\Espressif\utils\ESP8266\memanalyzer.exe; + cp c:\Espressif\utils\esptool.exe c:\Espressif\utils\ESP8266\esptool.exe; + } + else { + choco install esp8266-udk + } + + + +# Install esptool2 - git clone https://github.com/raburton/esptool2 - cd esptool2 - make From 855933d10fe88fee52399930f80fa0362c2180a5 Mon Sep 17 00:00:00 2001 From: robertkendrick Date: Thu, 3 Aug 2017 07:53:11 +0100 Subject: [PATCH 07/33] Added WifiStation.connect() to Basic_rboot sample (#1215) Newer NoOS SDKs seem to need WifiStation.connect() before they will connect to the network. This has been added to the serialCallBack command handler. --- samples/Basic_rBoot/app/application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/Basic_rBoot/app/application.cpp b/samples/Basic_rBoot/app/application.cpp index 46b03d4565..48c7567e97 100644 --- a/samples/Basic_rBoot/app/application.cpp +++ b/samples/Basic_rBoot/app/application.cpp @@ -112,6 +112,7 @@ void serialCallBack(Stream& stream, char arrivedChar, unsigned short availableCh // connect to wifi WifiStation.config(WIFI_SSID, WIFI_PWD); WifiStation.enable(true); + WifiStation.connect(); } else if (!strcmp(str, "ip")) { Serial.printf("ip: %s mac: %s\r\n", WifiStation.getIP().toString().c_str(), WifiStation.getMAC().c_str()); } else if (!strcmp(str, "ota")) { From 43072bd847096ccfe51c630567484ac4005cc5ed Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 8 Aug 2017 10:15:28 +0200 Subject: [PATCH 08/33] Ported fix igmp issues. (#1218) --- Sming/system/include/lwip/igmp.h | 2 +- Sming/third-party/.patches/esp-open-lwip.patch | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Sming/system/include/lwip/igmp.h b/Sming/system/include/lwip/igmp.h index 8cf9a48104..f0c9dea3fa 100644 --- a/Sming/system/include/lwip/igmp.h +++ b/Sming/system/include/lwip/igmp.h @@ -96,7 +96,7 @@ void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLAS err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; void igmp_tmr(void)ICACHE_FLASH_ATTR; -#define LWIP_RAND() rand() +#define LWIP_RAND() os_random() #ifdef __cplusplus } #endif diff --git a/Sming/third-party/.patches/esp-open-lwip.patch b/Sming/third-party/.patches/esp-open-lwip.patch index 9e1875e5b6..21a025222f 100644 --- a/Sming/third-party/.patches/esp-open-lwip.patch +++ b/Sming/third-party/.patches/esp-open-lwip.patch @@ -306,3 +306,16 @@ index 24ca8bb..0c20b6a 100644 #endif /* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +diff --git a/include/lwip/igmp.h b/include/lwip/igmp.h +index c90adcd..f0c9dea 100644 +--- a/include/lwip/igmp.h ++++ b/include/lwip/igmp.h +@@ -96,7 +96,7 @@ void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLAS + err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; + err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR; + void igmp_tmr(void)ICACHE_FLASH_ATTR; +-#define LWIP_RAND() r_rand() ++#define LWIP_RAND() os_random() + #ifdef __cplusplus + } + #endif From 78bcb1d78f683f76a18f2f08e1a275a867f7c48f Mon Sep 17 00:00:00 2001 From: Vogler Hartmut Date: Sun, 23 Jul 2017 13:32:32 +0200 Subject: [PATCH 09/33] Add methods to config via WPS (ENABLE_WPS=1 must be set in make) Add ENABLE_WPS switches also to Makefile-rboot.mk Keep the current opmode unchanged while starting wps Expand readme for WPS notices --- Readme.md | 2 + Sming/Makefile | 5 ++ Sming/Makefile-project.mk | 6 +++ Sming/Makefile-rboot.mk | 7 +++ Sming/SmingCore/Platform/Station.cpp | 73 ++++++++++++++++++++++++++++ Sming/SmingCore/Platform/Station.h | 25 ++++++++++ 6 files changed, 118 insertions(+) diff --git a/Readme.md b/Readme.md index 5acd9f49d6..5573500d6e 100644 --- a/Readme.md +++ b/Readme.md @@ -27,6 +27,7 @@ Sming - Open Source framework for high efficiency WiFi SoC ESP8266 native develo * Out of the box support for OTA over HTTPS. * [SNI](https://tools.ietf.org/html/rfc6066#page-6) and [Maximum Fragment Length](https://tools.ietf.org/html/rfc6066#page-8) SSL support. * PWM support based on [Stefan Bruens PWM](https://github.com/StefanBruens/ESP8266_new_pwm.git) +* WPS support optional activatable * Optional custom heap allocation based on [Umm Malloc](https://github.com/rhempel/umm_malloc.git) * Based on Espressif NONOS SDK. Tested with versions 1.4, 1.5 and 2.0. @@ -62,6 +63,7 @@ n/a = The selected SDK is not available on that OS - Custom LWIP: (default: ON) By default we are using custom compiled LWIP stack instead of the binary one provided from Espressif. This is increasing the free memory and decreasing the space on the flash. All espconn_* functions are turned off by default. If your application requires the use of some of the espconn_* functions then add the ENABLE_ESPCONN=1 directive. See `Makefile-user.mk` from the [Basic_SmartConfig](https://github.com/SmingHub/Sming/blob/develop/samples/Basic_SmartConfig/Makefile-user.mk#L41) application for examples. If you would like to use the binary LWIP then you should turn off the custom LWIP compilation by providing `ENABLE_CUSTOM_LWIP=0`. - SSL: (default: OFF) The SSL support is not built-in by default to conserve resources. If you want to enable it then take a look at the [Readme](https://github.com/SmingHub/Sming/blob/develop/samples/Basic_Ssl/README.md) in the Basic_Ssl samples. - Custom PWM: (default: ON) If you don't want to use the [open PWM implementation](https://github.com/StefanBruens/ESP8266_new_pwm) then compile your application with `ENABLE_CUSTOM_PWM=0`. There is no need to recompile the Sming library. +- WPS: (default: OFF) The WPS support (Wi-Fi Protected Setup) is not built-in by default to reach small images sizes in cases, where no WPS is needed. To enable WPS, use the switch ENABLE_WPS=1 for compiling Sming. - Custom serial baud rate: (default: OFF) The default serial baud rate is 115200. If you want to change it to a higher baud rate you can recompile Sming and your application changing the `COM_SPEED_SERIAL` directive. For example `COM_SPEED_SERIAL=921600`. - Custom heap allocation: (default: OFF) If your application is experiencing heap fragmentation then you can try the [umm_malloc](https://github.com/rhempel/umm_malloc) heap allocation. To enable it compile Sming with `ENABLE_CUSTOM_HEAP=1`. In order to use it in your sample/application make sure to compile the sample with `ENABLE_CUSTOM_HEAP=1`. **Do not enable custom heap allocation and -mforce-l32 compiler flag together**. - Debug information log level and format: There are four debug levels: debug=3, info=2, warn=1, error=0. Using `DEBUG_VERBOSE_LEVEL` you can set the desired level (0-3). For example `DEBUG_VERBOSE_LEVEL=2` will show only info messages and above. Another make directive is `DEBUG_PRINT_FILENAME_AND_LINE=1` which enables printing the filename and line number of every debug line. This will require extra space on flash. Note: you can compile the Sming library with a set of debug directives and your project with another settings, this way you can control debugging sepparately for sming and your application code. diff --git a/Sming/Makefile b/Sming/Makefile index 49fbf68dfa..87a8d1d6a1 100644 --- a/Sming/Makefile +++ b/Sming/Makefile @@ -275,6 +275,11 @@ ifeq ($(ENABLE_SSL),1) CXXFLAGS += $(AXTLS_FLAGS) endif +ifeq ($(ENABLE_WPS), 1) + LIBS += wps + CFLAGS += -DENABLE_WPS=1 +endif + SRC_DIR := $(MODULES) BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES)) diff --git a/Sming/Makefile-project.mk b/Sming/Makefile-project.mk index 03e7b76c53..a711768b51 100644 --- a/Sming/Makefile-project.mk +++ b/Sming/Makefile-project.mk @@ -205,6 +205,9 @@ endif # libraries used in this project, mainly provided by the SDK LIBS = microc microgcc hal phy pp net80211 $(LIBLWIP) wpa $(LIBMAIN) $(LIBSMING) crypto $(LIBPWM) smartconfig $(EXTRA_LIBS) +ifeq ($(ENABLE_WPS),1) + LIBS += wps +endif # compiler flags using during compilation of source files CFLAGS = -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 -DCOM_SPEED_SERIAL=$(COM_SPEED_SERIAL) $(USER_CFLAGS) -DENABLE_CMD_EXECUTOR=$(ENABLE_CMD_EXECUTOR) @@ -221,6 +224,9 @@ else CFLAGS += -Os -g STRIP := @true endif +ifeq ($(ENABLE_WPS),1) + CFLAGS += -DENABLE_WPS=1 +endif #Append debug options CFLAGS += -DCUST_FILE_BASE=$$* -DDEBUG_VERBOSE_LEVEL=$(DEBUG_VERBOSE_LEVEL) -DDEBUG_PRINT_FILENAME_AND_LINE=$(DEBUG_PRINT_FILENAME_AND_LINE) diff --git a/Sming/Makefile-rboot.mk b/Sming/Makefile-rboot.mk index b26f761668..1564d5e7dc 100644 --- a/Sming/Makefile-rboot.mk +++ b/Sming/Makefile-rboot.mk @@ -205,6 +205,10 @@ else CFLAGS += -Os -g STRIP := @true endif +ifeq ($(ENABLE_WPS),1) + CFLAGS += -DENABLE_WPS=1 +endif + #Append debug options CFLAGS += -DCUST_FILE_BASE=$$* -DDEBUG_VERBOSE_LEVEL=$(DEBUG_VERBOSE_LEVEL) -DDEBUG_PRINT_FILENAME_AND_LINE=$(DEBUG_PRINT_FILENAME_AND_LINE) CXXFLAGS = $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11 -felide-constructors @@ -252,6 +256,9 @@ ifeq ($(ENABLE_CUSTOM_PWM), 1) endif LIBS = microc microgcc hal phy pp net80211 $(LIBLWIP) wpa $(LIBMAIN) $(LIBSMING) crypto $(LIBPWM) smartconfig $(EXTRA_LIBS) +ifeq ($(ENABLE_WPS),1) + LIBS += wps +endif # SSL support using axTLS ifeq ($(ENABLE_SSL),1) diff --git a/Sming/SmingCore/Platform/Station.cpp b/Sming/SmingCore/Platform/Station.cpp index 3e2c3ed84e..dde41ae049 100644 --- a/Sming/SmingCore/Platform/Station.cpp +++ b/Sming/SmingCore/Platform/Station.cpp @@ -388,6 +388,79 @@ void StationClass::smartConfigStop() { smartConfigCallback = NULL; } +#ifdef ENABLE_WPS +void StationClass::internalWpsConfig(wps_cb_status status) +{ + bool processInternal=true; + if (wpsConfigCallback){ + processInternal=wpsConfigCallback(status); + } + if (processInternal){ + switch (status) { + case WPS_CB_ST_SUCCESS: + debugf("wifi_wps_status_cb(): WPS_CB_ST_SUCCESS\n"); + wpsConfigStop(); + connect(); + break; + case WPS_CB_ST_FAILED: + debugf("wifi_wps_status_cb(): WPS_CB_ST_FAILED\n"); + wpsConfigStop(); + connect(); // try to reconnect with old config + break; + case WPS_CB_ST_TIMEOUT: + debugf("wifi_wps_status_cb(): WPS_CB_ST_TIMEOUT\n"); + wpsConfigStop(); + connect(); // try to reconnect with old config + break; + case WPS_CB_ST_WEP: + debugf("wifi_wps_status_cb(): WPS_CB_ST_WEP\n"); + break; + default : + debugf("wifi_wps_status_cb(): unknown wps_cb_status %d\n",status); + wpsConfigStop(); + connect(); // try to reconnect with old config + } + } +} + +void StationClass::staticWpsConfigCallback(wps_cb_status status) { + WifiStation.internalWpsConfig(status); +} + +bool StationClass::wpsConfigStart(WPSConfigDelegate callback) { + debugf("WPS start\n"); + wpsConfigCallback=callback; + wifi_station_disconnect(); + wifi_set_opmode_current(wifi_get_opmode() | STATION_MODE); + debugf("WPS stationmode activated\n"); + if(!wifi_wps_enable(WPS_TYPE_PBC)) { + debugf("StationClass::wpsConfigStart() : wps enable failed\n"); + return(false); + } + if(!wifi_set_wps_cb((wps_st_cb_t) &staticWpsConfigCallback)) { + debugf("StationClass::wpsConfigStart() : cb failed\n"); + return(false); + } + + if(!wifi_wps_start()) { + debugf("StationClass::wpsConfigStart() : wifi_wps_start() failed\n"); + return(false); + } + return(true); +} + +bool StationClass::beginWPSConfig() { + debugf("StationClass::beginWPSConfig()\n"); + return(wpsConfigStart()); +} + +void StationClass::wpsConfigStop() { + if(!wifi_wps_disable()) { + debugf("StationClass::wpsConfigStop() : wifi_wps_disable() failed\n"); + } +} +#endif + //////////// BssInfo::BssInfo(bss_info* info) diff --git a/Sming/SmingCore/Platform/Station.h b/Sming/SmingCore/Platform/Station.h index b78484ee5f..4c6f60fe4b 100644 --- a/Sming/SmingCore/Platform/Station.h +++ b/Sming/SmingCore/Platform/Station.h @@ -71,6 +71,9 @@ typedef Vector BssList; ///< List of BSS typedef Delegate ScanCompletedDelegate; ///< Scan complete handler function typedef Delegate ConnectionDelegate; ///< Connection handler function typedef Delegate SmartConfigDelegate; ///< Smart configuration handler function +#ifdef ENABLE_WPS +typedef Delegate WPSConfigDelegate; +#endif /** @} */ class StationClass : protected ISystemReadyHandler @@ -218,6 +221,25 @@ class StationClass : protected ISystemReadyHandler */ void smartConfigStop(); +#ifdef ENABLE_WPS + /** @brief Start WiFi station by WPS method + * @param callback Function to call on WiFi WPS Events (Default: none) + */ + bool wpsConfigStart(WPSConfigDelegate callback=NULL); + + /** @brief Start WiFi station by WPS method + * @param callback Function to call on WiFi staton smart configuration complete (Default: none) + */ + bool beginWPSConfig(); + + /** @brief Stop WiFi station WPS configuration + */ + void wpsConfigStop(); + + void internalWpsConfig(wps_cb_status status); + static void staticWpsConfigCallback(wps_cb_status status); +#endif + protected: virtual void onSystemReady(); static void staticScanCompleted(void *arg, STATUS status); @@ -231,6 +253,9 @@ class StationClass : protected ISystemReadyHandler private: ScanCompletedDelegate scanCompletedCallback; SmartConfigDelegate smartConfigCallback = NULL; +#ifdef ENABLE_WPS + WPSConfigDelegate wpsConfigCallback = NULL; +#endif bool runScan; }; From 7d28d063168b65b5c9522af4f0f970ddb484c96e Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Mon, 14 Aug 2017 08:20:01 +0200 Subject: [PATCH 10/33] WPS: Small changes to the documentation. --- Readme.md | 3 +-- Sming/SmingCore/Platform/Station.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 5573500d6e..726675a0c0 100644 --- a/Readme.md +++ b/Readme.md @@ -27,7 +27,6 @@ Sming - Open Source framework for high efficiency WiFi SoC ESP8266 native develo * Out of the box support for OTA over HTTPS. * [SNI](https://tools.ietf.org/html/rfc6066#page-6) and [Maximum Fragment Length](https://tools.ietf.org/html/rfc6066#page-8) SSL support. * PWM support based on [Stefan Bruens PWM](https://github.com/StefanBruens/ESP8266_new_pwm.git) -* WPS support optional activatable * Optional custom heap allocation based on [Umm Malloc](https://github.com/rhempel/umm_malloc.git) * Based on Espressif NONOS SDK. Tested with versions 1.4, 1.5 and 2.0. @@ -63,7 +62,7 @@ n/a = The selected SDK is not available on that OS - Custom LWIP: (default: ON) By default we are using custom compiled LWIP stack instead of the binary one provided from Espressif. This is increasing the free memory and decreasing the space on the flash. All espconn_* functions are turned off by default. If your application requires the use of some of the espconn_* functions then add the ENABLE_ESPCONN=1 directive. See `Makefile-user.mk` from the [Basic_SmartConfig](https://github.com/SmingHub/Sming/blob/develop/samples/Basic_SmartConfig/Makefile-user.mk#L41) application for examples. If you would like to use the binary LWIP then you should turn off the custom LWIP compilation by providing `ENABLE_CUSTOM_LWIP=0`. - SSL: (default: OFF) The SSL support is not built-in by default to conserve resources. If you want to enable it then take a look at the [Readme](https://github.com/SmingHub/Sming/blob/develop/samples/Basic_Ssl/README.md) in the Basic_Ssl samples. - Custom PWM: (default: ON) If you don't want to use the [open PWM implementation](https://github.com/StefanBruens/ESP8266_new_pwm) then compile your application with `ENABLE_CUSTOM_PWM=0`. There is no need to recompile the Sming library. -- WPS: (default: OFF) The WPS support (Wi-Fi Protected Setup) is not built-in by default to reach small images sizes in cases, where no WPS is needed. To enable WPS, use the switch ENABLE_WPS=1 for compiling Sming. +- WPS: (default: OFF) The WPS support (Wi-Fi Protected Setup) is not activated by default to preserve resources. To enable WPS, use the switch ENABLE_WPS=1 for compiling Sming. - Custom serial baud rate: (default: OFF) The default serial baud rate is 115200. If you want to change it to a higher baud rate you can recompile Sming and your application changing the `COM_SPEED_SERIAL` directive. For example `COM_SPEED_SERIAL=921600`. - Custom heap allocation: (default: OFF) If your application is experiencing heap fragmentation then you can try the [umm_malloc](https://github.com/rhempel/umm_malloc) heap allocation. To enable it compile Sming with `ENABLE_CUSTOM_HEAP=1`. In order to use it in your sample/application make sure to compile the sample with `ENABLE_CUSTOM_HEAP=1`. **Do not enable custom heap allocation and -mforce-l32 compiler flag together**. - Debug information log level and format: There are four debug levels: debug=3, info=2, warn=1, error=0. Using `DEBUG_VERBOSE_LEVEL` you can set the desired level (0-3). For example `DEBUG_VERBOSE_LEVEL=2` will show only info messages and above. Another make directive is `DEBUG_PRINT_FILENAME_AND_LINE=1` which enables printing the filename and line number of every debug line. This will require extra space on flash. Note: you can compile the Sming library with a set of debug directives and your project with another settings, this way you can control debugging sepparately for sming and your application code. diff --git a/Sming/SmingCore/Platform/Station.h b/Sming/SmingCore/Platform/Station.h index 4c6f60fe4b..2f0363c3e6 100644 --- a/Sming/SmingCore/Platform/Station.h +++ b/Sming/SmingCore/Platform/Station.h @@ -228,7 +228,6 @@ class StationClass : protected ISystemReadyHandler bool wpsConfigStart(WPSConfigDelegate callback=NULL); /** @brief Start WiFi station by WPS method - * @param callback Function to call on WiFi staton smart configuration complete (Default: none) */ bool beginWPSConfig(); From 3132cda3619a977144f1e28f81bd0f1e13182d31 Mon Sep 17 00:00:00 2001 From: Max Weller Date: Mon, 21 Aug 2017 12:28:47 +0200 Subject: [PATCH 11/33] fix python3 compatibility problem in decode-stacktrace --- tools/decode-stacktrace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/decode-stacktrace.py b/tools/decode-stacktrace.py index b1ac29e871..52628f7fc0 100755 --- a/tools/decode-stacktrace.py +++ b/tools/decode-stacktrace.py @@ -47,6 +47,6 @@ def extractAddresses(data): line = "\r\n".join(addresses)+"\r\n" # line = line.ljust(125," ") - pipe.stdin.write(line) + pipe.stdin.write(line.encode('ascii')) pipe.stdin.flush() From d408e7de1382c22c2ac0289a1a074821eb504186 Mon Sep 17 00:00:00 2001 From: Maya Posch Date: Mon, 4 Sep 2017 11:43:09 +0200 Subject: [PATCH 12/33] Add custom PWM compile flag to enable old PWM library behaviour. (#1237) --- Sming/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Sming/Makefile b/Sming/Makefile index 39d0b826d0..b5fba81462 100644 --- a/Sming/Makefile +++ b/Sming/Makefile @@ -221,6 +221,7 @@ LIBS = microc microgcc hal phy pp net80211 $(LIBLWIP) wpa main ENABLE_CUSTOM_PWM ?= 1 ifeq ($(ENABLE_CUSTOM_PWM), 1) THIRD_PARTY_DATA += third-party/pwm/pwm.c + CFLAGS += -DSDK_PWM_PERIOD_COMPAT_MODE=1 endif MFORCE32 := $(shell $(CC) --help=target | grep mforce-l32) From 7c759fca7dcf10455c4dddd8d906c97e75d38eea Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 19 Sep 2017 13:45:31 +0200 Subject: [PATCH 13/33] Updated Spiffs code to version 0.3.7 + fixes. (#1246) Developers will have to call `make dist-clean` in order to test the newer version. --- Sming/Services/SpifFS/spiffs_config.h | 18 ++++++++++++++++++ Sming/third-party/spiffs | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Sming/Services/SpifFS/spiffs_config.h b/Sming/Services/SpifFS/spiffs_config.h index 84436f6c5d..8a931a149a 100644 --- a/Sming/Services/SpifFS/spiffs_config.h +++ b/Sming/Services/SpifFS/spiffs_config.h @@ -35,6 +35,10 @@ #ifndef SPIFFS_CHECK_DBG #define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__) #endif +// Set spiffs debug output call for all api invocations. +#ifndef SPIFFS_API_DBG +#define SPIFFS_API_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) +#endif // Enable/disable API functions to determine exact number of bytes // for filedescriptor and cache buffers. Once decided for a configuration, @@ -103,6 +107,20 @@ #define SPIFFS_OBJ_NAME_LEN (32) #endif +// Maximum length of the metadata associated with an object. +// Setting to non-zero value enables metadata-related API but also +// changes the on-disk format, so the change is not backward-compatible. +// +// Do note: the meta length must never exceed +// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64) +// +// This is derived from following: +// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) + +// spiffs_object_ix_header fields + at least some LUT entries) +#ifndef SPIFFS_OBJ_META_LEN +#define SPIFFS_OBJ_META_LEN (0) +#endif + // Size of buffer allocated on stack used when copying data. // Lower value generates more read/writes. No meaning having it bigger // than logical page size. diff --git a/Sming/third-party/spiffs b/Sming/third-party/spiffs index 21fe570974..f5e26c4e93 160000 --- a/Sming/third-party/spiffs +++ b/Sming/third-party/spiffs @@ -1 +1 @@ -Subproject commit 21fe570974103f71cf7ff02f9888c77746fbc66d +Subproject commit f5e26c4e933189593a71c6b82cda381a7b21e41c From 73f0c0d208e16863bd24d9858c3c70bc45ed2d45 Mon Sep 17 00:00:00 2001 From: slaff Date: Tue, 19 Sep 2017 13:46:10 +0200 Subject: [PATCH 14/33] Allow HttpResponse::sendString to be used multiple times for a single response. (#1243) Fixes #1240. --- Sming/SmingCore/Network/Http/HttpResponse.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Sming/SmingCore/Network/Http/HttpResponse.cpp b/Sming/SmingCore/Network/Http/HttpResponse.cpp index 1715b23b70..7729df71a8 100644 --- a/Sming/SmingCore/Network/Http/HttpResponse.cpp +++ b/Sming/SmingCore/Network/Http/HttpResponse.cpp @@ -55,22 +55,20 @@ HttpResponse* HttpResponse::setHeader(const String& name, const String& value) bool HttpResponse::sendString(const String& text) { - MemoryDataStream* memStream = new MemoryDataStream(); - if (memStream->write((const uint8_t*)text.c_str(), text.length()) != text.length()) { - delete memStream; - return false; - } - - if (stream != NULL) - { + if (stream != NULL && stream->getStreamType() != eSST_Memory) { SYSTEM_ERROR("Stream already created"); delete stream; stream = NULL; } - stream = memStream; + if(stream == NULL) { + stream = new MemoryDataStream(); + } + + MemoryDataStream *writable = static_cast(stream); + bool success = (writable->write((const uint8_t*)text.c_str(), text.length()) == text.length()); - return true; + return success; } bool HttpResponse::hasHeader(const String& name) From ed94fb77d7e8a948e7fc6837844b48d1a94f933c Mon Sep 17 00:00:00 2001 From: tius2000 Date: Fri, 29 Sep 2017 17:54:00 +0200 Subject: [PATCH 15/33] m_printf: stacksize reduced (#1097) reduced buffer size from 256 to 128 bytes allocate more stack if required size is no longer limited --- Sming/system/m_printf.cpp | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/Sming/system/m_printf.cpp b/Sming/system/m_printf.cpp index 03971661ab..507f873e00 100644 --- a/Sming/system/m_printf.cpp +++ b/Sming/system/m_printf.cpp @@ -9,7 +9,7 @@ Descr: embedded very simple version of printf with float support #include #include "osapi.h" -#define MPRINTF_BUF_SIZE 256 +#define INITIAL_BUFFSIZE 128 static void defaultPrintChar(uart_t *uart, char c) { return uart_tx_one_char(c); @@ -62,27 +62,25 @@ int m_snprintf(char* buf, int length, const char *fmt, ...) return n; } -int m_vprintf ( const char * format, va_list arg ) +int m_vprintf(const char *fmt, va_list va) { - if(!cbc_printchar) - { - return 0; - } - - char buf[MPRINTF_BUF_SIZE], *p; - - int n = 0; - m_vsnprintf(buf, sizeof(buf), format, arg); - - p = buf; - while (p && n < sizeof(buf) && *p) - { - cbc_printchar(cbc_printchar_uart, *p); - n++; - p++; - } + size_t size = INITIAL_BUFFSIZE - 1; + + // need to retry if size is not big enough + while (1) { + char buffer[size + 1]; + size_t sz = m_vsnprintf(buffer, sizeof(buffer), fmt, va); + if (sz > size) { + size = sz; + continue; + } - return n; + const char *p = buffer; + while (char c = *p++) { + cbc_printchar(cbc_printchar_uart, c); + } + return sz; + } } /** From 481eeb1c3970e4a6ec3280da1b098dbffe9b9731 Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Mon, 9 Oct 2017 10:16:50 +0200 Subject: [PATCH 16/33] Makefile: clear rboot configuration when flashing (#1249) make flash always flashes image 0. If rboot is switched to image 1, device will sill boot second image. This flashes blank.bin over rboot configuration sector (0x1000 address). --- Sming/Makefile-rboot.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sming/Makefile-rboot.mk b/Sming/Makefile-rboot.mk index 1564d5e7dc..a75b30f0ce 100644 --- a/Sming/Makefile-rboot.mk +++ b/Sming/Makefile-rboot.mk @@ -534,10 +534,10 @@ flash: all -$(Q) $(KILL_TERM) ifeq ($(DISABLE_SPIFFS), 1) # flashes rboot and first rom - $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) 0x00000 $(RBOOT_BIN) 0x02000 $(RBOOT_ROM_0) + $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) 0x00000 $(RBOOT_BIN) 0x01000 $(SDK_BASE)/bin/blank.bin 0x02000 $(RBOOT_ROM_0) else # flashes rboot, first rom and spiffs - $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) 0x00000 $(RBOOT_BIN) 0x02000 $(RBOOT_ROM_0) $(RBOOT_SPIFFS_0) $(SPIFF_BIN_OUT) + $(ESPTOOL) -p $(COM_PORT) -b $(COM_SPEED_ESPTOOL) write_flash $(flashimageoptions) 0x00000 $(RBOOT_BIN) 0x01000 $(SDK_BASE)/bin/blank.bin 0x02000 $(RBOOT_ROM_0) $(RBOOT_SPIFFS_0) $(SPIFF_BIN_OUT) endif $(TERMINAL) From a1ac636bb691ad02c7d5e699a6da8a4cc9c592e7 Mon Sep 17 00:00:00 2001 From: slaff Date: Mon, 9 Oct 2017 22:40:53 +0200 Subject: [PATCH 17/33] Simplified and improved Http Client and Http Server stream handling (#1247) Added support for chunked transfer encoding. Added support for multipart streams. Sending and receiving data should require less memory. Fixed sending of big streams over SSL. Added sample that demos secure HTTP upload of a "big" local file to remote server. Sending of "endless" data from the HttpClient and HttpServer should work as expected. --- Sming/Libraries/ArduCAM/ArduCAMStream.cpp | 3 + Sming/Libraries/ArduCAM/ArduCAMStream.h | 18 +- Sming/SmingCore/CircularBuffer.cpp | 123 +++++++++ Sming/SmingCore/CircularBuffer.h | 101 ++++++++ Sming/SmingCore/DataSourceStream.cpp | 6 +- Sming/SmingCore/DataSourceStream.h | 26 +- Sming/SmingCore/Network/Http/HttpCommon.h | 11 + .../SmingCore/Network/Http/HttpConnection.cpp | 235 ++++++++++-------- Sming/SmingCore/Network/Http/HttpConnection.h | 14 +- Sming/SmingCore/Network/Http/HttpRequest.cpp | 6 +- Sming/SmingCore/Network/Http/HttpRequest.h | 6 +- Sming/SmingCore/Network/Http/HttpResponse.cpp | 8 +- Sming/SmingCore/Network/Http/HttpResponse.h | 6 +- .../Network/Http/HttpServerConnection.cpp | 179 ++++++++----- .../Network/Http/HttpServerConnection.h | 12 +- .../Network/Http/Stream/HttpChunkedStream.cpp | 74 ++++++ .../Network/Http/Stream/HttpChunkedStream.h | 69 +++++ .../Http/Stream/HttpMultipartStream.cpp | 109 ++++++++ .../Network/Http/Stream/HttpMultipartStream.h | 90 +++++++ Sming/SmingCore/Network/TcpClient.h | 7 +- Sming/SmingCore/Network/TcpConnection.cpp | 9 +- samples/Arducam/app/application.cpp | 49 ++-- samples/Basic_WebClient/Makefile-user.mk | 2 +- samples/Basic_WebClient/app/application.cpp | 39 ++- 24 files changed, 961 insertions(+), 241 deletions(-) create mode 100644 Sming/SmingCore/CircularBuffer.cpp create mode 100644 Sming/SmingCore/CircularBuffer.h create mode 100644 Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.cpp create mode 100644 Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.h create mode 100644 Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.cpp create mode 100644 Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.h diff --git a/Sming/Libraries/ArduCAM/ArduCAMStream.cpp b/Sming/Libraries/ArduCAM/ArduCAMStream.cpp index c21adcc247..54791f6667 100644 --- a/Sming/Libraries/ArduCAM/ArduCAMStream.cpp +++ b/Sming/Libraries/ArduCAM/ArduCAMStream.cpp @@ -78,6 +78,9 @@ bool ArduCAMStream::isFinished() { uint16_t ArduCAMStream::readMemoryBlock(char* data, int bufSize) { + if(!dataReady()) { + return 0; + } if (!transfer) { transfer = true; diff --git a/Sming/Libraries/ArduCAM/ArduCAMStream.h b/Sming/Libraries/ArduCAM/ArduCAMStream.h index 29416bc965..c1dd82734f 100644 --- a/Sming/Libraries/ArduCAM/ArduCAMStream.h +++ b/Sming/Libraries/ArduCAM/ArduCAMStream.h @@ -10,11 +10,10 @@ #include "ArduCAM.h" - #include "../../Services/HexDump/HexDump.h" -class ArduCAMStream: public IDataSourceStream { +class ArduCAMStream: public ReadWriteStream { public: ArduCAMStream(ArduCAM *cam); virtual ~ArduCAMStream(); @@ -25,6 +24,21 @@ class ArduCAMStream: public IDataSourceStream { virtual bool seek(int len); virtual bool isFinished(); + virtual size_t write(uint8_t charToWrite) + { + return 0; + } + + /** @brief Write chars to stream + * @param buffer Pointer to buffer to write to the stream + * @param size Quantity of chars to writen + * @retval size_t Quantity of chars written to stream + */ + virtual size_t write(const uint8_t *buffer, size_t size) + { + return 0; + } + bool dataReady(); size_t available(); diff --git a/Sming/SmingCore/CircularBuffer.cpp b/Sming/SmingCore/CircularBuffer.cpp new file mode 100644 index 0000000000..b005cd7172 --- /dev/null +++ b/Sming/SmingCore/CircularBuffer.cpp @@ -0,0 +1,123 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Initial code done by Ivan Grokhotkov as part of the esp8266 core for Arduino environment. + * https://github.com/esp8266/Arduino/blob/master/cores/esp8266/cbuf.h + * + * Adapted for Sming by Slavey Karadzhov + * + ****/ + +#include "CircularBuffer.h" + +CircularBuffer::CircularBuffer(int size): buffer(new char[size]), readPos(buffer), writePos(buffer), size(size) +{ + +} + +CircularBuffer::~CircularBuffer() +{ + delete[] buffer; +} + +StreamType CircularBuffer::getStreamType() +{ + return StreamType::eSST_Memory; +} + +uint16_t CircularBuffer::readMemoryBlock(char* data, int bufSize) +{ + size_t bytesAvailable = length(); + size_t sizeToRead = (bufSize < bytesAvailable) ? bufSize : bytesAvailable; + size_t sizeRead = sizeToRead; + char * start = readPos; + if(writePos < readPos && sizeToRead > (size_t) ((buffer + size) - readPos)) { + size_t topSize = (buffer + size) - readPos; + memcpy(data, readPos, topSize); + start = buffer; + sizeToRead -= topSize; + data += topSize; + } + memcpy(data, start, sizeToRead); + return sizeRead; +} + +bool CircularBuffer::seek(int len) +{ + if(len > length()) { + flush(); + return false; + } + + if(readPos < writePos) { + readPos += len; + } + else if(readPos + len > buffer + size) { + readPos = buffer + (len - (buffer + size - readPos)); + } + else { + readPos += len; + } + + return true; +} + +bool CircularBuffer::isFinished() +{ + return (length() < 1); +} + +int CircularBuffer::length() +{ + if(writePos >= readPos) { + return writePos - readPos; + } + return size - (readPos - writePos); +} + +size_t CircularBuffer::room() const +{ + if(writePos >= readPos) { + return size - (writePos - readPos) - 1; + } + return readPos - writePos - 1; +} + + +String CircularBuffer::id() +{ + // TODO: check if that is printing the address of the buffer... + return String((char *)&buffer); +} + +size_t CircularBuffer::write(uint8_t charToWrite) +{ + if(!room()) { + return 0; + } + + *writePos = charToWrite; + writePos = wrap(writePos + 1); + + return 1; +} + +size_t CircularBuffer::write(const uint8_t *data, size_t bufSize) +{ + size_t space = room(); + size_t sizeToWrite = (bufSize < space) ? bufSize : space; + size_t sizeWritten = sizeToWrite; + if(writePos >= readPos && sizeToWrite > (size_t) (buffer + size - writePos)) { + size_t topSize = buffer + size - writePos; + memcpy(writePos, data, topSize); + writePos = buffer; + sizeToWrite -= topSize; + data += topSize; + } + memcpy(writePos, data, sizeToWrite); + writePos = wrap(writePos + sizeToWrite); + return sizeWritten; +} diff --git a/Sming/SmingCore/CircularBuffer.h b/Sming/SmingCore/CircularBuffer.h new file mode 100644 index 0000000000..8eef647f14 --- /dev/null +++ b/Sming/SmingCore/CircularBuffer.h @@ -0,0 +1,101 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Initial code done by Ivan Grokhotkov as part of the esp8266 core for Arduino environment. + * https://github.com/esp8266/Arduino/blob/master/cores/esp8266/cbuf.h + * + * Adapted for Sming by Slavey Karadzhov + * + ****/ + +#ifndef _SMING_CORE_CIRCULARBUFFER_H_ +#define _SMING_CORE_CIRCULARBUFFER_H_ + +#include "DataSourceStream.h" + +/** + * @brief Circular stream class + * @ingroup stream + * + * @{ +*/ + +///Base class for data source stream +class CircularBuffer: public ReadWriteStream +{ +public: + CircularBuffer(int size); + + virtual ~CircularBuffer(); + + /** @brief Get the stream type + * @retval StreamType The stream type. + * @todo Return value of IDataSourceStream:getStreamType base class function should be of type StreamType, e.g. eSST_User + */ + virtual StreamType getStreamType(); + + /** @brief Read a block of memory + * @param data Pointer to the data to be read + * @param bufSize Quantity of chars to read + * @retval uint16_t Quantity of chars read + * @todo Should IDataSourceStream::readMemoryBlock return same data type as its bufSize param? + */ + virtual uint16_t readMemoryBlock(char* data, int bufSize); + + /** @brief Move read cursor + * @param len Position within stream to move cursor to + * @retval bool True on success. + */ + virtual bool seek(int len); + + /** @brief Check if stream is finished + * @retval bool True on success. + */ + virtual bool isFinished(); + + /** + * @brief Return the total length of the stream + * @retval int -1 is returned when the size cannot be determined + */ + virtual int length(); + + /** + * @brief Returns unique id of the resource. + * @retval String the unique id of the stream. + */ + virtual String id(); + + virtual size_t write(uint8_t charToWrite); + + /** @brief Write chars to stream + * @param buffer Pointer to buffer to write to the stream + * @param size Quantity of chars to writen + * @retval size_t Quantity of chars written to stream + */ + virtual size_t write(const uint8_t *buffer, size_t size); + + size_t room() const; + + inline void flush() { + readPos = buffer; + writePos = buffer; + } + +private: + inline char* wrap(char* ptr) const { + return (ptr == buffer + size) ? buffer: ptr; + } + + +private: + char* buffer = NULL; + char* readPos = NULL; + char* writePos = NULL; + int size = 0; +}; + +/** @} */ +#endif /* _SMING_CORE_CIRCULARBUFFER_H_ */ diff --git a/Sming/SmingCore/DataSourceStream.cpp b/Sming/SmingCore/DataSourceStream.cpp index 760c8d1b78..070e0bb051 100644 --- a/Sming/SmingCore/DataSourceStream.cpp +++ b/Sming/SmingCore/DataSourceStream.cpp @@ -17,10 +17,8 @@ MemoryDataStream::MemoryDataStream() MemoryDataStream::~MemoryDataStream() { - if(buf != NULL) { - free(buf); - buf = NULL; - } + free(buf); + buf = NULL; pos = NULL; size = 0; } diff --git a/Sming/SmingCore/DataSourceStream.h b/Sming/SmingCore/DataSourceStream.h index fd81116c66..e0b2a48cc1 100644 --- a/Sming/SmingCore/DataSourceStream.h +++ b/Sming/SmingCore/DataSourceStream.h @@ -89,8 +89,26 @@ class IDataSourceStream virtual String id() { return String(); } }; +class ReadWriteStream : public IDataSourceStream +{ +public: + virtual ~ReadWriteStream() {} + + virtual size_t write(uint8_t charToWrite) = 0; + + /** @brief Write chars to stream + * @param buffer Pointer to buffer to write to the stream + * @param size Quantity of chars to writen + * @retval size_t Quantity of chars written to stream + */ + virtual size_t write(const uint8_t *buffer, size_t size) = 0; + + //Use base class documentation + virtual uint16_t readMemoryBlock(char* data, int bufSize) = 0; +}; + /// Memory data stream class -class MemoryDataStream : public Print, public IDataSourceStream +class MemoryDataStream : public Print, public ReadWriteStream { public: /** @brief Memory data stream base class @@ -109,7 +127,7 @@ class MemoryDataStream : public Print, public IDataSourceStream /** @brief Get size of stream * @retval int Quantity of chars in stream * - * @deprecated Use getLength instead + * @deprecated Use length() instead */ int getStreamLength() { return size; } @@ -149,7 +167,7 @@ class MemoryDataStream : public Print, public IDataSourceStream }; /// File stream class -class FileStream : public IDataSourceStream +class FileStream : public ReadWriteStream { public: @@ -188,7 +206,7 @@ class FileStream : public IDataSourceStream * @brief Return the total length of the stream * @retval int -1 is returned when the size cannot be determined */ - int length() { return -1; } + int length() { return size; } virtual String id(); diff --git a/Sming/SmingCore/Network/Http/HttpCommon.h b/Sming/SmingCore/Network/Http/HttpCommon.h index 96bfc2a8d5..183d5a1fa0 100644 --- a/Sming/SmingCore/Network/Http/HttpCommon.h +++ b/Sming/SmingCore/Network/Http/HttpCommon.h @@ -65,4 +65,15 @@ typedef HashMap HttpParams; typedef HashMap HttpHeaders; typedef enum http_method HttpMethod; +enum HttpConnectionState +{ + eHCS_Ready = 0, + eHCS_StartSending, + eHCS_SendingHeaders, + eHCS_StartBody, + eHCS_SendingBody, + eHCS_Sent +}; + + #endif /* _SMING_CORE_HTTP_COMMON_H_ */ diff --git a/Sming/SmingCore/Network/Http/HttpConnection.cpp b/Sming/SmingCore/Network/Http/HttpConnection.cpp index 7d4e3c33d6..403069b02b 100644 --- a/Sming/SmingCore/Network/Http/HttpConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpConnection.cpp @@ -11,6 +11,7 @@ ****/ #include "HttpConnection.h" +#include "HttpChunkedStream.h" #include "../../Services/WebHelpers/escape.h" @@ -136,9 +137,9 @@ String HttpConnection::getResponseString() void HttpConnection::reset() { - if(currentRequest != NULL) { - delete currentRequest; - currentRequest = NULL; + if(incomingRequest != NULL) { + delete incomingRequest; + incomingRequest = NULL; } code = 0; @@ -169,12 +170,12 @@ int HttpConnection::staticOnMessageBegin(http_parser* parser) connection->reset(); - connection->currentRequest = connection->executionQueue.dequeue(); - if(connection->currentRequest == NULL) { + connection->incomingRequest = connection->executionQueue.dequeue(); + if(connection->incomingRequest == NULL) { return 1; // there are no requests in the queue } - if(connection->currentRequest->responseStream != NULL) { + if(connection->incomingRequest->responseStream != NULL) { connection->mode = eHCM_Stream; } else { @@ -192,39 +193,39 @@ int HttpConnection::staticOnMessageComplete(http_parser* parser) return -1; } - if(!connection->currentRequest) { + if(!connection->incomingRequest) { return -2; // no current request... } debugf("staticOnMessageComplete: Execution queue: %d, %s", connection->executionQueue.count(), - connection->currentRequest->uri.toString().c_str() + connection->incomingRequest->uri.toString().c_str() ); // we are finished with this request int hasError = 0; - if(connection->currentRequest->requestCompletedDelegate) { + if(connection->incomingRequest->requestCompletedDelegate) { bool success = (HTTP_PARSER_ERRNO(parser) == HPE_OK) && // false when the parsing has failed (connection->code >= 200 && connection->code <= 399); // false when the HTTP status code is not ok - hasError = connection->currentRequest->requestCompletedDelegate(*connection, success); + hasError = connection->incomingRequest->requestCompletedDelegate(*connection, success); } - if(connection->currentRequest->auth != NULL) { - connection->currentRequest->auth->setResponse(connection->getResponse()); + if(connection->incomingRequest->auth != NULL) { + connection->incomingRequest->auth->setResponse(connection->getResponse()); } - if(connection->currentRequest->retries > 0) { - connection->currentRequest->retries--; - return (connection->executionQueue.enqueue(connection->currentRequest)? 0: -1); + if(connection->incomingRequest->retries > 0) { + connection->incomingRequest->retries--; + return (connection->executionQueue.enqueue(connection->incomingRequest)? 0: -1); } - if(connection->currentRequest->responseStream != NULL) { - connection->currentRequest->responseStream->close(); - delete connection->currentRequest->responseStream; + if(connection->incomingRequest->responseStream != NULL) { + connection->incomingRequest->responseStream->close(); + delete connection->incomingRequest->responseStream; } - delete connection->currentRequest; - connection->currentRequest = NULL; + delete connection->incomingRequest; + connection->incomingRequest = NULL; if(!connection->executionQueue.count()) { connection->onConnected(ERR_OK); @@ -259,17 +260,17 @@ int HttpConnection::staticOnHeadersComplete(http_parser* parser) */ connection->code = parser->status_code; - if(connection->currentRequest == NULL) { + if(connection->incomingRequest == NULL) { // nothing to process right now... return 1; } int error = 0; - if(connection->currentRequest->headersCompletedDelegate) { - error = connection->currentRequest->headersCompletedDelegate(*connection, connection->responseHeaders); + if(connection->incomingRequest->headersCompletedDelegate) { + error = connection->incomingRequest->headersCompletedDelegate(*connection, connection->responseHeaders); } - if(!error && connection->currentRequest->method == HTTP_HEAD) { + if(!error && connection->incomingRequest->method == HTTP_HEAD) { error = 1; } @@ -326,8 +327,8 @@ int HttpConnection::staticOnBody(http_parser *parser, const char *at, size_t len return -1; } - if(connection->currentRequest->requestBodyDelegate) { - return connection->currentRequest->requestBodyDelegate(*connection, at, length); + if(connection->incomingRequest->requestBodyDelegate) { + return connection->incomingRequest->requestBodyDelegate(*connection, at, length); } if (connection->mode == eHCM_String) { @@ -335,10 +336,10 @@ int HttpConnection::staticOnBody(http_parser *parser, const char *at, size_t len return 0; } - if(connection->currentRequest->responseStream != NULL) { - int res = connection->currentRequest->responseStream->write((const uint8_t *)at, length); + if(connection->incomingRequest->responseStream != NULL) { + int res = connection->incomingRequest->responseStream->write((const uint8_t *)at, length); if (res != length) { - connection->currentRequest->responseStream->close(); + connection->incomingRequest->responseStream->close(); return 1; } } @@ -358,57 +359,100 @@ int HttpConnection::staticOnChunkComplete(http_parser* parser) { } #endif -err_t HttpConnection::onConnected(err_t err) { - if (err == ERR_OK) { - debugf("HttpConnection::onConnected: waitingQueue.count: %d", waitingQueue->count()); +void HttpConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) { - do { + if(!(sourceEvent == eTCE_Connected || sourceEvent == eTCE_Sent)) { + return; + } + + debugf("HttpConnection::onReadyToSendData: waitingQueue.count: %d", waitingQueue->count()); + + do { + if(state == eHCS_Sent) { + state = eHCS_Ready; + } + + if(state == eHCS_Ready) { HttpRequest* request = waitingQueue->peek(); if(request == NULL) { debugf("Nothing in the waiting queue"); + outgoingRequest = NULL; break; } + // if the executionQueue is not empty then we have to check if we can pipeline that request + if(executionQueue.count()) { + if(!(request->method == HTTP_GET || request->method == HTTP_HEAD)) { + // if the current request cannot be pipelined -> break; + break; + } + + // if we have previous request + if(outgoingRequest != NULL) { + if(!(outgoingRequest->method == HTTP_GET || outgoingRequest->method == HTTP_HEAD)) { + // the outgoing request does not allow pipelining + break; + } + } + } // executionQueue.count() + if(!executionQueue.enqueue(request)) { debugf("The working queue is full at the moment"); break; } waitingQueue->dequeue(); - send(request); - if(!(request->method == HTTP_GET || request->method == HTTP_HEAD)) { - // if the current request cannot be pipelined -> break; - break; + outgoingRequest = request; + state = eHCS_SendingHeaders; + sendRequestHeaders(request); + + break; + } + + if(state >= eHCS_StartSending && state < eHCS_Sent) { + if(state == eHCS_SendingHeaders) { + if(stream != NULL && !stream->isFinished()) { + break; + } + + state = eHCS_StartBody; } - HttpRequest* nextRequest = waitingQueue->peek(); - if(nextRequest != NULL && !(nextRequest->method == HTTP_GET || nextRequest->method == HTTP_HEAD)) { - // if the next request cannot be pipelined -> break for now - break; + if(sendRequestBody(outgoingRequest)) { + state = eHCS_Sent; + delete stream; + stream = NULL; + continue; } - } while(1); - } + } - TcpClient::onConnected(err); - return ERR_OK; + break; + + } while(true); + + TcpClient::onReadyToSendData(sourceEvent); } -void HttpConnection::send(HttpRequest* request) { +void HttpConnection::sendRequestHeaders(HttpRequest* request) { sendString(http_method_str(request->method) + String(" ") + request->uri.getPathWithQuery() + " HTTP/1.1\r\nHost: " + request->uri.Host + "\r\n"); + // TODO: represent the post params as stream ... + // Adjust the content-length request->headers["Content-Length"] = "0"; if(request->rawDataLength) { request->headers["Content-Length"] = String(request->rawDataLength); } - else if (request->stream != NULL && request->stream->length() > -1) { - request->headers["Content-Length"] = String(request->stream->length()); + else if (request->stream != NULL) { + if(request->stream->length() > -1) { + request->headers["Content-Length"] = String(request->stream->length()); + } + else { + request->headers.remove("Content-Length"); + } } - // TODO: represent the post params as stream ... - - if(!request->headers.contains("Content-Length")) { request->headers["Transfer-Encoding"] = "chunked"; } @@ -423,72 +467,61 @@ void HttpConnection::send(HttpRequest* request) { sendString(write.c_str()); } sendString("\r\n"); +} - // Send content +bool HttpConnection::sendRequestBody(HttpRequest* request) { + if(state == eHCS_StartBody) { + state = eHCS_SendingBody; + // if there is input raw data -> send it + if(request->rawDataLength > 0) { + TcpClient::send((const char*)request->rawData, (uint16_t)request->rawDataLength); + request->rawDataLength = 0; - // if there is input raw data -> send it - if(request->rawDataLength > 0) { - TcpClient::send((const char*)request->rawData, (uint16_t)request->rawDataLength); - } - else if(request->stream != NULL) { - send(request->stream); + return false; + } - debugf("Stream completed"); - delete request->stream; - request->stream = NULL; - } #if 0 + // Post Params should be also stream... + if (request->postParams.count()) { + for(int i = 0; i < request->postParams.count(); i++) { + // TODO: prevent memory fragmentation ... + char *dest = uri_escape(NULL, 0, request->postParams.valueAt(i).c_str(), request->postParams.valueAt(i).length()); + String write = request->postParams.keyAt(i) + "=" + String(dest) + "&"; + sendString(write.c_str()); + free(dest); + } + } +#endif - // Post Params should be also stream... + if(request->stream == NULL) { + return true; + } - else if (request->postParams.count()) { - for(int i = 0; i < request->postParams.count(); i++) { - // TODO: prevent memory fragmentation ... - char *dest = uri_escape(NULL, 0, request->postParams.valueAt(i).c_str(), request->postParams.valueAt(i).length()); - String write = request->postParams.keyAt(i) + "=" + String(dest) + "&"; - sendString(write.c_str()); - free(dest); + delete stream; + if(request->headers["Transfer-Encoding"] == "chunked") { + stream = new HttpChunkedStream(request->stream); + } + else { + stream = request->stream; // avoid intermediate buffers } + request->stream = NULL; + return false; } -#endif -} - -bool HttpConnection::send(IDataSourceStream* inputStream, bool forceCloseAfterSent /* = false*/) -{ - if(inputStream->length() != -1) { - // send the data as one big blob - do { - int len = 256; - char data[len]; - len = inputStream->readMemoryBlock(data, len); - TcpClient::send(data, len); - inputStream->seek(max(len, 0)); - } while(!inputStream->isFinished()); + if(stream == NULL) { + // we are done for now return true; } - // Send the data in chunked-encoding - - do { - int len = 256; - char data[len]; - len = inputStream->readMemoryBlock(data, len); - - // send the data in chunks... - sendString(String(len)+ "\r\n"); - TcpClient::send(data, len); - sendString("\n\r"); - inputStream->seek(max(len, 0)); - } while(!inputStream->isFinished()); - - sendString("0\r\n\r\n", forceCloseAfterSent); + if(request->stream == NULL && !stream->isFinished()) { + return false; + } return true; } HttpRequest* HttpConnection::getRequest() { - return currentRequest; + return incomingRequest; } HttpResponse* HttpConnection::getResponse() { @@ -508,7 +541,7 @@ HttpResponse* HttpConnection::getResponse() { MemoryDataStream* memory = new MemoryDataStream(); memory->write((uint8_t *)responseStringData.c_str(), responseStringData.length()); - response->stream = (IDataSourceStream* )memory; + response->stream = memory; } return response; } diff --git a/Sming/SmingCore/Network/Http/HttpConnection.h b/Sming/SmingCore/Network/Http/HttpConnection.h index 2ea81f7072..019f71ee74 100644 --- a/Sming/SmingCore/Network/Http/HttpConnection.h +++ b/Sming/SmingCore/Network/Http/HttpConnection.h @@ -77,14 +77,11 @@ class HttpConnection : protected TcpClient { protected: void reset(); - virtual err_t onConnected(err_t err); virtual err_t onReceive(pbuf *buf); virtual err_t onProtocolUpgrade(http_parser* parser); - + virtual void onReadyToSendData(TcpConnectionEvent sourceEvent); virtual void onError(err_t err); - bool send(IDataSourceStream* inputStream, bool forceCloseAfterSent = false); - void cleanup(); private: @@ -102,6 +99,9 @@ class HttpConnection : protected TcpClient { #endif static int IRAM_ATTR staticOnMessageComplete(http_parser* parser); + void sendRequestHeaders(HttpRequest* request); + bool sendRequestBody(HttpRequest* request); + protected: HttpClientMode mode; String responseStringData; @@ -117,7 +117,11 @@ class HttpConnection : protected TcpClient { bool lastWasValue = true; String lastData = ""; String currentField = ""; - HttpRequest* currentRequest = NULL; + HttpRequest* incomingRequest = NULL; + HttpRequest* outgoingRequest = NULL; + +private: + HttpConnectionState state = eHCS_Ready; }; #endif /* _SMING_CORE_HTTP_CONNECTION_H_ */ diff --git a/Sming/SmingCore/Network/Http/HttpRequest.cpp b/Sming/SmingCore/Network/Http/HttpRequest.cpp index 26cd7607d6..7dddbc8b93 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.cpp +++ b/Sming/SmingCore/Network/Http/HttpRequest.cpp @@ -12,7 +12,7 @@ #include "HttpRequest.h" -HttpRequest::HttpRequest(URL uri) { +HttpRequest::HttpRequest(const URL& uri) { this->uri = uri; } @@ -209,7 +209,7 @@ HttpRequest* HttpRequest::setBody(const String& body) { if(written < body.length()) { debugf("HttpRequest::setBody: Unable to store the complete body"); } - stream = (IDataSourceStream*)memory; + stream = memory; return this; } @@ -219,7 +219,7 @@ HttpRequest* HttpRequest::setBody(uint8_t *rawData, size_t length) { return this; } -HttpRequest* HttpRequest::setBody(IDataSourceStream *stream) { +HttpRequest* HttpRequest::setBody(ReadWriteStream *stream) { this->stream = stream; return this; } diff --git a/Sming/SmingCore/Network/Http/HttpRequest.h b/Sming/SmingCore/Network/Http/HttpRequest.h index 23aac97ae3..59de80a991 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.h +++ b/Sming/SmingCore/Network/Http/HttpRequest.h @@ -35,7 +35,7 @@ class HttpRequest { public: - HttpRequest(URL uri); + HttpRequest(const URL& uri); HttpRequest(const HttpRequest& value); __forceinline HttpRequest* clone() const { return new HttpRequest(*this); } HttpRequest& operator = (const HttpRequest& rhs); @@ -107,7 +107,7 @@ class HttpRequest { #endif HttpRequest* setBody(const String& body); - HttpRequest* setBody(IDataSourceStream *stream); + HttpRequest* setBody(ReadWriteStream *stream); HttpRequest* setBody(uint8_t *rawData, size_t length); HttpRequest* setResponseStream(IOutputStream *stream); @@ -144,7 +144,7 @@ class HttpRequest { uint8_t *rawData = NULL; size_t rawDataLength = 0; - IDataSourceStream *stream = NULL; + ReadWriteStream *stream = NULL; IOutputStream *responseStream = NULL; diff --git a/Sming/SmingCore/Network/Http/HttpResponse.cpp b/Sming/SmingCore/Network/Http/HttpResponse.cpp index 7729df71a8..21505838fa 100644 --- a/Sming/SmingCore/Network/Http/HttpResponse.cpp +++ b/Sming/SmingCore/Network/Http/HttpResponse.cpp @@ -15,10 +15,8 @@ HttpResponse::~HttpResponse() { - if(stream != NULL) { - delete stream; - stream = NULL; - } + delete stream; + stream = NULL; } HttpResponse* HttpResponse::setContentType(const String& type) @@ -162,7 +160,7 @@ bool HttpResponse::sendJsonObject(JsonObjectStream* newJsonStreamInstance) return true; } -bool HttpResponse::sendDataStream( IDataSourceStream * newDataStream , const String& reqContentType /* = "" */) +bool HttpResponse::sendDataStream( ReadWriteStream * newDataStream , const String& reqContentType /* = "" */) { if (stream != NULL) { diff --git a/Sming/SmingCore/Network/Http/HttpResponse.h b/Sming/SmingCore/Network/Http/HttpResponse.h index c0a57def4f..97a387da96 100644 --- a/Sming/SmingCore/Network/Http/HttpResponse.h +++ b/Sming/SmingCore/Network/Http/HttpResponse.h @@ -74,19 +74,19 @@ class HttpResponse { // @end deprecated // Send Datastream, can be called with Classes derived from - bool sendDataStream( IDataSourceStream * newDataStream , enum MimeType type) { + bool sendDataStream( ReadWriteStream * newDataStream , enum MimeType type) { return sendDataStream(newDataStream, ContentType::toString(type)); } // Send Datastream, can be called with Classes derived from - bool sendDataStream( IDataSourceStream * newDataStream , const String& reqContentType = "" ); + bool sendDataStream( ReadWriteStream * newDataStream , const String& reqContentType = "" ); void reset(); public: int code; HttpHeaders headers; - IDataSourceStream* stream = NULL; + ReadWriteStream* stream = NULL; }; #endif /* _SMING_CORE_HTTP_RESPONSE_H_ */ diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp index d672da16cd..f9309ffddc 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp @@ -16,6 +16,7 @@ #include "TcpServer.h" #include "../../Services/cWebsocket/websocket.h" #include "WebConstants.h" +#include "HttpChunkedStream.h" bool HttpServerConnection::parserSettingsInitialized = false; http_parser_settings HttpServerConnection::parserSettings; @@ -73,7 +74,6 @@ int HttpServerConnection::staticOnMessageBegin(http_parser* parser) connection->response.stream = NULL; } - connection->headersSent = false; connection->state = eHCS_Ready; // ... and Request @@ -347,101 +347,149 @@ err_t HttpServerConnection::onReceive(pbuf *buf) void HttpServerConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) { - if(state != eHCS_Sending) { - TcpClient::onReadyToSendData(sourceEvent); + if(sourceEvent == eTCE_Poll) { return; } - bool sendContent = (request.method != HTTP_HEAD); + if(state == eHCS_Sent) { + state = eHCS_Ready; + } - if(!headersSent) { -#ifndef DISABLE_HTTPSRV_ETAG - if(response.stream != NULL && !response.headers.contains("ETag")) { - String tag = response.stream->id(); - if(tag.length() > 0) { - response.headers["ETag"] = String('"' + tag + '"'); - } + do { + + if(!(state >= eHCS_StartSending && state < eHCS_Sent)) { + break; + } + + if(state == eHCS_StartSending) { + sendResponseHeaders(&response); + state = eHCS_SendingHeaders; + break; } - if(request.headers.contains("If-Match") && response.headers.contains("ETag") && - request.headers["If-Match"] == response.headers["ETag"]) { - if(request.method == HTTP_GET || request.method == HTTP_HEAD) { - response.code = HTTP_STATUS_NOT_MODIFIED; - response.headers["Content-Length"] = "0"; - sendContent = false; + if(state == eHCS_SendingHeaders) { + if(stream != NULL && !stream->isFinished()) { + break; } + + state = eHCS_StartBody; } -#endif /* DISABLE_HTTPSRV_ETAG */ - String statusLine = "HTTP/1.1 "+String(response.code) + " " + getStatus((enum http_status)response.code) + "\r\n"; - writeString(statusLine, TCP_WRITE_FLAG_MORE | TCP_WRITE_FLAG_COPY); - if(response.stream != NULL && response.stream->length() != -1) { - response.headers["Content-Length"] = String(response.stream->length()); + if(sendResponseBody(&response)) { + delete stream; + stream = NULL; + state = eHCS_Sent; } - if(!response.headers.contains("Content-Length") && response.stream == NULL) { - response.headers["Content-Length"] = "0"; + + break; + + } while(false); + + if(state == eHCS_Sent && response.headers["Connection"] == "close") { + setTimeOut(1); // decrease the timeout to 1 tick + } + + if(state == eHCS_Sent) { + response.reset(); + request.reset(); + } + + TcpClient::onReadyToSendData(sourceEvent); +} + +void HttpServerConnection::sendResponseHeaders(HttpResponse* response) +{ +#ifndef DISABLE_HTTPSRV_ETAG + if(response->stream != NULL && !response->headers.contains("ETag")) { + String tag = response->stream->id(); + if(tag.length() > 0) { + response->headers["ETag"] = String('"' + tag + '"'); } + } - if(!response.headers.contains("Connection")) { - if(request.headers.contains("Connection") && request.headers["Connection"] == "close") { - // the other side requests closing of the tcp connection... - response.headers["Connection"] = "close"; - } - else { - response.headers["Connection"] = "keep-alive"; // Keep-Alive to reuse the connection - } + if(request.headers.contains("If-Match") && response->headers.contains("ETag") && + request.headers["If-Match"] == response->headers["ETag"]) { + if(request.method == HTTP_GET || request.method == HTTP_HEAD) { + response->code = HTTP_STATUS_NOT_MODIFIED; + response->headers["Content-Length"] = "0"; + delete response->stream; + response->stream = NULL; + } + } +#endif /* DISABLE_HTTPSRV_ETAG */ + String statusLine = "HTTP/1.1 "+String(response->code) + " " + getStatus((enum http_status)response->code) + "\r\n"; + sendString(statusLine.c_str()); + if(response->stream != NULL && response->stream->length() != -1) { + response->headers["Content-Length"] = String(response->stream->length()); + } + if(!response->headers.contains("Content-Length") && response->stream == NULL) { + response->headers["Content-Length"] = "0"; + } + + if(!response->headers.contains("Connection")) { + if(request.headers.contains("Connection") && request.headers["Connection"] == "close") { + // the other side requests closing of the tcp connection... + response->headers["Connection"] = "close"; } + else { + response->headers["Connection"] = "keep-alive"; // Keep-Alive to reuse the connection + } + } #if HTTP_SERVER_EXPOSE_NAME == 1 - response.headers["Server"] = "HttpServer/Sming"; + response->headers["Server"] = "HttpServer/Sming"; #endif #if HTTP_SERVER_EXPOSE_DATE == 1 - response.headers["Date"] = SystemClock.getSystemTimeString(); + response->headers["Date"] = SystemClock.getSystemTimeString(); #endif - for (int i = 0; i < response.headers.count(); i++) - { - String write = response.headers.keyAt(i) + ": " + response.headers.valueAt(i) + "\r\n"; - writeString(write.c_str(), TCP_WRITE_FLAG_MORE | TCP_WRITE_FLAG_COPY); - } - writeString("\r\n", TCP_WRITE_FLAG_MORE | TCP_WRITE_FLAG_COPY); - headersSent = true; + for (int i = 0; i < response->headers.count(); i++) + { + String write = response->headers.keyAt(i) + ": " + response->headers.valueAt(i) + "\r\n"; + sendString(write.c_str()); } + sendString("\r\n"); +} - do { - if(sendContent == false) { - if(response.stream != NULL) { - delete response.stream; - response.stream = NULL; +bool HttpServerConnection::sendResponseBody(HttpResponse *response) +{ + if (state == eHCS_StartBody) { + state = eHCS_SendingBody; + if(request.method == HTTP_HEAD) { + if(response->stream != NULL) { + delete response->stream; + response->stream = NULL; } - state = eHCS_Sent; - break; + return true; } - if(response.stream == NULL) { - state = eHCS_Sent; - break; + if(response->stream == NULL) { + return true; } - write(response.stream); - if (response.stream->isFinished()) { - debugf("Body stream completed"); - delete response.stream; // Free memory now! - response.stream = NULL; - state = eHCS_Sent; + delete stream; + if(response->headers["Transfer-Encoding"] == "chunked") { + stream = new HttpChunkedStream(response->stream); } - } while(false); + else { + stream = response->stream; // avoid intermediate buffers + } + response->stream = NULL; - if(state == eHCS_Sent && response.headers["Connection"] == "close") { - setTimeOut(1); // decrease the timeout to 1 tick + return false; } - if(state == eHCS_Sent) { - response.reset(); - request.reset(); + if(stream == NULL) { + // we are done for now + return true; } - TcpClient::onReadyToSendData(sourceEvent); + if(response->stream == NULL && !stream->isFinished()) { + return false; + } + + return true; + } void HttpServerConnection::onError(err_t err) { @@ -460,7 +508,8 @@ const char * HttpServerConnection::getStatus(enum http_status code) void HttpServerConnection::send() { - state = eHCS_Sending; + state = eHCS_StartSending; + onReadyToSendData(eTCE_Received); } void HttpServerConnection::sendError(const char* message /* = NULL*/, enum http_status code /* = HTTP_STATUS_BAD_REQUEST */) diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.h b/Sming/SmingCore/Network/Http/HttpServerConnection.h index 6a68e415fa..e9f0818de2 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.h +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.h @@ -34,13 +34,6 @@ class HttpServerConnection; typedef Delegate HttpServerConnectionDelegate; -enum HttpConnectionState -{ - eHCS_Ready, - eHCS_Sending, - eHCS_Sent -}; - class HttpServerConnection: public TcpClient { public: @@ -71,6 +64,9 @@ class HttpServerConnection: public TcpClient static int IRAM_ATTR staticOnBody(http_parser *parser, const char *at, size_t length); static int IRAM_ATTR staticOnMessageComplete(http_parser* parser); + void sendResponseHeaders(HttpResponse* response); + bool sendResponseBody(HttpResponse* response); + public: void* userData = NULL; // << use to pass user data between requests @@ -87,8 +83,6 @@ class HttpServerConnection: public TcpClient HttpRequest request = HttpRequest(URL()); HttpResponse response; - bool headersSent = false; - HttpResourceDelegate headersCompleteDelegate = 0; HttpResourceDelegate requestCompletedDelegate = 0; HttpServerConnectionBodyDelegate onBodyDelegate = 0; diff --git a/Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.cpp b/Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.cpp new file mode 100644 index 0000000000..cd29889270 --- /dev/null +++ b/Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.cpp @@ -0,0 +1,74 @@ +#include "HttpChunkedStream.h" + +HttpChunkedStream::HttpChunkedStream(ReadWriteStream *stream) +{ + this->stream = stream; +} + +HttpChunkedStream::~HttpChunkedStream() +{ + delete tempStream; + delete stream; + tempStream = NULL; + stream = NULL; +} + +size_t HttpChunkedStream::write(uint8_t charToWrite) +{ + return stream->write(charToWrite); +} + +size_t HttpChunkedStream::write(const uint8_t *buffer, size_t size) +{ + return stream->write(buffer, size); +} + +uint16_t HttpChunkedStream::readMemoryBlock(char* data, int bufSize) +{ + const int readSize = NETWORK_SEND_BUFFER_SIZE; + + if(stream == NULL || stream->isFinished()) { + return 0; + } + + if(tempStream == NULL) { + tempStream = new CircularBuffer(readSize + 10); + } + + if(!tempStream->isFinished()) { + return tempStream->readMemoryBlock(data, bufSize); + } + + // pump new data into the stream + int len = readSize; + char buffer[len]; + len = stream->readMemoryBlock(buffer, len); + stream->seek(max(len, 0)); + if(len < 1) { + return 0; + } + + String content = String(len) + "\r\n"; + tempStream->write((uint8_t*)content.c_str(), content.length()); + tempStream->write((uint8_t*)buffer, len); + content = "\n\r"; + tempStream->write((uint8_t*)content.c_str(), content.length()); + if (len < readSize) { + content = "0\r\n\r\n"; + tempStream->write((uint8_t*)content.c_str(), content.length()); + } + + return tempStream->readMemoryBlock(data, bufSize); +} + +//Use base class documentation +bool HttpChunkedStream::seek(int len) +{ + return tempStream->seek(len); +} + +//Use base class documentation +bool HttpChunkedStream::isFinished() +{ + return (stream->isFinished() && tempStream->isFinished()); +} diff --git a/Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.h b/Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.h new file mode 100644 index 0000000000..0a962df04f --- /dev/null +++ b/Sming/SmingCore/Network/Http/Stream/HttpChunkedStream.h @@ -0,0 +1,69 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * @author Slavey Karadzhov + * + ****/ + +#ifndef _SMING_CORE_HTTP_CHUNKEDSTREAM_H_ +#define _SMING_CORE_HTTP_CHUNKEDSTREAM_H_ + +#include "../HttpCommon.h" +#include "../HttpResponse.h" +#include "../HttpRequest.h" +#include "../../../CircularBuffer.h" + +/** + * @brief HTTP chunked stream class + * @ingroup stream http + * + * @{ +*/ + +class HttpChunkedStream: public ReadWriteStream +{ +public: + HttpChunkedStream(ReadWriteStream *stream); + virtual ~HttpChunkedStream(); + + //Use base class documentation + virtual StreamType getStreamType() { return stream->getStreamType(); } + + /** + * @brief Return the total length of the stream + * @retval int -1 is returned when the size cannot be determined + */ + int length() { return stream->length(); } + + /** @brief Write a single char to stream + * @param charToWrite Char to write to the stream + * @retval size_t Quantity of chars written to stream (always 1) + */ + virtual size_t write(uint8_t charToWrite); + + /** @brief Write chars to stream + * @param buffer Pointer to buffer to write to the stream + * @param size Quantity of chars to written + * @retval size_t Quantity of chars written to stream + */ + virtual size_t write(const uint8_t *buffer, size_t size); + + //Use base class documentation + virtual uint16_t readMemoryBlock(char* data, int bufSize); + + //Use base class documentation + virtual bool seek(int len); + + //Use base class documentation + virtual bool isFinished(); + +private: + ReadWriteStream *stream = NULL; + CircularBuffer *tempStream = NULL; +}; + +/** @} */ +#endif /* _SMING_CORE_HTTP_CHUNKEDSTREAM_H_ */ diff --git a/Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.cpp b/Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.cpp new file mode 100644 index 0000000000..c2d8b55678 --- /dev/null +++ b/Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.cpp @@ -0,0 +1,109 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * @author Slavey Karadzhov + * + ****/ + +#include "HttpMultipartStream.h" + +HttpMultipartStream::HttpMultipartStream(HttpPartProducerDelegate delegate): producer(delegate) +{ + +} + + +HttpMultipartStream::~HttpMultipartStream() +{ + delete stream; + stream = NULL; + delete nextStream; + nextStream = NULL; +} + +size_t HttpMultipartStream::write(uint8_t charToWrite) +{ + // TODO: those methods should not be used... + return 0; +} + +size_t HttpMultipartStream::write(const uint8_t *buffer, size_t size) +{ + // TODO: those methods should not be used... + return 0; +} + //Use base class documentation +uint16_t HttpMultipartStream::readMemoryBlock(char* data, int bufSize) +{ + if(stream != NULL && stream->isFinished()) { + delete stream; + stream = NULL; + } + + if(stream == NULL && nextStream != NULL) { + stream = nextStream; + nextStream = NULL; + } + + if(stream == NULL) { + HttpPartResult result = producer(); + stream = new MemoryDataStream(); + + String line = String("\r\n--") + getBoundary() + String("\r\n"); + stream->write((uint8_t *)line.c_str(), line.length()); + if(result.headers != NULL) { + + if(!result.headers->contains("Content-Length") ) { + if(result.stream != NULL && result.stream->length() > -1) { + (*result.headers)["Content-Length"] = result.stream->length(); + } + } + + for (int i = 0; i < result.headers->count(); i++) { + line = result.headers->keyAt(i) + ": " + result.headers->valueAt(i) + "\r\n"; + stream->write((uint8_t *)line.c_str(), line.length()); + } + + delete result.headers; + result.headers = NULL; + } + line = "\r\n"; + stream->write((uint8_t *)line.c_str(), line.length()); + + nextStream = result.stream; + } + + return stream->readMemoryBlock(data, bufSize); +} + +bool HttpMultipartStream::seek(int len) +{ + return stream->seek(len); +} + +bool HttpMultipartStream::isFinished() +{ + return false; +} + +const char* HttpMultipartStream::getBoundary() +{ + if(boundary[0] == 0) { + static const char pool[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + int len = sizeof(boundary); + memset(boundary, 0, len); + for (int i = 0; i < len - 1; ++i) { + boundary[i] = pool[os_random() % (sizeof(pool) - 1)]; + } + boundary[len - 1] = 0; + } + + return boundary; +} diff --git a/Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.h b/Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.h new file mode 100644 index 0000000000..28bea02cd3 --- /dev/null +++ b/Sming/SmingCore/Network/Http/Stream/HttpMultipartStream.h @@ -0,0 +1,90 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/SmingHub/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * @author Slavey Karadzhov + * + ****/ + +#ifndef _SMING_CORE_HTTP_MPARTSTREAM_H_ +#define _SMING_CORE_HTTP_MPARTSTREAM_H_ + +#include "../HttpCommon.h" +#include "../HttpResponse.h" +#include "../HttpRequest.h" +#include "../../../Delegate.h" + +/** + * @brief HTTP multipart stream class + * @ingroup stream http + * + * @{ +*/ + +typedef struct { + HttpHeaders* headers = NULL; + ReadWriteStream* stream = NULL; +} HttpPartResult; + +typedef Delegate HttpPartProducerDelegate; + +class HttpMultipartStream: public ReadWriteStream +{ +public: + HttpMultipartStream(HttpPartProducerDelegate delegate); + virtual ~HttpMultipartStream(); + + //Use base class documentation + virtual StreamType getStreamType() { + // TODO: fix this... + return stream->getStreamType(); + } + + /** + * @brief Return the total length of the stream + * @retval int -1 is returned when the size cannot be determined + */ + int length() { return -1; } + + /** @brief Write a single char to stream + * @param charToWrite Char to write to the stream + * @retval size_t Quantity of chars written to stream (always 1) + */ + virtual size_t write(uint8_t charToWrite); + + /** @brief Write chars to stream + * @param buffer Pointer to buffer to write to the stream + * @param size Quantity of chars to written + * @retval size_t Quantity of chars written to stream + */ + virtual size_t write(const uint8_t *buffer, size_t size); + + //Use base class documentation + virtual uint16_t readMemoryBlock(char* data, int bufSize); + + //Use base class documentation + virtual bool seek(int len); + + //Use base class documentation + virtual bool isFinished(); + + /** + * @brief Returns the generated boundary + * + * @retval const char* + */ + const char* getBoundary(); + +private: + HttpPartProducerDelegate producer; + + ReadWriteStream *stream = NULL; + ReadWriteStream *nextStream = NULL; + + char boundary[16] = {0}; +}; + +/** @} */ +#endif /* _SMING_CORE_HTTP_MPARTSTREAM_H_ */ diff --git a/Sming/SmingCore/Network/TcpClient.h b/Sming/SmingCore/Network/TcpClient.h index 4f27342ca0..7b67e78ce6 100644 --- a/Sming/SmingCore/Network/TcpClient.h +++ b/Sming/SmingCore/Network/TcpClient.h @@ -18,7 +18,7 @@ #include "../Delegate.h" class TcpClient; -class MemoryDataStream; +class ReadWriteStream; class IPAddress; //typedef void (*TcpClientEventDelegate)(TcpClient& client, TcpConnectionEvent sourceEvent); @@ -78,12 +78,15 @@ class TcpClient : public TcpConnection void pushAsyncPart(); +protected: + ReadWriteStream* stream = nullptr; + private: TcpClientState state; TcpClientCompleteDelegate completed = nullptr; TcpClientDataDelegate receive = nullptr; TcpClientEventDelegate ready = nullptr; - MemoryDataStream* stream = nullptr; + bool asyncCloseAfterSent = false; int16_t asyncTotalSent = 0; int16_t asyncTotalLen = 0; diff --git a/Sming/SmingCore/Network/TcpConnection.cpp b/Sming/SmingCore/Network/TcpConnection.cpp index ee9e2066e4..f29399a53e 100644 --- a/Sming/SmingCore/Network/TcpConnection.cpp +++ b/Sming/SmingCore/Network/TcpConnection.cpp @@ -193,6 +193,13 @@ int TcpConnection::write(const char* data, int len, uint8_t apiflags /* = TCP_WR #ifdef ENABLE_SSL if(ssl) { + u16_t expected = ssl_calculate_write_length(ssl, len); + u16_t available = tcp ? tcp_sndbuf(tcp) : 0; +// debugf("SSL: Expected: %d, Available: %d", expected, available); + if (expected < 0 || available < expected) { + return -1; // No memory + } + int written = axl_ssl_write(ssl, (const uint8_t *)data, len); // debugf("SSL: Write len: %d, Written: %d", len, written); if(written < ERR_OK) { @@ -267,7 +274,7 @@ int TcpConnection::write(IDataSourceStream* stream) int written = write(buffer, available, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE); total += written; stream->seek(max(written, 0)); - debugf("Written: %d, Available: %d, isFinished: %d, PushCount: %d", written, available, (stream->isFinished()?1:0), pushCount); + debugf("Written: %d, Available: %d, isFinished: %d, PushCount: %d [TcpBuf: %d]", written, available, (stream->isFinished()?1:0), pushCount, tcp_sndbuf(tcp)); repeat = written == available && !stream->isFinished() && pushCount < 25; } else diff --git a/samples/Arducam/app/application.cpp b/samples/Arducam/app/application.cpp index 53fbfca837..f3eb0d9e55 100644 --- a/samples/Arducam/app/application.cpp +++ b/samples/Arducam/app/application.cpp @@ -14,6 +14,7 @@ #include #include +#include // If you want, you can define WiFi settings globally in Eclipse Environment Variables @@ -36,7 +37,7 @@ * RES (RESET) GPIO16 * DC (DC) GPIO2 */ -#define CAM_SCLK 14 // HW SPI pins - dont change +#define CAM_SCLK 14 // HW SPI pins - don't change #define CAM_MOSI 13 #define CAM_MISO 12 @@ -65,7 +66,7 @@ void startApplicationCommand() /* * initCam() * - * Initalize I2C, SPI Bus and check if the cammera is there + * Initialize I2C, SPI Bus and check if the camera is there * Initialize the camera for JPEG 320x240 * */ @@ -165,7 +166,7 @@ void onCamSetup(HttpRequest &request, HttpResponse &response) { /* - * http request to capture and send an image from the cammera + * http request to capture and send an image from the camera * uses actual setting set by ArdCammCommand Handler */ void onCapture(HttpRequest &request, HttpResponse &response) { @@ -187,13 +188,27 @@ void onCapture(HttpRequest &request, HttpResponse &response) { const char * contentType = arduCamCommand.getContentType(); if (stream->dataReady()) { - response.setHeader("Content Lenght", String(stream->available())); + response.setHeader("Content-Length", String(stream->available())); response.sendDataStream(stream, contentType); } Serial.printf("onCapture() process Stream %d ms\r\n", millis() - startTime); } +HttpPartResult snapshotProducer() +{ + HttpPartResult result; + + startCapture(); + ArduCAMStream *camStream = new ArduCAMStream(&myCAM); + result.stream = camStream; + + result.headers = new HttpHeaders(); + (*result.headers)["Content-Type"] = "image/jpeg"; + + return result; +} + void onStream(HttpRequest &request, HttpResponse &response) { Serial.printf("perform onCapture()\r\n"); @@ -203,24 +218,8 @@ void onStream(HttpRequest &request, HttpResponse &response) { myCAM.clear_fifo_flag(); myCAM.write_reg(ARDUCHIP_FRAMES, 0x00); - // get the picture - startTime = millis(); - startCapture(); - Serial.printf("onCapture() startCapture() %d ms\r\n", millis() - startTime); - - response.setContentType("Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n"); - response.sendString("HTTP/1.1 200 OK\r\n"); - - - while (1) { - startCapture(); - ArduCAMStream *stream = new ArduCAMStream(&myCAM); - - if (stream->dataReady()) { - response.sendString("--frame\r\n"); - response.sendDataStream(stream, "Content-Type: image/jpeg\r\n\r\n"); - } - } + HttpMultipartStream* stream = new HttpMultipartStream(snapshotProducer); + response.sendDataStream(stream, String("multipart/x-mixed-replace; boundary=") + stream->getBoundary()); } void onFavicon(HttpRequest &request, HttpResponse &response) { @@ -230,8 +229,8 @@ void onFavicon(HttpRequest &request, HttpResponse &response) { /* * start http and telnet server - * telnet can be used to configure cammera settings - * unsing ArdCammCommand handler + * telnet can be used to configure camera settings + * using ArdCammCommand handler */ void StartServers() { @@ -239,7 +238,7 @@ void StartServers() server.addPath("/", onIndex); server.addPath("/cam/set", onCamSetup); server.addPath("/cam/capture", onCapture); -// server.addPath("/stream", onStream); + server.addPath("/stream", onStream); server.addPath("/favicon.ico", onFavicon); server.setDefaultHandler(onFile); diff --git a/samples/Basic_WebClient/Makefile-user.mk b/samples/Basic_WebClient/Makefile-user.mk index 3901e89699..079d48ffed 100644 --- a/samples/Basic_WebClient/Makefile-user.mk +++ b/samples/Basic_WebClient/Makefile-user.mk @@ -33,7 +33,7 @@ MODULES = app # SPI_MODE = dio ## SPIFFS options -DISABLE_SPIFFS = 1 +# DISABLE_SPIFFS = 1 # SPIFF_FILES = files # We need rBoot in order to be able to run bigger Flash roms. diff --git a/samples/Basic_WebClient/app/application.cpp b/samples/Basic_WebClient/app/application.cpp index e501b59fc2..05ec2d5d43 100644 --- a/samples/Basic_WebClient/app/application.cpp +++ b/samples/Basic_WebClient/app/application.cpp @@ -19,7 +19,7 @@ #endif Timer procTimer; -HttpClient downloadClient; +HttpClient httpClient; /* Debug SSL functions */ void displaySessionId(SSL *ssl) @@ -114,8 +114,8 @@ void connectOk(IPAddress ip, IPAddress mask, IPAddress gateway) HttpHeaders requestHeaders; requestHeaders["User-Agent"] = "WebClient/Sming"; - downloadClient.send( - downloadClient.request("https://www.attachix.com/assets/css/local.css") + httpClient.send( + httpClient.request("https://www.attachix.com/assets/css/local.css") ->setHeaders(requestHeaders) ->setSslOptions(SSL_SERVER_VERIFY_LATER) /* @@ -132,21 +132,39 @@ void connectOk(IPAddress ip, IPAddress mask, IPAddress gateway) ); - downloadClient.send( - downloadClient.request("https://www.attachix.com/services/") + httpClient.send( + httpClient.request("https://www.attachix.com/services/") ->setMethod(HTTP_HEAD) ->setHeaders(requestHeaders) ->onRequestComplete(onDownload) ); +#ifndef DISABLE_SPIFFS + /* + * The code below demonstrates how to upload a file efficiently + * to a remote server in a secure way. + * + */ + FileStream* fileStream = new FileStream("data.txt"); + + HttpHeaders fileHeaders; + fileHeaders["Content-Type"] = "application/octet-stream"; + + httpClient.send( + httpClient.request("https://www.attachix.com/uploads/") + ->setMethod(HTTP_PUT) + ->setHeaders(fileHeaders) + ->setBody(fileStream) + ); +#endif - downloadClient.send( - downloadClient.request("https://www.attachix.com/business/") + httpClient.send( + httpClient.request("https://www.attachix.com/business/") ->setMethod(HTTP_HEAD) ->onRequestComplete(onDownload) ); - downloadClient.sendRequest(HTTP_HEAD, "https://www.attachix.com/intl/en/policies/privacy/", requestHeaders, onDownload); + httpClient.sendRequest(HTTP_HEAD, "https://www.attachix.com/intl/en/policies/privacy/", requestHeaders, onDownload); // The code above should make ONE tcp connection, ONE SSL handshake and then all requests should be pipelined to the // remote server taking care to speed the fetching of a page as fast as possible. @@ -174,6 +192,11 @@ void init() Serial.systemDebugOutput(true); // Allow debug print to serial Serial.println("Ready for SSL tests"); +#ifndef DISABLE_SPIFFS + debugf("trying to mount spiffs at 0x%08x, length %d", RBOOT_SPIFFS_0, SPIFF_SIZE); + spiffs_mount_manual(RBOOT_SPIFFS_0, SPIFF_SIZE); +#endif + // Setup the WIFI connection WifiStation.enable(true); WifiStation.config(WIFI_SSID, WIFI_PWD); // Put you SSID and Password here From 4fedd39ba1a960f996d6d59589110f787014beae Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 12 Oct 2017 10:02:46 +0200 Subject: [PATCH 18/33] Added support for wildcard content-types for the body parsers. (#1254) Added dummy body parser that stores all content into memory. --- .../SmingCore/Network/Http/HttpBodyParser.cpp | 21 ++++++++++++++++++ Sming/SmingCore/Network/Http/HttpBodyParser.h | 11 ++++++++++ Sming/SmingCore/Network/Http/HttpRequest.cpp | 8 ++++--- .../Network/Http/HttpServerConnection.cpp | 22 +++++++++++++++++-- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/Sming/SmingCore/Network/Http/HttpBodyParser.cpp b/Sming/SmingCore/Network/Http/HttpBodyParser.cpp index ee13b77541..93719c737e 100644 --- a/Sming/SmingCore/Network/Http/HttpBodyParser.cpp +++ b/Sming/SmingCore/Network/Http/HttpBodyParser.cpp @@ -95,3 +95,24 @@ void formUrlParser(HttpRequest& request, const char *at, int length) data = data.substring(pos + 1); } } + +void bodyToStringParser(HttpRequest& request, const char *at, int length) +{ + String* data = static_cast(request.args); + + if(length == -1) { + delete data; + data = new String(); + request.args = (void *)data; + return; + } + + if(length == -2) { + request.setBody(*data); + delete data; + request.args = NULL; + return; + } + + *data += String(at, length); +} diff --git a/Sming/SmingCore/Network/Http/HttpBodyParser.h b/Sming/SmingCore/Network/Http/HttpBodyParser.h index 98ebb881fd..1c72b8da43 100644 --- a/Sming/SmingCore/Network/Http/HttpBodyParser.h +++ b/Sming/SmingCore/Network/Http/HttpBodyParser.h @@ -38,6 +38,17 @@ extern "C" { */ void formUrlParser(HttpRequest& request, const char *at, int length); +/** + * @brief Stores the complete body into memory. + * The content later can be retrieved by calling request.getBody() + * @param HttpRequest& + * @param const *char + * @param int length Negative lengths are used to specify special cases + * -1 - start of incoming data + * -2 - end of incoming data + */ +void bodyToStringParser(HttpRequest& request, const char *at, int length); + #ifdef __cplusplus } #endif diff --git a/Sming/SmingCore/Network/Http/HttpRequest.cpp b/Sming/SmingCore/Network/Http/HttpRequest.cpp index 7dddbc8b93..c11de48432 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.cpp +++ b/Sming/SmingCore/Network/Http/HttpRequest.cpp @@ -50,9 +50,10 @@ HttpRequest& HttpRequest::operator = (const HttpRequest& rhs) { } HttpRequest::~HttpRequest() { - if(queryParams != NULL) { - delete queryParams; - } + delete queryParams; + delete stream; + queryParams = NULL; + stream = NULL; } HttpRequest* HttpRequest::setURL(URL uri) { @@ -156,6 +157,7 @@ String HttpRequest::getBody() char buf[1024]; for(int i=0; i< stream->length(); i += 1024) { int available = memory->readMemoryBlock(buf, 1024); + memory->seek(max(available, 0)); ret += String(buf, available); if(available < 1024) { break; diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp index f9309ffddc..4dc2c14185 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp @@ -199,8 +199,26 @@ int HttpServerConnection::staticOnHeadersComplete(http_parser* parser) contentType = contentType.substring(0, endPos); } - if(connection->bodyParsers->contains(contentType)) { - connection->bodyParser = (*connection->bodyParsers)[contentType]; + String majorType = contentType.substring(0, contentType.indexOf('/')); + majorType += "/*"; + + // Content-Type for exact type: application/json + // Wildcard type for application: application/* + // Wildcard type for the rest* + + Vector types; + types.add(contentType); + types.add(majorType); + types.add("*"); + + for(int i=0; i< types.count(); i++) { + if(connection->bodyParsers->contains(types.at(i))) { + connection->bodyParser = (*connection->bodyParsers)[types.at(i)]; + break; + } + } + + if(connection->bodyParser) { connection->bodyParser(connection->request, NULL, -1); } } From b4fc3d2cc2040022efdd5b2516371504febf747d Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Sat, 30 Sep 2017 09:54:24 +0200 Subject: [PATCH 19/33] Makefile: add make dependencies support This allows for automatic rebuilds when header files are changed. --- Sming/Makefile-project.mk | 14 ++++++++++++-- Sming/Makefile-rboot.mk | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Sming/Makefile-project.mk b/Sming/Makefile-project.mk index 63b870faf2..b75f059596 100644 --- a/Sming/Makefile-project.mk +++ b/Sming/Makefile-project.mk @@ -364,12 +364,20 @@ vpath %.c $(SRC_DIR) vpath %.cpp $(SRC_DIR) define compile-objects -$1/%.o: %.c +$1/%.o: %.c $1/%.c.d $(vecho) "CC $$<" $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ -$1/%.o: %.cpp +$1/%.o: %.cpp $1/%.cpp.d $(vecho) "C+ $$<" $(Q) $(CXX) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CXXFLAGS) -c $$< -o $$@ +$1/%.c.d: %.c + $(vecho) "DEP $$<" + $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -MM -MT $1/$$*.o $$< -o $$@ +$1/%.cpp.d: %.cpp + $(vecho) "DEP $$<" + $(Q) $(CXX) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CXXFLAGS) -MM -MT $1/$$*.o $$< -o $$@ + +.PRECIOUS: $1/%.c.d $1/%.cpp.d endef .PHONY: all checkdirs spiff_update spiff_clean clean @@ -515,3 +523,5 @@ clean: $(Q) rm -rf $(FW_BASE) $(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) +$(foreach bdir,$(BUILD_DIR),$(eval include $(wildcard $(bdir)/*.c.d))) +$(foreach bdir,$(BUILD_DIR),$(eval include $(wildcard $(bdir)/*.cpp.d))) diff --git a/Sming/Makefile-rboot.mk b/Sming/Makefile-rboot.mk index a75b30f0ce..df6b5d3552 100644 --- a/Sming/Makefile-rboot.mk +++ b/Sming/Makefile-rboot.mk @@ -429,12 +429,20 @@ vpath %.c $(SRC_DIR) vpath %.cpp $(SRC_DIR) define compile-objects -$1/%.o: %.c +$1/%.o: %.c $1/%.c.d $(vecho) "CC $$<" $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ -$1/%.o: %.cpp +$1/%.o: %.cpp $1/%.cpp.d $(vecho) "C+ $$<" $(Q) $(CXX) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CXXFLAGS) -c $$< -o $$@ +$1/%.c.d: %.c + $(vecho) "DEP $$<" + $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -MM -MT $1/$$*.o $$< -o $$@ +$1/%.cpp.d: %.cpp + $(vecho) "DEP $$<" + $(Q) $(CXX) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CXXFLAGS) -MM -MT $1/$$*.o $$< -o $$@ + +.PRECIOUS: $1/%.c.d $1/%.cpp.d endef .PHONY: all checkdirs spiff_update spiff_clean clean @@ -559,3 +567,5 @@ clean: $(Q) rm -rf $(FW_BASE) $(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) +$(foreach bdir,$(BUILD_DIR),$(eval include $(wildcard $(bdir)/*.c.d))) +$(foreach bdir,$(BUILD_DIR),$(eval include $(wildcard $(bdir)/*.cpp.d))) From fd55e14558a0b0c92124fd9d5320eedf8f507b18 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Thu, 12 Oct 2017 13:10:17 +0200 Subject: [PATCH 20/33] Makefile: Added dep support for the compilation of Sming library. --- Sming/Makefile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Sming/Makefile b/Sming/Makefile index b5fba81462..9119cfe618 100644 --- a/Sming/Makefile +++ b/Sming/Makefile @@ -342,12 +342,18 @@ $1/%.o: %.S $(vecho) "AS $$<" $(Q) $(AS) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ endif -$1/%.o: %.c +$1/%.o: %.c $1/%.c.d $(vecho) "CC $$<" $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ -$1/%.o: %.cpp +$1/%.o: %.cpp $1/%.cpp.d $(vecho) "C+ $$<" $(Q) $(CXX) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CXXFLAGS) -c $$< -o $$@ +$1/%.c.d: %.c + $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -MM -MT $1/$$*.o $$< -o $$@ +$1/%.cpp.d: %.cpp + $(Q) $(CXX) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CXXFLAGS) -MM -MT $1/$$*.o $$< -o $$@ + +.PRECIOUS: $1/%.c.d $1/%.cpp.d endef .PHONY: all checkdirs clean spiffy test samples-clean samples $(SAMPLES_DIRS) docs api wiki @@ -484,4 +490,6 @@ dist-clean: clean samples-clean third-party-clean $(Q) $(GIT) checkout $(USER_LIBDIR) $(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) +$(foreach bdir,$(BUILD_DIR),$(eval include $(wildcard $(bdir)/*.c.d))) +$(foreach bdir,$(BUILD_DIR),$(eval include $(wildcard $(bdir)/*.cpp.d))) From e4eaa3c6d70b9f029c4de6ed0315d5663b843d4e Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 13 Oct 2017 16:51:56 +0200 Subject: [PATCH 21/33] Backported that commit https://github.com/igrr/axtls-8266/commit/24af415e4a5ecdb32b76b5802f52b71367953b75 back here. (#1255) --- Sming/third-party/.patches/axtls-8266.patch | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/Sming/third-party/.patches/axtls-8266.patch b/Sming/third-party/.patches/axtls-8266.patch index 45a0e3c35b..128b5612af 100644 --- a/Sming/third-party/.patches/axtls-8266.patch +++ b/Sming/third-party/.patches/axtls-8266.patch @@ -503,3 +503,46 @@ index 4972119..f6f44f8 100644 { if (tp) { +diff --git a/crypto/rsa.c b/crypto/rsa.c +index ab74b4d..5651a69 100644 +--- a/crypto/rsa.c ++++ b/crypto/rsa.c +@@ -73,6 +73,7 @@ void RSA_priv_key_new(RSA_CTX **ctx, + bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET); + bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET); + #endif ++ bi_clear_cache(bi_ctx); + } + + void RSA_pub_key_new(RSA_CTX **ctx, +@@ -94,6 +95,7 @@ void RSA_pub_key_new(RSA_CTX **ctx, + bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET); + rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len); + bi_permanent(rsa_ctx->e); ++ bi_clear_cache(bi_ctx); + } + + /** +diff --git a/ssl/x509.c b/ssl/x509.c +index 35bd728..f76fa5e 100644 +--- a/ssl/x509.c ++++ b/ssl/x509.c +@@ -247,6 +247,9 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) + if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || + asn1_signature(cert, &offset, x509_ctx)) + goto end_cert; ++ ++ /* Saves a few bytes of memory */ ++ bi_clear_cache(bi_ctx); + #endif + ret = X509_OK; + end_cert: +@@ -485,6 +488,8 @@ int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) + ret = X509_VFY_ERROR_BAD_SIGNATURE; + } + ++ bi_clear_cache(ctx); ++ + if (ret) + goto end_verify; + From ea1bd326d2a59b638c90ac01e6f73ce1d7896a26 Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 13 Oct 2017 16:52:22 +0200 Subject: [PATCH 22/33] The demonstration with the file upload will crash if no file is found in the SPIFFS file system. (#1258) --- samples/Basic_WebClient/files/data.txt | 110 +++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 samples/Basic_WebClient/files/data.txt diff --git a/samples/Basic_WebClient/files/data.txt b/samples/Basic_WebClient/files/data.txt new file mode 100644 index 0000000000..aefaad859c --- /dev/null +++ b/samples/Basic_WebClient/files/data.txt @@ -0,0 +1,110 @@ +MIUSOV, as a man of breeding and delicacy, could not but feel some inward qualms, when he reached the Father Superior's with Ivan: he felt ashamed of having lost his temper. He felt that he ought to have disdained that despicable wretch, Fyodor Pavlovitch, too much to have been upset by him in Father Zossima's cell, and so to have forgotten himself. "The monks were not to blame, in any case," he reflected, on the steps. "And if they're decent people here (and the Father Superior, I understand, is a nobleman) why not be friendly and courteous with them? I won't argue, I'll fall in with everything, I'll win them by politeness, and... and... show them that I've nothing to do with that Aesop, that buffoon, that Pierrot, and have merely been taken in over this affair, just as they have." +He determined to drop his litigation with the monastery, and relinquish his claims to the wood-cutting and fishery rights at once. He was the more ready to do this because the rights had become much less valuable, and he had indeed the vaguest idea where the wood and river in question were. + +These excellent intentions were strengthened when he entered the Father Superior's dining-room, though, strictly speaking, it was not a dining-room, for the Father Superior had only two rooms altogether; they were, however, much larger and more comfortable than Father Zossima's. But there was no great luxury about the furnishing of these rooms either. The furniture was of mahogany, covered with leather, in the old-fashioned style of 1820 the floor was not even stained, but everything was shining with cleanliness, and there were many choice flowers in the windows; the most sumptuous thing in the room at the moment was, of course, the beautifully decorated table. The cloth was clean, the service shone; there were three kinds of well-baked bread, two bottles of wine, two of excellent mead, and a large glass jug of kvas- both the latter made in the monastery, and famous in the neighbourhood. There was no vodka. Rakitin related afterwards that there were five dishes: fish-soup made of sterlets, served with little fish patties; then boiled fish served in a special way; then salmon cutlets, ice pudding and compote, and finally, blanc-mange. Rakitin found out about all these good things, for he could not resist peeping into the kitchen, where he already had a footing. He had a footing everywhere, and got information about everything. He was of an uneasy and envious temper. He was well aware of his own considerable abilities, and nervously exaggerated them in his self-conceit. He knew he would play a prominent part of some sort, but Alyosha, who was attached to him, was distressed to see that his friend Rakitin was dishonourable, and quite unconscious of being so himself, considering, on the contrary, that because he would not steal money left on the table he was a man of the highest integrity. Neither Alyosha nor anyone else could have influenced him in that. + +Rakitin, of course, was a person of too little consequence to be invited to the dinner, to which Father Iosif, Father Paissy, and one other monk were the only inmates of the monastery invited. They were already waiting when Miusov, Kalganov, and Ivan arrived. The other guest, Maximov, stood a little aside, waiting also. The Father Superior stepped into the middle of the room to receive his guests. He was a tall, thin, but still vigorous old man, with black hair streaked with grey, and a long, grave, ascetic face. He bowed to his guests in silence. But this time they approached to receive his blessing. Miusov even tried to kiss his hand, but the Father Superior drew it back in time to avoid the salute. But Ivan and Kalganov went through the ceremony in the most simple-hearted and complete manner, kissing his hand as peasants do. + +"We must apologise most humbly, your reverence," began Miusov, simpering affably, and speaking in a dignified and respectful tone. "Pardon us for having come alone without the gentleman you invited, Fyodor Pavlovitch. He felt obliged to decline the honour of your hospitality, and not without reason. In the reverend Father Zossima's cell he was carried away by the unhappy dissension with his son, and let fall words which were quite out of keeping... in fact, quite unseemly... as"- he glanced at the monks- "your reverence is, no doubt, already aware. And therefore, recognising that he had been to blame, he felt sincere regret and shame, and begged me, and his son Ivan Fyodorovitch, to convey to you his apologies and regrets. In brief, he hopes and desires to make amends later. He asks your blessing, and begs you to forget what has taken place." + +As he uttered the last word of his tirade, Miusov completely recovered his self-complacency, and all traces of his former irritation disappeared. He fully and sincerely loved humanity again. + +The Father Superior listened to him with dignity, and, with a slight bend of the head, replied: + +"I sincerely deplore his absence. Perhaps at our table he might have learnt to like us, and we him. Pray be seated, gentlemen." + +He stood before the holy image, and began to say grace, aloud. All bent their heads reverently, and Maximov clasped his hands before him, with peculiar fervour. + +It was at this moment that Fyodor Pavlovitch played his last prank. It must be noted that he really had meant to go home, and really had felt the impossibility of going to dine with the Father Superior as though nothing had happened, after his disgraceful behaviour in the elder's cell. Not that he was so very much ashamed of himself- quite the contrary perhaps. But still he felt it would be unseemly to go to dinner. Yet his creaking carriage had hardly been brought to the steps of the hotel, and he had hardly got into it, when he suddenly stopped short. He remembered his own words at the elder's: "I always feel when I meet people that I am lower than all, and that they all take me for a buffoon; so I say let me play the buffoon, for you are, every one of you, stupider and lower than I." He longed to revenge himself on everyone for his own unseemliness. He suddenly recalled how he had once in the past been asked, "Why do you hate so and so, so much?" And he had answered them, with his shameless impudence, "I'll tell you. He has done me no harm. But I played him a dirty trick, and ever since I have hated him." + +Remembering that now, he smiled quietly and malignantly, hesitating for a moment. His eyes gleamed, and his lips positively quivered. + +"Well, since I have begun, I may as well go on," he decided. His predominant sensation at that moment might be expressed in the following words, "Well, there is no rehabilitating myself now. So let me shame them for all I am worth. I will show them I don't care what they think- that's all!" + +He told the coachman to wait, while with rapid steps he returned to the monastery and straight to the Father Superior's. He had no clear idea what he would do, but he knew that he could not control himself, and that a touch might drive him to the utmost limits of obscenity, but only to obscenity, to nothing criminal, nothing for which he could be legally punished. In the last resort, he could always restrain himself, and had marvelled indeed at himself, on that score, sometimes. He appeared in the Father Superior's dining-room, at the moment when the prayer was over, and all were moving to the table. Standing in the doorway, he scanned the company, and laughing his prolonged, impudent, malicious chuckle, looked them all boldly in the face. "They thought I had gone, and here I am again," he cried to the whole room. + +For one moment everyone stared at him without a word; and at once everyone felt that something revolting, grotesque, positively scandalous, was about to happen. Miusov passed immediately from the most benevolent frame of mind to the most savage. All the feelings that had subsided and died down in his heart revived instantly. + +"No! this I cannot endure!" he cried. "I absolutely cannot! and... I certainly cannot!" + +The blood rushed to his head. He positively stammered; but he was beyond thinking of style, and he seized his hat. + +"What is it he cannot?" cried Fyodor Pavlovitch, "that he absolutely cannot and certainly cannot? Your reverence, am I to come in or not? Will you receive me as your guest?" + +"You are welcome with all my heart," answered the Superior. "Gentlemen!" he added, "I venture to beg you most earnestly to lay aside your dissensions, and to be united in love and family harmony- with prayer to the Lord at our humble table." + +"No, no, it is impossible!" cried Miusov, beside himself. + +"Well, if it is impossible for Pyotr Alexandrovitch, it is impossible for me, and I won't stop. That is why I came. I will keep with Pyotr Alexandrovitch everywhere now. If you will go away, Pyotr Alexandrovitch, I will go away too, if you remain, I will remain. You stung him by what you said about family harmony, Father Superior, he does not admit he is my relation. That's right, isn't it, von Sohn? Here's von Sohn. How are you, von Sohn?" + +"Do you mean me?" muttered Maximov, puzzled. + +"Of course I mean you," cried Fyodor Pavlovitch. "Who else? The Father Superior could not be von Sohn." + +"But I am not von Sohn either. I am Maximov." + +"No, you are von Sohn. Your reverence, do you know who von Sohn was? It was a famous murder case. He was killed in a house of harlotry- I believe that is what such places are called among you- he was killed and robbed, and in spite of his venerable age, he was nailed up in a box and sent from Petersburg to Moscow in the luggage van, and while they were nailing him up, the harlots sang songs and played the harp, that is to say, the piano. So this is that very von Solin. He has risen from the dead, hasn't he, von Sohn?" + +"What is happening? What's this?" voices were heard in the group of monks. + +"Let us go," cried Miusov, addressing Kalganov. + +"No, excuse me," Fyodor Pavlovitch broke in shrilly, taking another step into the room. "Allow me to finish. There in the cell you blamed me for behaving disrespectfully just because I spoke of eating gudgeon, Pyotr Alexandrovitch. Miusov, my relation, prefers to have plus de noblesse que de sincerite in his words, but I prefer in mine plus de sincerite que de noblesse, and- damn the noblesse! That's right, isn't it, von Sohn? Allow me, Father Superior, though I am a buffoon and play the buffoon, yet I am the soul of honour, and I want to speak my mind. Yes, I am the soul of honour, while in Pyotr Alexandrovitch there is wounded vanity and nothing else. I came here perhaps to have a look and speak my mind. My son, Alexey, is here, being saved. I am his father; I care for his welfare, and it is my duty to care. While I've been playing the fool, I have been listening and having a look on the sly; and now I want to give you the last act of the performance. You know how things are with us? As a thing falls, so it lies. As a thing once has fallen, so it must lie for ever. Not a bit of it! I want to get up again. Holy Father, I am indignant with you. Confession is a great sacrament, before which I am ready to bow down reverently; but there in the cell, they all kneel down and confess aloud. Can it be right to confess aloud? It was ordained by the holy Fathers to confess in secret: then only your confession will be a mystery, and so it was of old. But how can I explain to him before everyone that I did this and that... well, you understand what- sometimes it would not be proper to talk about it- so it is really a scandal! No, Fathers, one might be carried along with you to the Flagellants, I dare say.... at the first opportunity I shall write to the Synod, and I shall take my son, Alexey, home." + +We must note here that Fyodor Pavlovitch knew where to look for the weak spot. There had been at one time malicious rumours which had even reached the Archbishop (not only regarding our monastery, but in others where the institution of elders existed) that too much respect was paid to the elders, even to the detriment of the authority of the Superior, that the elders abused the sacrament of confession and so on and so on- absurd charges which had died away of themselves everywhere. But the spirit of folly, which had caught up Fyodor Pavlovitch and was bearing him on the current of his own nerves into lower and lower depths of ignominy, prompted him with this old slander. Fyodor Pavlovitch did not understand a word of it, and he could not even put it sensibly, for on this occasion no one had been kneeling and confessing aloud in the elder's cell, so that he could not have seen anything of the kind. He was only speaking from confused memory of old slanders. But as soon as he had uttered his foolish tirade, he felt he had been talking absurd nonsense, and at once longed to prove to his audience, and above all to himself, that he had not been talking nonsense. And, though he knew perfectly well that with each word he would be adding more and more absurdity, he could not restrain himself, and plunged forward blindly. + +"How disgraceful!" cried Pyotr Alexandrovitch. + +"Pardon me!" said the Father Superior. "It was said of old, 'Many have begun to speak against me and have uttered evil sayings about me. And hearing it I have said to myself: it is the correction of the Lord and He has sent it to heal my vain soul.' And so we humbly thank you, honoured guest!" and he made Fyodor Pavlovitch a low bow. + +"Tut- tut- tut- sanctimoniousness and stock phrases! Old phrases and old gestures. The old lies and formal prostrations. We know all about them. A kiss on the lips and a dagger in the heart, as in Schiller's Robbers. I don't like falsehood, Fathers, I want the truth. But the truth is not to be found in eating gudgeon and that I proclaim aloud! Father monks, why do you fast? Why do you expect reward in heaven for that? Why, for reward like that I will come and fast too! No, saintly monk, you try being virtuous in the world, do good to society, without shutting yourself up in a monastery at other people's expense, and without expecting a reward up aloft for it- you'll find that a bit harder. I can talk sense, too, Father Superior. What have they got here?" He went up to the table. "Old port wine, mead brewed by the Eliseyev Brothers. Fie, fie, fathers! That is something beyond gudgeon. Look at the bottles the fathers have brought out, he he he! And who has provided it all? The Russian peasant, the labourer, brings here the farthing earned by his horny hand, wringing it from his family and the tax-gatherer! You bleed the people, you know, holy Fathers." + +"This is too disgraceful!" said Father Iosif. + +Father Paissy kept obstinately silent. Miusov rushed from the room, and Kalgonov after him. + +"Well, Father, I will follow Pyotr Alexandrovitch! I am not coming to see you again. You may beg me on your knees, I shan't come. I sent you a thousand roubles, so you have begun to keep your eye on me. He he he! No, I'll say no more. I am taking my revenge for my youth, for all the humiliation I endured." He thumped the table with his fist in a paroxysm of simulated feeling. "This monastery has played a great part in my life! It has cost me many bitter tears. You used to set my wife, the crazy one, against me. You cursed me with bell and book, you spread stories about me all over the place. Enough, fathers! This is the age of Liberalism, the age of steamers and railways. Neither a thousand, nor a hundred roubles, no, nor a hundred farthings will you get out of me!" + +It must be noted again that our monastery never had played any great part in his life, and he never had shed a bitter tear owing to it. But he was so carried away by his simulated emotion, that he was for one moment almost believing it himself. He was so touched he was almost weeping. But at that very instant, he felt that it was time to draw back. + +The Father Superior bowed his head at his malicious lie, and again spoke impressively: + +"It is written again, 'Bear circumspectly and gladly dishonour that cometh upon thee by no act of thine own, be not confounded and hate not him who hath dishonoured thee.' And so will we." + +"Tut, tut, tut! Bethinking thyself and the rest of the rigmarole. Bethink yourselves Fathers, I will go. But I will take my son, Alexey, away from here for ever, on my parental authority. Ivan Fyodorovitch, my most dutiful son, permit me to order you to follow me. Von Sohn, what have you to stay for? Come and see me now in the town. It is fun there. It is only one short verst; instead of lenten oil, I will give you sucking-pig and kasha. We will have dinner with some brandy and liqueur to it.... I've cloudberry wine. Hey, von Sohn, don't lose your chance." He went out, shouting and gesticulating. + +It was at that moment Rakitin saw him and pointed him out to Alyosha. + +"Alexey!" his father shouted, from far off, catching sight of him. "You come home to me to-day, for good, and bring your pillow and mattress, and leave no trace behind." + +Alyosha stood rooted to the spot, watching the scene in silence. Meanwhile, Fyodor Pavlovitch had got into the carriage, and Ivan was about to follow him in grim silence without even turning to say good-bye to Alyosha. But at this point another almost incredible scene of grotesque buffoonery gave the finishing touch to the episode. Maximov suddenly appeared by the side of the carriage. He ran up, panting, afraid of being too late. Rakitin and Alyosha saw him running. He was in such a hurry that in his impatience he put his foot on the step on which Ivan's left foot was still resting, and clutching the carriage he kept trying to jump in. "I am going with you! " he kept shouting, laughing a thin mirthful laugh with a look of reckless glee in his face. "Take me, too." + +"There!" cried Fyodor Pavlovitch, delighted. "Did I not say he was von Sohn. It is von Sohn himself, risen from the dead. Why, how did you tear yourself away? What did you von Sohn there? And how could you get away from the dinner? You must be a brazen-faced fellow! I am that myself, but I am surprised at you, brother! Jump in, jump in! Let him pass, Ivan. It will be fun. He can lie somewhere at our feet. Will you lie at our feet, von Sohn? Or perch on the box with the coachman. Skip on to the box, von Sohn!" + +But Ivan, who had by now taken his seat, without a word gave Maximov a violent punch in the breast and sent him flying. It was quite by chance he did not fall. + +"Drive on!" Ivan shouted angrily to the coachman. + +"Why, what are you doing, what are you about? Why did you do that?" Fyodor Pavlovitch protested. + +But the carriage had already driven away. Ivan made no reply. + +"Well, you are a fellow," Fyodor Pavlovitch said again. + +After a pause of two minutes, looking askance at his son, "Why, it was you got up all this monastery business. You urged it, you approved of it. Why are you angry now?" + +"You've talked rot enough. You might rest a bit now," Ivan snapped sullenly. + +Fyodor Pavlovitch was silent again for two minutes. + +"A drop of brandy would be nice now," he observed sententiously, but Ivan made no response. + +"You shall have some, too, when we get home." + +Ivan was still silent. + +Fyodor Pavlovitch waited another two minutes. + +"But I shall take Alyosha away from the monastery, though you will dislike it so much, most honoured Karl von Moor." + +Ivan shrugged his shoulders contemptuously, and turning away stared at the road. And they did not speak again all the way home. From c224962ff390aa2d2fbae8814943b8c09eaa43f6 Mon Sep 17 00:00:00 2001 From: slaff Date: Sat, 14 Oct 2017 10:35:03 +0200 Subject: [PATCH 23/33] Arduino compatibility improvements. (#1213) * Updated the Adafruit SSD1306 library. Added better Arduino compatibility. * Re-added SH1106 support. * Fix for wrong GPIO reg type (issue #397) * Started fetching some Arduino libraries via git submodules. Updated Adafruit_ST7735 library to its latest version. Updated Adafruit_SSD1306 library to its latest version. * Re-applied support for SH1106_128_64 - 1.3" OLED display version. --- .gitmodules | 8 + .../Libraries/.patches/Adafruit_SSD1306.patch | 96 +++ Sming/Libraries/.patches/Readme.md | 1 + .../Adafruit_PCD8544/Adafruit_PCD8544.h | 4 +- Sming/Libraries/Adafruit_SSD1306 | 1 + .../Adafruit_SSD1306/Adafruit_SSD1306.cpp | 796 ------------------ .../Adafruit_SSD1306/Adafruit_SSD1306.h | 180 ---- Sming/Libraries/Adafruit_SSD1306/README.txt | 24 - .../ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino | 357 -------- .../ssd1306_128x32_spi/ssd1306_128x32_spi.ino | 368 -------- .../ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino | 356 -------- .../ssd1306_128x64_spi/ssd1306_128x64_spi.ino | 368 -------- Sming/Libraries/Adafruit_SSD1306/license.txt | 26 - Sming/Libraries/Adafruit_ST7735 | 1 + .../Adafruit_ST7735/Adafruit_ST7735.cpp | 742 ---------------- .../Adafruit_ST7735/Adafruit_ST7735.h | 187 ---- Sming/Libraries/Adafruit_ST7735/README.txt | 26 - .../examples/graphicstest/graphicstest.ino | 300 ------- .../examples/rotationtest/rotationtest.ino | 285 ------- .../examples/shieldtest/shieldtest.ino | 256 ------ .../soft_spitftbitmap/soft_spitftbitmap.ino | 219 ----- .../examples/spitftbitmap/spitftbitmap.ino | 215 ----- .../Adafruit_ST7735/library.properties | 9 - .../CapacitiveSensor/CapacitiveSensor.h | 2 +- Sming/Libraries/TFT_ILI9163C/TFT_ILI9163C.h | 4 +- Sming/Makefile | 24 +- Sming/Makefile-project.mk | 5 +- Sming/Makefile-rboot.mk | 5 +- Sming/SmingCore/ArduinoCompat.cpp | 21 + Sming/SmingCore/ArduinoCompat.h | 29 + Sming/SmingCore/pgmspace.h | 2 + Sming/SmingCore/pins_arduino.h | 23 +- Sming/Wiring/Arduino.h | 1 + 33 files changed, 202 insertions(+), 4739 deletions(-) create mode 100644 Sming/Libraries/.patches/Adafruit_SSD1306.patch create mode 100644 Sming/Libraries/.patches/Readme.md create mode 160000 Sming/Libraries/Adafruit_SSD1306 delete mode 100644 Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.cpp delete mode 100644 Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.h delete mode 100644 Sming/Libraries/Adafruit_SSD1306/README.txt delete mode 100644 Sming/Libraries/Adafruit_SSD1306/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino delete mode 100644 Sming/Libraries/Adafruit_SSD1306/examples/ssd1306_128x32_spi/ssd1306_128x32_spi.ino delete mode 100644 Sming/Libraries/Adafruit_SSD1306/examples/ssd1306_128x64_i2c/ssd1306_128x64_i2c.ino delete mode 100644 Sming/Libraries/Adafruit_SSD1306/examples/ssd1306_128x64_spi/ssd1306_128x64_spi.ino delete mode 100644 Sming/Libraries/Adafruit_SSD1306/license.txt create mode 160000 Sming/Libraries/Adafruit_ST7735 delete mode 100644 Sming/Libraries/Adafruit_ST7735/Adafruit_ST7735.cpp delete mode 100644 Sming/Libraries/Adafruit_ST7735/Adafruit_ST7735.h delete mode 100644 Sming/Libraries/Adafruit_ST7735/README.txt delete mode 100644 Sming/Libraries/Adafruit_ST7735/examples/graphicstest/graphicstest.ino delete mode 100644 Sming/Libraries/Adafruit_ST7735/examples/rotationtest/rotationtest.ino delete mode 100644 Sming/Libraries/Adafruit_ST7735/examples/shieldtest/shieldtest.ino delete mode 100644 Sming/Libraries/Adafruit_ST7735/examples/soft_spitftbitmap/soft_spitftbitmap.ino delete mode 100644 Sming/Libraries/Adafruit_ST7735/examples/spitftbitmap/spitftbitmap.ino delete mode 100644 Sming/Libraries/Adafruit_ST7735/library.properties create mode 100644 Sming/SmingCore/ArduinoCompat.cpp create mode 100644 Sming/SmingCore/ArduinoCompat.h create mode 100644 Sming/SmingCore/pgmspace.h diff --git a/.gitmodules b/.gitmodules index f5a9300542..054baa12d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,11 @@ path = Sming/third-party/ws_parser url = https://github.com/charliesome/ws_parser.git ignore = dirty +[submodule "Sming/Libraries/Adafruit_ST7735"] + path = Sming/Libraries/Adafruit_ST7735 + url = https://github.com/adafruit/Adafruit-ST7735-Library.git + ignore = dirty +[submodule "Sming/Libraries/Adafruit_SSD1306"] + path = Sming/Libraries/Adafruit_SSD1306 + url = https://github.com/adafruit/Adafruit_SSD1306.git + ignore = dirty diff --git a/Sming/Libraries/.patches/Adafruit_SSD1306.patch b/Sming/Libraries/.patches/Adafruit_SSD1306.patch new file mode 100644 index 0000000000..c0baf653c3 --- /dev/null +++ b/Sming/Libraries/.patches/Adafruit_SSD1306.patch @@ -0,0 +1,96 @@ +diff --git a/Adafruit_SSD1306.cpp b/Adafruit_SSD1306.cpp +index 570a335..40f4784 100644 +--- a/Adafruit_SSD1306.cpp ++++ b/Adafruit_SSD1306.cpp +@@ -252,7 +252,7 @@ void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { + ssd1306_command(SSD1306_SETCONTRAST); // 0x81 + ssd1306_command(0x8F); + +-#elif defined SSD1306_128_64 ++#elif defined SSD1306_128_64 || defined SH1106_128_64 + ssd1306_command(SSD1306_SETCOMPINS); // 0xDA + ssd1306_command(0x12); + ssd1306_command(SSD1306_SETCONTRAST); // 0x81 +@@ -417,6 +417,28 @@ void Adafruit_SSD1306::dim(boolean dim) { + } + + void Adafruit_SSD1306::display(void) { ++#if defined SH1106_128_64 ++ for (int index = 0; index < 8; index++) { ++ ssd1306_command(SH1106_SETSTARTPAGE + index); ++ /* for some reason display is shifted by 2 columns ++ * on 1.3" displays from ebay ++ */ ++ ssd1306_command(SSD1306_SETLOWCOLUMN + 2); // low column start address ++ ssd1306_command(SSD1306_SETHIGHCOLUMN); // high column start address ++ ++ for (int pixel = 0; pixel < SSD1306_LCDWIDTH; pixel++) { ++ Wire.beginTransmission(_i2caddr); ++ WIRE_WRITE(0x40); ++ // input buffer doesn't accept all bytes at once ++ for (uint8_t x=0; x<16; x++) { ++ WIRE_WRITE(buffer[index * SSD1306_LCDWIDTH + pixel]); ++ ++pixel; ++ } ++ --pixel; ++ Wire.endTransmission(); ++ } ++ } ++#else + ssd1306_command(SSD1306_COLUMNADDR); + ssd1306_command(0); // Column start address (0 = reset) + ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) +@@ -482,6 +504,7 @@ void Adafruit_SSD1306::display(void) { + TWBR = twbrbackup; + #endif + } ++#endif /* defined SH1106_128_64 */ + } + + // clear everything +diff --git a/Adafruit_SSD1306.h b/Adafruit_SSD1306.h +index 1162f87..4226f3e 100644 +--- a/Adafruit_SSD1306.h ++++ b/Adafruit_SSD1306.h +@@ -69,20 +69,28 @@ All text above, and the splash screen must be included in any redistribution + + SSD1306_96_16 + ++ SH1106_128_64 - 1.3" OLED display version ++ + -----------------------------------------------------------------------*/ +-// #define SSD1306_128_64 +- #define SSD1306_128_32 ++// #define SH1106_128_64 ++ #define SSD1306_128_64 ++// #define SSD1306_128_32 + // #define SSD1306_96_16 + /*=========================================================================*/ + ++#if defined SSD1306_128_64 && defined SH1106_128_64 ++ #error "Select either SH1106 or SSD1306 display type in SSD1306.h" ++#endif ++ ++ + #if defined SSD1306_128_64 && defined SSD1306_128_32 + #error "Only one SSD1306 display can be specified at once in SSD1306.h" + #endif +-#if !defined SSD1306_128_64 && !defined SSD1306_128_32 && !defined SSD1306_96_16 ++#if !defined SSD1306_128_64 && !defined SSD1306_128_32 && !defined SSD1306_96_16 && !defined SH1106_128_64 + #error "At least one SSD1306 display must be specified in SSD1306.h" + #endif + +-#if defined SSD1306_128_64 ++#if defined SSD1306_128_64 || defined SH1106_128_64 + #define SSD1306_LCDWIDTH 128 + #define SSD1306_LCDHEIGHT 64 + #endif +@@ -132,6 +140,8 @@ All text above, and the splash screen must be included in any redistribution + #define SSD1306_EXTERNALVCC 0x1 + #define SSD1306_SWITCHCAPVCC 0x2 + ++#define SH1106_SETSTARTPAGE 0xB0 ++ + // Scrolling #defines + #define SSD1306_ACTIVATE_SCROLL 0x2F + #define SSD1306_DEACTIVATE_SCROLL 0x2E diff --git a/Sming/Libraries/.patches/Readme.md b/Sming/Libraries/.patches/Readme.md new file mode 100644 index 0000000000..555d2f6422 --- /dev/null +++ b/Sming/Libraries/.patches/Readme.md @@ -0,0 +1 @@ +This directory contains patches to upstream Arudino libraries. diff --git a/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.h b/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.h index 1199b0fa87..d573fde4e1 100644 --- a/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.h +++ b/Sming/Libraries/Adafruit_PCD8544/Adafruit_PCD8544.h @@ -32,8 +32,8 @@ All text above, and the splash screen must be included in any redistribution typedef volatile RwReg PortReg; typedef uint32_t PortMask; #else - typedef volatile uint8_t PortReg; - typedef uint8_t PortMask; + typedef volatile GPIO_REG_TYPE PortReg; + typedef GPIO_REG_TYPE PortMask; #endif #define BLACK 1 diff --git a/Sming/Libraries/Adafruit_SSD1306 b/Sming/Libraries/Adafruit_SSD1306 new file mode 160000 index 0000000000..ddfec78fa1 --- /dev/null +++ b/Sming/Libraries/Adafruit_SSD1306 @@ -0,0 +1 @@ +Subproject commit ddfec78fa15f0ff8dfc8a76524077ba6bb5fc6f3 diff --git a/Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.cpp b/Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.cpp deleted file mode 100644 index 6d0d109b83..0000000000 --- a/Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.cpp +++ /dev/null @@ -1,796 +0,0 @@ -/********************************************************************* -This is a library for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen below must be included in any redistribution -*********************************************************************/ - -//#include -//#ifndef __SAM3X8E__ -// #include -//#endif -#include "Adafruit_SSD1306.h" - -#include - -#include "../../SmingCore/Wire.h" -#include "../Adafruit_GFX/Adafruit_GFX.h" - -// the memory buffer for the LCD - -static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, -0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, -#if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH > 96*16) -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, -0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, -0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8, -0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, -0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01, -0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF, -0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00, -0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF, -0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, -0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F, -0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, -0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03, -0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, -0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00, -0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03, -0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -#if (SSD1306_LCDHEIGHT == 64) -0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F, -0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F, -0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, -0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, -0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E, -0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC, -0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06, -0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8, -0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, -0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C, -0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, -0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, -0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07, -0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -#endif -#endif -}; - - - -// the most basic function, set a single pixel -void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) { - if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) - return; - - // check rotation, move pixel around if necessary - switch (getRotation()) { - case 1: - swap(x, y); - x = WIDTH - x - 1; - break; - case 2: - x = WIDTH - x - 1; - y = HEIGHT - y - 1; - break; - case 3: - swap(x, y); - y = HEIGHT - y - 1; - break; - } - - // x is which column - switch (color) - { - case WHITE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << (y&7)); break; - case BLACK: buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break; - case INVERSE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break; - } - -} - -Adafruit_SSD1306::Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { - cs = CS; - rst = RST; - dc = DC; - sclk = SCLK; - sid = SID; - hwSPI = false; -} - -// constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset -Adafruit_SSD1306::Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { - dc = DC; - rst = RST; - cs = CS; - hwSPI = true; -} - -// initializer for I2C - we only indicate the reset pin! -Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) : -Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { - sclk = dc = cs = sid = -1; - rst = reset; -} - - -void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { - _vccstate = vccstate; - _i2caddr = i2caddr; - - // set pin directions - if (sid != -1){ - pinMode(dc, OUTPUT); - pinMode(cs, OUTPUT); - csport = portOutputRegister(digitalPinToPort(cs)); - cspinmask = digitalPinToBitMask(cs); - dcport = portOutputRegister(digitalPinToPort(dc)); - dcpinmask = digitalPinToBitMask(dc); - if (!hwSPI){ - // set pins for software-SPI - pinMode(sid, OUTPUT); - pinMode(sclk, OUTPUT); - clkport = portOutputRegister(digitalPinToPort(sclk)); - clkpinmask = digitalPinToBitMask(sclk); - mosiport = portOutputRegister(digitalPinToPort(sid)); - mosipinmask = digitalPinToBitMask(sid); - } - if (hwSPI){ - SPI.begin (); -#if defined(__SAM3X8E__) - SPI.setClockDivider (9); // 9.3 MHz -#elif defined(__ESP8266_EX__) - ;// SPI clock divider not implemented yet! -#else - SPI.setClockDivider (SPI_CLOCK_DIV2); // 8 MHz -#endif - } - } - else - { - // I2C Init - Wire.begin(); -#ifdef __SAM3X8E__ - // Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL) - TWI1->TWI_CWGR = 0; - TWI1->TWI_CWGR = ((VARIANT_MCK / (2 * 400000)) - 4) * 0x101; -#endif - } - - if (reset) { - // Setup reset pin direction (used by both SPI and I2C) - pinMode(rst, OUTPUT); - digitalWrite(rst, HIGH); - // VDD (3.3V) goes high at start, lets just chill for a ms - delay(1); - // bring reset low - digitalWrite(rst, LOW); - // wait 10ms - delay(10); - // bring out of reset - digitalWrite(rst, HIGH); - // turn on VCC (9V?) - } - - #if defined SSD1306_128_32 - // Init sequence for 128x32 OLED module - ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE - ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 - ssd1306_command(0x80); // the suggested ratio 0x80 - ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 - ssd1306_command(0x1F); - ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 - ssd1306_command(0x0); // no offset - ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 - ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x10); } - else - { ssd1306_command(0x14); } - ssd1306_command(SSD1306_MEMORYMODE); // 0x20 - ssd1306_command(0x00); // 0x0 act like ks0108 - ssd1306_command(SSD1306_SEGREMAP | 0x1); - ssd1306_command(SSD1306_COMSCANDEC); - ssd1306_command(SSD1306_SETCOMPINS); // 0xDA - ssd1306_command(0x02); - ssd1306_command(SSD1306_SETCONTRAST); // 0x81 - ssd1306_command(0x8F); - ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x22); } - else - { ssd1306_command(0xF1); } - ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB - ssd1306_command(0x40); - ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 - ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 - #endif - - #if defined SSD1306_128_64 || defined SH1106_128_64 - // Init sequence for 128x64 OLED module - ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE - ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 - ssd1306_command(0x80); // the suggested ratio 0x80 - ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 - ssd1306_command(0x3F); - ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 - ssd1306_command(0x0); // no offset - ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 - ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x10); } - else - { ssd1306_command(0x14); } - ssd1306_command(SSD1306_MEMORYMODE); // 0x20 - ssd1306_command(0x00); // 0x0 act like ks0108 - ssd1306_command(SSD1306_SEGREMAP | 0x1); - ssd1306_command(SSD1306_COMSCANDEC); - ssd1306_command(SSD1306_SETCOMPINS); // 0xDA - ssd1306_command(0x12); - ssd1306_command(SSD1306_SETCONTRAST); // 0x81 - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x9F); } - else - { ssd1306_command(0xCF); } - ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x22); } - else - { ssd1306_command(0xF1); } - ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB - ssd1306_command(0x40); - ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 - ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 - #endif - - #if defined SSD1306_96_16 - // Init sequence for 96x16 OLED module - ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE - ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 - ssd1306_command(0x80); // the suggested ratio 0x80 - ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 - ssd1306_command(0x0F); - ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 - ssd1306_command(0x00); // no offset - ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 - ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x10); } - else - { ssd1306_command(0x14); } - ssd1306_command(SSD1306_MEMORYMODE); // 0x20 - ssd1306_command(0x00); // 0x0 act like ks0108 - ssd1306_command(SSD1306_SEGREMAP | 0x1); - ssd1306_command(SSD1306_COMSCANDEC); - ssd1306_command(SSD1306_SETCOMPINS); // 0xDA - ssd1306_command(0x2); //ada x12 - ssd1306_command(SSD1306_SETCONTRAST); // 0x81 - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x10); } - else - { ssd1306_command(0xAF); } - ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 - if (vccstate == SSD1306_EXTERNALVCC) - { ssd1306_command(0x22); } - else - { ssd1306_command(0xF1); } - ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB - ssd1306_command(0x40); - ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 - ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 - #endif - - ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel -} - - -void Adafruit_SSD1306::invertDisplay(uint8_t i) { - if (i) { - ssd1306_command(SSD1306_INVERTDISPLAY); - } else { - ssd1306_command(SSD1306_NORMALDISPLAY); - } -} - -void Adafruit_SSD1306::ssd1306_command(uint8_t c) { - if (sid != -1) - { - // SPI - //digitalWrite(cs, HIGH); - *csport |= cspinmask; - //digitalWrite(dc, LOW); - *dcport &= ~dcpinmask; - //digitalWrite(cs, LOW); - *csport &= ~cspinmask; - fastSPIwrite(c); - //digitalWrite(cs, HIGH); - *csport |= cspinmask; - } - else - { - // I2C - uint8_t control = 0x00; // Co = 0, D/C = 0 - Wire.beginTransmission(_i2caddr); - WIRE_WRITE(control); - WIRE_WRITE(c); - Wire.endTransmission(); - } -} - -// startscrollright -// Activate a right handed scroll for rows start through stop -// Hint, the display is 16 rows tall. To scroll the whole display, run: -// display.scrollright(0x00, 0x0F) -void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop){ - ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL); - ssd1306_command(0X00); - ssd1306_command(start); - ssd1306_command(0X00); - ssd1306_command(stop); - ssd1306_command(0X00); - ssd1306_command(0XFF); - ssd1306_command(SSD1306_ACTIVATE_SCROLL); -} - -// startscrollleft -// Activate a right handed scroll for rows start through stop -// Hint, the display is 16 rows tall. To scroll the whole display, run: -// display.scrollright(0x00, 0x0F) -void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop){ - ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL); - ssd1306_command(0X00); - ssd1306_command(start); - ssd1306_command(0X00); - ssd1306_command(stop); - ssd1306_command(0X00); - ssd1306_command(0XFF); - ssd1306_command(SSD1306_ACTIVATE_SCROLL); -} - -// startscrolldiagright -// Activate a diagonal scroll for rows start through stop -// Hint, the display is 16 rows tall. To scroll the whole display, run: -// display.scrollright(0x00, 0x0F) -void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){ - ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); - ssd1306_command(0X00); - ssd1306_command(SSD1306_LCDHEIGHT); - ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL); - ssd1306_command(0X00); - ssd1306_command(start); - ssd1306_command(0X00); - ssd1306_command(stop); - ssd1306_command(0X01); - ssd1306_command(SSD1306_ACTIVATE_SCROLL); -} - -// startscrolldiagleft -// Activate a diagonal scroll for rows start through stop -// Hint, the display is 16 rows tall. To scroll the whole display, run: -// display.scrollright(0x00, 0x0F) -void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){ - ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); - ssd1306_command(0X00); - ssd1306_command(SSD1306_LCDHEIGHT); - ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL); - ssd1306_command(0X00); - ssd1306_command(start); - ssd1306_command(0X00); - ssd1306_command(stop); - ssd1306_command(0X01); - ssd1306_command(SSD1306_ACTIVATE_SCROLL); -} - -void Adafruit_SSD1306::stopscroll(void){ - ssd1306_command(SSD1306_DEACTIVATE_SCROLL); -} - -// Dim the display -// dim = true: display is dimmed -// dim = false: display is normal -void Adafruit_SSD1306::dim(boolean dim) { - uint8_t contrast; - - if (dim) { - contrast = 0; // Dimmed display - } else { - if (_vccstate == SSD1306_EXTERNALVCC) { - contrast = 0x9F; - } else { - contrast = 0xCF; - } - } - // the range of contrast to too small to be really useful - // it is useful to dim the display - ssd1306_command(SSD1306_SETCONTRAST); - ssd1306_command(contrast); -} - -void Adafruit_SSD1306::ssd1306_data(uint8_t c) { - if (sid != -1) - { - // SPI - //digitalWrite(cs, HIGH); - *csport |= cspinmask; - //digitalWrite(dc, HIGH); - *dcport |= dcpinmask; - //digitalWrite(cs, LOW); - *csport &= ~cspinmask; - fastSPIwrite(c); - //digitalWrite(cs, HIGH); - *csport |= cspinmask; - } - else - { - // I2C - uint8_t control = 0x40; // Co = 0, D/C = 1 - Wire.beginTransmission(_i2caddr); - WIRE_WRITE(control); - WIRE_WRITE(c); - Wire.endTransmission(); - } -} - -void Adafruit_SSD1306::display(void) { -#if defined SH1106_128_64 - for (int index = 0; index < 8; index++) { - ssd1306_command(SH1106_SETSTARTPAGE + index); - /* for some reason display is shifted by 2 columns - * on 1.3" displays from ebay - */ - ssd1306_command(SSD1306_SETLOWCOLUMN + 2); // low column start address - ssd1306_command(SSD1306_SETHIGHCOLUMN); // high column start address - - for (int pixel = 0; pixel < SSD1306_LCDWIDTH; pixel++) { - Wire.beginTransmission(_i2caddr); - WIRE_WRITE(0x40); - // input buffer doesn't accept all bytes at once - for (uint8_t x=0; x<16; x++) { - WIRE_WRITE(buffer[index * SSD1306_LCDWIDTH + pixel]); - ++pixel; - } - --pixel; - Wire.endTransmission(); - } - } -#else - ssd1306_command(SSD1306_COLUMNADDR); - ssd1306_command(0); // Column start address (0 = reset) - ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) - - ssd1306_command(SSD1306_PAGEADDR); - ssd1306_command(0); // Page start address (0 = reset) - #if SSD1306_LCDHEIGHT == 64 - ssd1306_command(7); // Page end address - #endif - #if SSD1306_LCDHEIGHT == 32 - ssd1306_command(3); // Page end address - #endif - #if SSD1306_LCDHEIGHT == 16 - ssd1306_command(1); // Page end address - #endif - - if (sid != -1) - { - // SPI - *csport |= cspinmask; - *dcport |= dcpinmask; - *csport &= ~cspinmask; - - for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { - fastSPIwrite(buffer[i]); - //ssd1306_data(buffer[i]); - } - *csport |= cspinmask; - } - else - { - // save I2C bitrate -#if !defined(__SAM3X8E__) && !defined(__ESP8266_EX__) - uint8_t twbrbackup = TWBR; - TWBR = 12; // upgrade to 400KHz! -#endif - - //Serial.println(TWBR, DEC); - //Serial.println(TWSR & 0x3, DEC); - - // I2C - for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { - // send a bunch of data in one xmission - Wire.beginTransmission(_i2caddr); - WIRE_WRITE(0x40); - for (uint8_t x=0; x<16; x++) { - WIRE_WRITE(buffer[i]); - i++; - } - i--; - Wire.endTransmission(); - } -#if !defined(__SAM3X8E__) && !defined(__ESP8266_EX__) - TWBR = twbrbackup; -#endif - } -#endif -} - -// clear everything -void Adafruit_SSD1306::clearDisplay(void) { - memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8)); -} - - -inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) { - - if(hwSPI) { - (void)SPI.transfer(d); - } else { - for(uint8_t bit = 0x80; bit; bit >>= 1) { - *clkport &= ~clkpinmask; - if(d & bit) *mosiport |= mosipinmask; - else *mosiport &= ~mosipinmask; - *clkport |= clkpinmask; - } - } - //*csport |= cspinmask; -} - -void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { - boolean bSwap = false; - switch(rotation) { - case 0: - // 0 degree rotation, do nothing - break; - case 1: - // 90 degree rotation, swap x & y for rotation, then invert x - bSwap = true; - swap(x, y); - x = WIDTH - x - 1; - break; - case 2: - // 180 degree rotation, invert x and y - then shift y around for height. - x = WIDTH - x - 1; - y = HEIGHT - y - 1; - x -= (w-1); - break; - case 3: - // 270 degree rotation, swap x & y for rotation, then invert y and adjust y for w (not to become h) - bSwap = true; - swap(x, y); - y = HEIGHT - y - 1; - y -= (w-1); - break; - } - - if(bSwap) { - drawFastVLineInternal(x, y, w, color); - } else { - drawFastHLineInternal(x, y, w, color); - } -} - -void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) { - // Do bounds/limit checks - if(y < 0 || y >= HEIGHT) { return; } - - // make sure we don't try to draw below 0 - if(x < 0) { - w += x; - x = 0; - } - - // make sure we don't go off the edge of the display - if( (x + w) > WIDTH) { - w = (WIDTH - x); - } - - // if our width is now negative, punt - if(w <= 0) { return; } - - // set up the pointer for movement through the buffer - register uint8_t *pBuf = buffer; - // adjust the buffer pointer for the current row - pBuf += ((y/8) * SSD1306_LCDWIDTH); - // and offset x columns in - pBuf += x; - - register uint8_t mask = 1 << (y&7); - - switch (color) - { - case WHITE: while(w--) { *pBuf++ |= mask; }; break; - case BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break; - case INVERSE: while(w--) { *pBuf++ ^= mask; }; break; - } -} - -void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { - bool bSwap = false; - switch(rotation) { - case 0: - break; - case 1: - // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w) - bSwap = true; - swap(x, y); - x = WIDTH - x - 1; - x -= (h-1); - break; - case 2: - // 180 degree rotation, invert x and y - then shift y around for height. - x = WIDTH - x - 1; - y = HEIGHT - y - 1; - y -= (h-1); - break; - case 3: - // 270 degree rotation, swap x & y for rotation, then invert y - bSwap = true; - swap(x, y); - y = HEIGHT - y - 1; - break; - } - - if(bSwap) { - drawFastHLineInternal(x, y, h, color); - } else { - drawFastVLineInternal(x, y, h, color); - } -} - - -void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) { - - // do nothing if we're off the left or right side of the screen - if(x < 0 || x >= WIDTH) { return; } - - // make sure we don't try to draw below 0 - if(__y < 0) { - // __y is negative, this will subtract enough from __h to account for __y being 0 - __h += __y; - __y = 0; - - } - - // make sure we don't go past the height of the display - if( (__y + __h) > HEIGHT) { - __h = (HEIGHT - __y); - } - - // if our height is now negative, punt - if(__h <= 0) { - return; - } - - // this display doesn't need ints for coordinates, use local byte registers for faster juggling - register uint8_t y = __y; - register uint8_t h = __h; - - - // set up the pointer for fast movement through the buffer - register uint8_t *pBuf = buffer; - // adjust the buffer pointer for the current row - pBuf += ((y/8) * SSD1306_LCDWIDTH); - // and offset x columns in - pBuf += x; - - // do the first partial byte, if necessary - this requires some masking - register uint8_t mod = (y&7); - if(mod) { - // mask off the high n bits we want to set - mod = 8-mod; - - // note - lookup table results in a nearly 10% performance improvement in fill* functions - // register uint8_t mask = ~(0xFF >> (mod)); - static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; - register uint8_t mask = premask[mod]; - - // adjust the mask if we're not going to reach the end of this byte - if( h < mod) { - mask &= (0XFF >> (mod-h)); - } - - switch (color) - { - case WHITE: *pBuf |= mask; break; - case BLACK: *pBuf &= ~mask; break; - case INVERSE: *pBuf ^= mask; break; - } - - // fast exit if we're done here! - if(h= 8) { - if (color == INVERSE) { // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop - do { - *pBuf=~(*pBuf); - - // adjust the buffer forward 8 rows worth of data - pBuf += SSD1306_LCDWIDTH; - - // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now) - h -= 8; - } while(h >= 8); - } - else { - // store a local value to work with - register uint8_t val = (color == WHITE) ? 255 : 0; - - do { - // write our value in - *pBuf = val; - - // adjust the buffer forward 8 rows worth of data - pBuf += SSD1306_LCDWIDTH; - - // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now) - h -= 8; - } while(h >= 8); - } - } - - // now do the final partial byte, if necessary - if(h) { - mod = h & 7; - // this time we want to mask the low bits of the byte, vs the high bits we did above - // register uint8_t mask = (1 << mod) - 1; - // note - lookup table results in a nearly 10% performance improvement in fill* functions - static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - register uint8_t mask = postmask[mod]; - switch (color) - { - case WHITE: *pBuf |= mask; break; - case BLACK: *pBuf &= ~mask; break; - case INVERSE: *pBuf ^= mask; break; - } - } -} diff --git a/Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.h b/Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.h deleted file mode 100644 index 524531ac1a..0000000000 --- a/Sming/Libraries/Adafruit_SSD1306/Adafruit_SSD1306.h +++ /dev/null @@ -1,180 +0,0 @@ -/********************************************************************* -This is a library for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -#if ARDUINO >= 100 - #include "Arduino.h" - #define WIRE_WRITE Wire.write -#else - #include "WProgram.h" - #define WIRE_WRITE Wire.send -#endif - -#ifdef __SAM3X8E__ - typedef volatile RwReg PortReg; - typedef uint32_t PortMask; -#else - typedef volatile uint8_t PortReg; - typedef uint8_t PortMask; -#endif - -#include "../../SmingCore/SPI.h" -#include - -#define BLACK 0 -#define WHITE 1 -#define INVERSE 2 - -#define SSD1306_I2C_ADDRESS 0x3C // 011110+SA0+RW - 0x3C or 0x3D -// Address for 128x32 is 0x3C -// Address for 128x64 is 0x3D (default) or 0x3C (if SA0 is grounded) - -/*========================================================================= - SSD1306 Displays - ----------------------------------------------------------------------- - The driver is used in multiple displays (128x64, 128x32, etc.). - Select the appropriate display below to create an appropriately - sized framebuffer, etc. - - SSD1306_128_64 128x64 pixel display - - SSD1306_128_32 128x32 pixel display - - SSD1306_96_16 - - SH1106_128_64 - 1.3" OLED display version - - -----------------------------------------------------------------------*/ -// #define SH1106_128_64 - #define SSD1306_128_64 -// #define SSD1306_128_32 -// #define SSD1306_96_16 -/*=========================================================================*/ - -#if defined SSD1306_128_64 && defined SH1106_128_64 - #error "Select either SH1106 or SSD1306 display type in SSD1306.h" -#endif - -#if defined SSD1306_128_64 && defined SSD1306_128_32 - #error "Only one SSD1306 display can be specified at once in SSD1306.h" -#endif -#if !defined SSD1306_128_64 && !defined SSD1306_128_32 && \ - !defined SSD1306_96_16 && !defined SH1106_128_64 - #error "At least one SSD1306 display must be specified in SSD1306.h" -#endif - -#if defined SSD1306_128_64 || defined SH1106_128_64 - #define SSD1306_LCDWIDTH 128 - #define SSD1306_LCDHEIGHT 64 -#endif -#if defined SSD1306_128_32 - #define SSD1306_LCDWIDTH 128 - #define SSD1306_LCDHEIGHT 32 -#endif -#if defined SSD1306_96_16 - #define SSD1306_LCDWIDTH 96 - #define SSD1306_LCDHEIGHT 16 -#endif - -#define SSD1306_SETCONTRAST 0x81 -#define SSD1306_DISPLAYALLON_RESUME 0xA4 -#define SSD1306_DISPLAYALLON 0xA5 -#define SSD1306_NORMALDISPLAY 0xA6 -#define SSD1306_INVERTDISPLAY 0xA7 -#define SSD1306_DISPLAYOFF 0xAE -#define SSD1306_DISPLAYON 0xAF - -#define SSD1306_SETDISPLAYOFFSET 0xD3 -#define SSD1306_SETCOMPINS 0xDA - -#define SSD1306_SETVCOMDETECT 0xDB - -#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 -#define SSD1306_SETPRECHARGE 0xD9 - -#define SSD1306_SETMULTIPLEX 0xA8 - -#define SSD1306_SETLOWCOLUMN 0x00 -#define SSD1306_SETHIGHCOLUMN 0x10 - -#define SSD1306_SETSTARTLINE 0x40 - -#define SSD1306_MEMORYMODE 0x20 -#define SSD1306_COLUMNADDR 0x21 -#define SSD1306_PAGEADDR 0x22 - -#define SSD1306_COMSCANINC 0xC0 -#define SSD1306_COMSCANDEC 0xC8 - -#define SSD1306_SEGREMAP 0xA0 - -#define SSD1306_CHARGEPUMP 0x8D - -#define SSD1306_EXTERNALVCC 0x1 -#define SSD1306_SWITCHCAPVCC 0x2 - -#define SH1106_SETSTARTPAGE 0xB0 - -// Scrolling #defines -#define SSD1306_ACTIVATE_SCROLL 0x2F -#define SSD1306_DEACTIVATE_SCROLL 0x2E -#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 -#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 -#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 -#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 -#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A - -class Adafruit_SSD1306 : public Adafruit_GFX { - public: - Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS); - Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS); - Adafruit_SSD1306(int8_t RST); - - void begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC, uint8_t i2caddr = SSD1306_I2C_ADDRESS, bool reset=true); - void ssd1306_command(uint8_t c); - void ssd1306_data(uint8_t c); - - void clearDisplay(void); - void invertDisplay(uint8_t i); - void display(); - - void startscrollright(uint8_t start, uint8_t stop); - void startscrollleft(uint8_t start, uint8_t stop); - - void startscrolldiagright(uint8_t start, uint8_t stop); - void startscrolldiagleft(uint8_t start, uint8_t stop); - void stopscroll(void); - - void dim(boolean dim); - - void drawPixel(int16_t x, int16_t y, uint16_t color); - - virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); - virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); - - private: - int8_t _i2caddr, _vccstate, sid, sclk, dc, rst, cs; - void fastSPIwrite(uint8_t c); - - boolean hwSPI; - PortReg *mosiport, *clkport, *csport, *dcport; - PortMask mosipinmask, clkpinmask, cspinmask, dcpinmask; - - inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline)); - inline void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline)); - -}; diff --git a/Sming/Libraries/Adafruit_SSD1306/README.txt b/Sming/Libraries/Adafruit_SSD1306/README.txt deleted file mode 100644 index 420cc153cc..0000000000 --- a/Sming/Libraries/Adafruit_SSD1306/README.txt +++ /dev/null @@ -1,24 +0,0 @@ -This is a library for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -Scrolling code contributed by Michael Gregg -BSD license, check license.txt for more information -All text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1306. Check that the Adafruit_SSD1306 folder contains Adafruit_SSD1306.cpp and Adafruit_SSD1306.h - -Place the Adafruit_SSD1306 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. - -You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from -https://github.com/adafruit/Adafruit-GFX-Library -and download/install that library as well \ No newline at end of file diff --git a/Sming/Libraries/Adafruit_SSD1306/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino b/Sming/Libraries/Adafruit_SSD1306/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino deleted file mode 100644 index e82ebc10e3..0000000000 --- a/Sming/Libraries/Adafruit_SSD1306/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino +++ /dev/null @@ -1,357 +0,0 @@ -/********************************************************************* -This is an example for our Monochrome OLEDs based on SSD1306 drivers - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/category/63_98 - -This example is for a 128x32 size display using I2C to communicate -3 pins are required to interface (2 I2C and one reset) - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -#include -#include -#include -#include - -#define OLED_RESET 4 -Adafruit_SSD1306 display(OLED_RESET); - -#define NUMFLAKES 10 -#define XPOS 0 -#define YPOS 1 -#define DELTAY 2 - - -#define LOGO16_GLCD_HEIGHT 16 -#define LOGO16_GLCD_WIDTH 16 -static const unsigned char PROGMEM logo16_glcd_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -#if (SSD1306_LCDHEIGHT != 32) -#error("Height incorrect, please fix Adafruit_SSD1306.h!"); -#endif - -void setup() { - Serial.begin(9600); - - // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) - display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) - // init done - - // Show image buffer on the display hardware. - // Since the buffer is intialized with an Adafruit splashscreen - // internally, this will display the splashscreen. - display.display(); - delay(2000); - - // Clear the buffer. - display.clearDisplay(); - - // draw a single pixel - display.drawPixel(10, 10, WHITE); - // Show the display buffer on the hardware. - // NOTE: You _must_ call display after making any drawing commands - // to make them visible on the display hardware! - display.display(); - delay(2000); - display.clearDisplay(); - - // draw many lines - testdrawline(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw rectangles - testdrawrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple rectangles - testfillrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw mulitple circles - testdrawcircle(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw a white circle, 10 pixel radius - display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); - display.display(); - delay(2000); - display.clearDisplay(); - - testdrawroundrect(); - delay(2000); - display.clearDisplay(); - - testfillroundrect(); - delay(2000); - display.clearDisplay(); - - testdrawtriangle(); - delay(2000); - display.clearDisplay(); - - testfilltriangle(); - delay(2000); - display.clearDisplay(); - - // draw the first ~12 characters in the font - testdrawchar(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw scrolling text - testscrolltext(); - delay(2000); - display.clearDisplay(); - - // text display tests - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println("Hello, world!"); - display.setTextColor(BLACK, WHITE); // 'inverted' text - display.println(3.141592); - display.setTextSize(2); - display.setTextColor(WHITE); - display.print("0x"); display.println(0xDEADBEEF, HEX); - display.display(); - delay(2000); - - // miniature bitmap display - display.clearDisplay(); - display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); - display.display(); - - // invert the display - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - // draw a bitmap icon and 'animate' movement - testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); -} - - -void loop() { - -} - - -void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { - uint8_t icons[NUMFLAKES][3]; - - // initialize - for (uint8_t f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - - Serial.print("x: "); - Serial.print(icons[f][XPOS], DEC); - Serial.print(" y: "); - Serial.print(icons[f][YPOS], DEC); - Serial.print(" dy: "); - Serial.println(icons[f][DELTAY], DEC); - } - - while (1) { - // draw each icon - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); - } - display.display(); - delay(200); - - // then erase it + move it - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); - // move it - icons[f][YPOS] += icons[f][DELTAY]; - // if its gone, reinit - if (icons[f][YPOS] > display.height()) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - } - } - } -} - - -void testdrawchar(void) { - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - - for (uint8_t i=0; i < 168; i++) { - if (i == '\n') continue; - display.write(i); - if ((i > 0) && (i % 21 == 0)) - display.println(); - } - display.display(); -} - -void testdrawcircle(void) { - for (int16_t i=0; i0; i-=5) { - display.fillTriangle(display.width()/2, display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, WHITE); - if (color == WHITE) color = BLACK; - else color = WHITE; - display.display(); - } -} - -void testdrawroundrect(void) { - for (int16_t i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - } - for (int16_t i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=0; i http://www.adafruit.com/category/63_98 - -This example is for a 128x32 size display using SPI to communicate -4 or 5 pins are required to interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -#include -#include -#include -#include - -// If using software SPI (the default case): -#define OLED_MOSI 9 -#define OLED_CLK 10 -#define OLED_DC 11 -#define OLED_CS 12 -#define OLED_RESET 13 -Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); - -/* Uncomment this block to use hardware SPI -#define OLED_DC 6 -#define OLED_CS 7 -#define OLED_RESET 8 -Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS); -*/ - -#define NUMFLAKES 10 -#define XPOS 0 -#define YPOS 1 -#define DELTAY 2 - -#define LOGO16_GLCD_HEIGHT 16 -#define LOGO16_GLCD_WIDTH 16 -static const unsigned char PROGMEM logo16_glcd_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -#if (SSD1306_LCDHEIGHT != 32) -#error("Height incorrect, please fix Adafruit_SSD1306.h!"); -#endif - -void setup() { - Serial.begin(9600); - - // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) - display.begin(SSD1306_SWITCHCAPVCC); - // init done - - // Show image buffer on the display hardware. - // Since the buffer is intialized with an Adafruit splashscreen - // internally, this will display the splashscreen. - display.display(); - delay(2000); - - // Clear the buffer. - display.clearDisplay(); - - // draw a single pixel - display.drawPixel(10, 10, WHITE); - // Show the display buffer on the hardware. - // NOTE: You _must_ call display after making any drawing commands - // to make them visible on the display hardware! - display.display(); - delay(2000); - display.clearDisplay(); - - // draw many lines - testdrawline(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw rectangles - testdrawrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple rectangles - testfillrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw mulitple circles - testdrawcircle(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw a white circle, 10 pixel radius - display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); - display.display(); - delay(2000); - display.clearDisplay(); - - testdrawroundrect(); - delay(2000); - display.clearDisplay(); - - testfillroundrect(); - delay(2000); - display.clearDisplay(); - - testdrawtriangle(); - delay(2000); - display.clearDisplay(); - - testfilltriangle(); - delay(2000); - display.clearDisplay(); - - // draw the first ~12 characters in the font - testdrawchar(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw scrolling text - testscrolltext(); - delay(2000); - display.clearDisplay(); - - // text display tests - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println("Hello, world!"); - display.setTextColor(BLACK, WHITE); // 'inverted' text - display.println(3.141592); - display.setTextSize(2); - display.setTextColor(WHITE); - display.print("0x"); display.println(0xDEADBEEF, HEX); - display.display(); - delay(2000); - - // miniature bitmap display - display.clearDisplay(); - display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); - display.display(); - - // invert the display - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - // draw a bitmap icon and 'animate' movement - testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); -} - - -void loop() { - -} - - -void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { - uint8_t icons[NUMFLAKES][3]; - - // initialize - for (uint8_t f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - - Serial.print("x: "); - Serial.print(icons[f][XPOS], DEC); - Serial.print(" y: "); - Serial.print(icons[f][YPOS], DEC); - Serial.print(" dy: "); - Serial.println(icons[f][DELTAY], DEC); - } - - while (1) { - // draw each icon - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); - } - display.display(); - delay(200); - - // then erase it + move it - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); - // move it - icons[f][YPOS] += icons[f][DELTAY]; - // if its gone, reinit - if (icons[f][YPOS] > display.height()) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - } - } - } -} - - -void testdrawchar(void) { - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - - for (uint8_t i=0; i < 168; i++) { - if (i == '\n') continue; - display.write(i); - if ((i > 0) && (i % 21 == 0)) - display.println(); - } - display.display(); -} - -void testdrawcircle(void) { - for (int16_t i=0; i0; i-=5) { - display.fillTriangle(display.width()/2, display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, WHITE); - if (color == WHITE) color = BLACK; - else color = WHITE; - display.display(); - } -} - -void testdrawroundrect(void) { - for (int16_t i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - } - for (int16_t i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=0; i http://www.adafruit.com/category/63_98 - -This example is for a 128x64 size display using I2C to communicate -3 pins are required to interface (2 I2C and one reset) - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -#include -#include -#include -#include - -#define OLED_RESET 4 -Adafruit_SSD1306 display(OLED_RESET); - -#define NUMFLAKES 10 -#define XPOS 0 -#define YPOS 1 -#define DELTAY 2 - - -#define LOGO16_GLCD_HEIGHT 16 -#define LOGO16_GLCD_WIDTH 16 -static const unsigned char PROGMEM logo16_glcd_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -#if (SSD1306_LCDHEIGHT != 64) -#error("Height incorrect, please fix Adafruit_SSD1306.h!"); -#endif - -void setup() { - Serial.begin(9600); - - // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) - display.begin(SSD1306_SWITCHCAPVCC, 0x3D); // initialize with the I2C addr 0x3D (for the 128x64) - // init done - - // Show image buffer on the display hardware. - // Since the buffer is intialized with an Adafruit splashscreen - // internally, this will display the splashscreen. - display.display(); - delay(2000); - - // Clear the buffer. - display.clearDisplay(); - - // draw a single pixel - display.drawPixel(10, 10, WHITE); - // Show the display buffer on the hardware. - // NOTE: You _must_ call display after making any drawing commands - // to make them visible on the display hardware! - display.display(); - delay(2000); - display.clearDisplay(); - - // draw many lines - testdrawline(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw rectangles - testdrawrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple rectangles - testfillrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw mulitple circles - testdrawcircle(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw a white circle, 10 pixel radius - display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); - display.display(); - delay(2000); - display.clearDisplay(); - - testdrawroundrect(); - delay(2000); - display.clearDisplay(); - - testfillroundrect(); - delay(2000); - display.clearDisplay(); - - testdrawtriangle(); - delay(2000); - display.clearDisplay(); - - testfilltriangle(); - delay(2000); - display.clearDisplay(); - - // draw the first ~12 characters in the font - testdrawchar(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw scrolling text - testscrolltext(); - delay(2000); - display.clearDisplay(); - - // text display tests - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println("Hello, world!"); - display.setTextColor(BLACK, WHITE); // 'inverted' text - display.println(3.141592); - display.setTextSize(2); - display.setTextColor(WHITE); - display.print("0x"); display.println(0xDEADBEEF, HEX); - display.display(); - delay(2000); - - // miniature bitmap display - display.clearDisplay(); - display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); - display.display(); - - // invert the display - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - // draw a bitmap icon and 'animate' movement - testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); -} - - -void loop() { - -} - - -void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { - uint8_t icons[NUMFLAKES][3]; - - // initialize - for (uint8_t f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - - Serial.print("x: "); - Serial.print(icons[f][XPOS], DEC); - Serial.print(" y: "); - Serial.print(icons[f][YPOS], DEC); - Serial.print(" dy: "); - Serial.println(icons[f][DELTAY], DEC); - } - - while (1) { - // draw each icon - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); - } - display.display(); - delay(200); - - // then erase it + move it - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); - // move it - icons[f][YPOS] += icons[f][DELTAY]; - // if its gone, reinit - if (icons[f][YPOS] > display.height()) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - } - } - } -} - - -void testdrawchar(void) { - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - - for (uint8_t i=0; i < 168; i++) { - if (i == '\n') continue; - display.write(i); - if ((i > 0) && (i % 21 == 0)) - display.println(); - } - display.display(); -} - -void testdrawcircle(void) { - for (int16_t i=0; i0; i-=5) { - display.fillTriangle(display.width()/2, display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, WHITE); - if (color == WHITE) color = BLACK; - else color = WHITE; - display.display(); - } -} - -void testdrawroundrect(void) { - for (int16_t i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - } - for (int16_t i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=0; i http://www.adafruit.com/category/63_98 - -This example is for a 128x64 size display using SPI to communicate -4 or 5 pins are required to interface - -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -BSD license, check license.txt for more information -All text above, and the splash screen must be included in any redistribution -*********************************************************************/ - -#include -#include -#include -#include - -// If using software SPI (the default case): -#define OLED_MOSI 9 -#define OLED_CLK 10 -#define OLED_DC 11 -#define OLED_CS 12 -#define OLED_RESET 13 -Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); - -/* Uncomment this block to use hardware SPI -#define OLED_DC 6 -#define OLED_CS 7 -#define OLED_RESET 8 -Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS); -*/ - -#define NUMFLAKES 10 -#define XPOS 0 -#define YPOS 1 -#define DELTAY 2 - -#define LOGO16_GLCD_HEIGHT 16 -#define LOGO16_GLCD_WIDTH 16 -static const unsigned char PROGMEM logo16_glcd_bmp[] = -{ B00000000, B11000000, - B00000001, B11000000, - B00000001, B11000000, - B00000011, B11100000, - B11110011, B11100000, - B11111110, B11111000, - B01111110, B11111111, - B00110011, B10011111, - B00011111, B11111100, - B00001101, B01110000, - B00011011, B10100000, - B00111111, B11100000, - B00111111, B11110000, - B01111100, B11110000, - B01110000, B01110000, - B00000000, B00110000 }; - -#if (SSD1306_LCDHEIGHT != 64) -#error("Height incorrect, please fix Adafruit_SSD1306.h!"); -#endif - -void setup() { - Serial.begin(9600); - - // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) - display.begin(SSD1306_SWITCHCAPVCC); - // init done - - // Show image buffer on the display hardware. - // Since the buffer is intialized with an Adafruit splashscreen - // internally, this will display the splashscreen. - display.display(); - delay(2000); - - // Clear the buffer. - display.clearDisplay(); - - // draw a single pixel - display.drawPixel(10, 10, WHITE); - // Show the display buffer on the hardware. - // NOTE: You _must_ call display after making any drawing commands - // to make them visible on the display hardware! - display.display(); - delay(2000); - display.clearDisplay(); - - // draw many lines - testdrawline(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw rectangles - testdrawrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw multiple rectangles - testfillrect(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw mulitple circles - testdrawcircle(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw a white circle, 10 pixel radius - display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); - display.display(); - delay(2000); - display.clearDisplay(); - - testdrawroundrect(); - delay(2000); - display.clearDisplay(); - - testfillroundrect(); - delay(2000); - display.clearDisplay(); - - testdrawtriangle(); - delay(2000); - display.clearDisplay(); - - testfilltriangle(); - delay(2000); - display.clearDisplay(); - - // draw the first ~12 characters in the font - testdrawchar(); - display.display(); - delay(2000); - display.clearDisplay(); - - // draw scrolling text - testscrolltext(); - delay(2000); - display.clearDisplay(); - - // text display tests - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - display.println("Hello, world!"); - display.setTextColor(BLACK, WHITE); // 'inverted' text - display.println(3.141592); - display.setTextSize(2); - display.setTextColor(WHITE); - display.print("0x"); display.println(0xDEADBEEF, HEX); - display.display(); - delay(2000); - - // miniature bitmap display - display.clearDisplay(); - display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); - display.display(); - - // invert the display - display.invertDisplay(true); - delay(1000); - display.invertDisplay(false); - delay(1000); - - // draw a bitmap icon and 'animate' movement - testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); -} - - -void loop() { - -} - - -void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { - uint8_t icons[NUMFLAKES][3]; - - // initialize - for (uint8_t f=0; f< NUMFLAKES; f++) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - - Serial.print("x: "); - Serial.print(icons[f][XPOS], DEC); - Serial.print(" y: "); - Serial.print(icons[f][YPOS], DEC); - Serial.print(" dy: "); - Serial.println(icons[f][DELTAY], DEC); - } - - while (1) { - // draw each icon - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); - } - display.display(); - delay(200); - - // then erase it + move it - for (uint8_t f=0; f< NUMFLAKES; f++) { - display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); - // move it - icons[f][YPOS] += icons[f][DELTAY]; - // if its gone, reinit - if (icons[f][YPOS] > display.height()) { - icons[f][XPOS] = random(display.width()); - icons[f][YPOS] = 0; - icons[f][DELTAY] = random(5) + 1; - } - } - } -} - - -void testdrawchar(void) { - display.setTextSize(1); - display.setTextColor(WHITE); - display.setCursor(0,0); - - for (uint8_t i=0; i < 168; i++) { - if (i == '\n') continue; - display.write(i); - if ((i > 0) && (i % 21 == 0)) - display.println(); - } - display.display(); -} - -void testdrawcircle(void) { - for (int16_t i=0; i0; i-=5) { - display.fillTriangle(display.width()/2, display.height()/2-i, - display.width()/2-i, display.height()/2+i, - display.width()/2+i, display.height()/2+i, WHITE); - if (color == WHITE) color = BLACK; - else color = WHITE; - display.display(); - } -} - -void testdrawroundrect(void) { - for (int16_t i=0; i=0; i-=4) { - display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=display.width()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); - display.display(); - } - for (int16_t i=display.height()-1; i>=0; i-=4) { - display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); - display.display(); - } - delay(250); - - display.clearDisplay(); - for (int16_t i=0; i http://www.adafruit.com/products/358 -The 1.8" TFT shield - ----> https://www.adafruit.com/product/802 -The 1.44" TFT breakout - ----> https://www.adafruit.com/product/2088 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#include "Adafruit_ST7735.h" -#include -#include "pins_arduino.h" -#include "wiring_private.h" -#include - - -inline uint16_t swapcolor(uint16_t x) { - return (x << 11) | (x & 0x07E0) | (x >> 11); -} - -#if defined (SPI_HAS_TRANSACTION) - static SPISettings mySPISettings; -#elif defined (__AVR__) - static uint8_t SPCRbackup; - static uint8_t mySPCR; -#endif - - - -// Constructor when using software SPI. All output pins are configurable. -Adafruit_ST7735::Adafruit_ST7735(int8_t cs, int8_t rs, int8_t sid, int8_t sclk, int8_t rst) - : Adafruit_GFX(ST7735_TFTWIDTH, ST7735_TFTHEIGHT_18) -{ - _cs = cs; - _rs = rs; - _sid = sid; - _sclk = sclk; - _rst = rst; - hwSPI = false; -} - - -// Constructor when using hardware SPI. Faster, but must use SPI pins -// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.) -Adafruit_ST7735::Adafruit_ST7735(int8_t cs, int8_t rs, int8_t rst) - : Adafruit_GFX(ST7735_TFTWIDTH, ST7735_TFTHEIGHT_18) { - _cs = cs; - _rs = rs; - _rst = rst; - hwSPI = true; - _sid = _sclk = 0; -} - -#if defined(CORE_TEENSY) && !defined(__AVR__) -#define __AVR__ -#endif - -inline void Adafruit_ST7735::spiwrite(uint8_t c) { - - //Serial.println(c, HEX); - - if (hwSPI) { -#if defined (SPI_HAS_TRANSACTION) - SPI.transfer(c); -#elif defined (__AVR__) - SPCRbackup = SPCR; - SPCR = mySPCR; - SPI.transfer(c); - SPCR = SPCRbackup; -// SPDR = c; -// while(!(SPSR & _BV(SPIF))); -#elif defined (__arm__) - SPI.setClockDivider(21); //4MHz - SPI.setDataMode(SPI_MODE0); - SPI.transfer(c); -#elif defined (__ESP8266_EX__) - SPI.transfer(c); -#endif - } else { - // Fast SPI bitbang swiped from LPD8806 library - for(uint8_t bit = 0x80; bit; bit >>= 1) { - if(c & bit) *dataport |= datapinmask; - else *dataport &= ~datapinmask; - *clkport |= clkpinmask; - *clkport &= ~clkpinmask; - } - } -} - - -void Adafruit_ST7735::writecommand(uint8_t c) { -#if defined (SPI_HAS_TRANSACTION) - SPI.beginTransaction(mySPISettings); -#endif - *rsport &= ~rspinmask; - *csport &= ~cspinmask; - - //Serial.print("C "); - spiwrite(c); - - *csport |= cspinmask; -#if defined (SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - - -void Adafruit_ST7735::writedata(uint8_t c) { -#if defined (SPI_HAS_TRANSACTION) - SPI.beginTransaction(mySPISettings); -#endif - *rsport |= rspinmask; - *csport &= ~cspinmask; - - //Serial.print("D "); - spiwrite(c); - - *csport |= cspinmask; -#if defined (SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - -// Rather than a bazillion writecommand() and writedata() calls, screen -// initialization commands and arguments are organized in these tables -// stored in PROGMEM. The table may look bulky, but that's mostly the -// formatting -- storage-wise this is hundreds of bytes more compact -// than the equivalent code. Companion function follows. -#define DELAY 0x80 -static const uint8_t PROGMEM - Bcmd[] = { // Initialization commands for 7735B screens - 18, // 18 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay - 50, // 50 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay - 255, // 255 = 500 ms delay - ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay: - 0x05, // 16-bit color - 10, // 10 ms delay - ST7735_FRMCTR1, 3+DELAY, // 4: Frame rate control, 3 args + delay: - 0x00, // fastest refresh - 0x06, // 6 lines front porch - 0x03, // 3 lines back porch - 10, // 10 ms delay - ST7735_MADCTL , 1 , // 5: Memory access ctrl (directions), 1 arg: - 0x08, // Row addr/col addr, bottom to top refresh - ST7735_DISSET5, 2 , // 6: Display settings #5, 2 args, no delay: - 0x15, // 1 clk cycle nonoverlap, 2 cycle gate - // rise, 3 cycle osc equalize - 0x02, // Fix on VTL - ST7735_INVCTR , 1 , // 7: Display inversion control, 1 arg: - 0x0, // Line inversion - ST7735_PWCTR1 , 2+DELAY, // 8: Power control, 2 args + delay: - 0x02, // GVDD = 4.7V - 0x70, // 1.0uA - 10, // 10 ms delay - ST7735_PWCTR2 , 1 , // 9: Power control, 1 arg, no delay: - 0x05, // VGH = 14.7V, VGL = -7.35V - ST7735_PWCTR3 , 2 , // 10: Power control, 2 args, no delay: - 0x01, // Opamp current small - 0x02, // Boost frequency - ST7735_VMCTR1 , 2+DELAY, // 11: Power control, 2 args + delay: - 0x3C, // VCOMH = 4V - 0x38, // VCOML = -1.1V - 10, // 10 ms delay - ST7735_PWCTR6 , 2 , // 12: Power control, 2 args, no delay: - 0x11, 0x15, - ST7735_GMCTRP1,16 , // 13: Magical unicorn dust, 16 args, no delay: - 0x09, 0x16, 0x09, 0x20, // (seriously though, not sure what - 0x21, 0x1B, 0x13, 0x19, // these config values represent) - 0x17, 0x15, 0x1E, 0x2B, - 0x04, 0x05, 0x02, 0x0E, - ST7735_GMCTRN1,16+DELAY, // 14: Sparkles and rainbows, 16 args + delay: - 0x0B, 0x14, 0x08, 0x1E, // (ditto) - 0x22, 0x1D, 0x18, 0x1E, - 0x1B, 0x1A, 0x24, 0x2B, - 0x06, 0x06, 0x02, 0x0F, - 10, // 10 ms delay - ST7735_CASET , 4 , // 15: Column addr set, 4 args, no delay: - 0x00, 0x02, // XSTART = 2 - 0x00, 0x81, // XEND = 129 - ST7735_RASET , 4 , // 16: Row addr set, 4 args, no delay: - 0x00, 0x02, // XSTART = 1 - 0x00, 0x81, // XEND = 160 - ST7735_NORON , DELAY, // 17: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 18: Main screen turn on, no args, w/delay - 255 }, // 255 = 500 ms delay - - Rcmd1[] = { // Init for 7735R, part 1 (red or green tab) - 15, // 15 commands in list: - ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay - 150, // 150 ms delay - ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, 0 args, w/delay - 255, // 500 ms delay - ST7735_FRMCTR1, 3 , // 3: Frame rate ctrl - normal mode, 3 args: - 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) - ST7735_FRMCTR2, 3 , // 4: Frame rate control - idle mode, 3 args: - 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) - ST7735_FRMCTR3, 6 , // 5: Frame rate ctrl - partial mode, 6 args: - 0x01, 0x2C, 0x2D, // Dot inversion mode - 0x01, 0x2C, 0x2D, // Line inversion mode - ST7735_INVCTR , 1 , // 6: Display inversion ctrl, 1 arg, no delay: - 0x07, // No inversion - ST7735_PWCTR1 , 3 , // 7: Power control, 3 args, no delay: - 0xA2, - 0x02, // -4.6V - 0x84, // AUTO mode - ST7735_PWCTR2 , 1 , // 8: Power control, 1 arg, no delay: - 0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD - ST7735_PWCTR3 , 2 , // 9: Power control, 2 args, no delay: - 0x0A, // Opamp current small - 0x00, // Boost frequency - ST7735_PWCTR4 , 2 , // 10: Power control, 2 args, no delay: - 0x8A, // BCLK/2, Opamp current small & Medium low - 0x2A, - ST7735_PWCTR5 , 2 , // 11: Power control, 2 args, no delay: - 0x8A, 0xEE, - ST7735_VMCTR1 , 1 , // 12: Power control, 1 arg, no delay: - 0x0E, - ST7735_INVOFF , 0 , // 13: Don't invert display, no args, no delay - ST7735_MADCTL , 1 , // 14: Memory access control (directions), 1 arg: - 0xC8, // row addr/col addr, bottom to top refresh - ST7735_COLMOD , 1 , // 15: set color mode, 1 arg, no delay: - 0x05 }, // 16-bit color - - Rcmd2green[] = { // Init for 7735R, part 2 (green tab only) - 2, // 2 commands in list: - ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay: - 0x00, 0x02, // XSTART = 0 - 0x00, 0x7F+0x02, // XEND = 127 - ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay: - 0x00, 0x01, // XSTART = 0 - 0x00, 0x9F+0x01 }, // XEND = 159 - Rcmd2red[] = { // Init for 7735R, part 2 (red tab only) - 2, // 2 commands in list: - ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay: - 0x00, 0x00, // XSTART = 0 - 0x00, 0x7F, // XEND = 127 - ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay: - 0x00, 0x00, // XSTART = 0 - 0x00, 0x9F }, // XEND = 159 - - Rcmd2green144[] = { // Init for 7735R, part 2 (green 1.44 tab) - 2, // 2 commands in list: - ST7735_CASET , 4 , // 1: Column addr set, 4 args, no delay: - 0x00, 0x00, // XSTART = 0 - 0x00, 0x7F, // XEND = 127 - ST7735_RASET , 4 , // 2: Row addr set, 4 args, no delay: - 0x00, 0x00, // XSTART = 0 - 0x00, 0x7F }, // XEND = 127 - - Rcmd3[] = { // Init for 7735R, part 3 (red or green tab) - 4, // 4 commands in list: - ST7735_GMCTRP1, 16 , // 1: Magical unicorn dust, 16 args, no delay: - 0x02, 0x1c, 0x07, 0x12, - 0x37, 0x32, 0x29, 0x2d, - 0x29, 0x25, 0x2B, 0x39, - 0x00, 0x01, 0x03, 0x10, - ST7735_GMCTRN1, 16 , // 2: Sparkles and rainbows, 16 args, no delay: - 0x03, 0x1d, 0x07, 0x06, - 0x2E, 0x2C, 0x29, 0x2D, - 0x2E, 0x2E, 0x37, 0x3F, - 0x00, 0x00, 0x02, 0x10, - ST7735_NORON , DELAY, // 3: Normal display on, no args, w/delay - 10, // 10 ms delay - ST7735_DISPON , DELAY, // 4: Main screen turn on, no args w/delay - 100 }; // 100 ms delay - - -// Companion code to the above tables. Reads and issues -// a series of LCD commands stored in PROGMEM byte array. -void Adafruit_ST7735::commandList(const uint8_t *addr) { - - uint8_t numCommands, numArgs; - uint16_t ms; - - numCommands = pgm_read_byte(addr++); // Number of commands to follow - while(numCommands--) { // For each command... - writecommand(pgm_read_byte(addr++)); // Read, issue command - numArgs = pgm_read_byte(addr++); // Number of args to follow - ms = numArgs & DELAY; // If hibit set, delay follows args - numArgs &= ~DELAY; // Mask out delay bit - while(numArgs--) { // For each argument... - writedata(pgm_read_byte(addr++)); // Read, issue argument - } - - if(ms) { - ms = pgm_read_byte(addr++); // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms - delay(ms); - } - } -} - - -// Initialization code common to both 'B' and 'R' type displays -void Adafruit_ST7735::commonInit(const uint8_t *cmdList) { - colstart = rowstart = 0; // May be overridden in init func - - pinMode(_rs, OUTPUT); - pinMode(_cs, OUTPUT); - csport = portOutputRegister(digitalPinToPort(_cs)); - rsport = portOutputRegister(digitalPinToPort(_rs)); - cspinmask = digitalPinToBitMask(_cs); - rspinmask = digitalPinToBitMask(_rs); - - if(hwSPI) { // Using hardware SPI -#if defined (SPI_HAS_TRANSACTION) - SPI.begin(); - mySPISettings = SPISettings(10000000, MSBFIRST, SPI_MODE0); -#elif defined (__AVR__) - SPCRbackup = SPCR; - SPI.begin(); - SPI.setClockDivider(SPI_CLOCK_DIV4); - SPI.setDataMode(SPI_MODE0); - mySPCR = SPCR; // save our preferred state - //Serial.print("mySPCR = 0x"); Serial.println(SPCR, HEX); - SPCR = SPCRbackup; // then restore -#elif defined (__SAM3X8E__) - SPI.begin(); - SPI.setClockDivider(21); //4MHz - SPI.setDataMode(SPI_MODE0); -#elif defined (__ESP8266_EX__) - SPI.begin(); - -#endif - } else { - pinMode(_sclk, OUTPUT); - pinMode(_sid , OUTPUT); - clkport = portOutputRegister(digitalPinToPort(_sclk)); - dataport = portOutputRegister(digitalPinToPort(_sid)); - clkpinmask = digitalPinToBitMask(_sclk); - datapinmask = digitalPinToBitMask(_sid); - *clkport &= ~clkpinmask; - *dataport &= ~datapinmask; - } - - // toggle RST low to reset; CS low so it'll listen to us - *csport &= ~cspinmask; - if (_rst) { - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(500); - digitalWrite(_rst, LOW); - delay(500); - digitalWrite(_rst, HIGH); - delay(500); - } - - if(cmdList) commandList(cmdList); -} - - -// Initialization for ST7735B screens -void Adafruit_ST7735::initB(void) { - commonInit(Bcmd); -} - - -// Initialization for ST7735R screens (green or red tabs) -void Adafruit_ST7735::initR(uint8_t options) { - commonInit(Rcmd1); - if(options == INITR_GREENTAB) { - commandList(Rcmd2green); - colstart = 2; - rowstart = 1; - } else if(options == INITR_144GREENTAB) { - _height = ST7735_TFTHEIGHT_144; - commandList(Rcmd2green144); - colstart = 2; - rowstart = 3; - } else { - // colstart, rowstart left at default '0' values - commandList(Rcmd2red); - } - commandList(Rcmd3); - - // if black, change MADCTL color filter - if (options == INITR_BLACKTAB) { - writecommand(ST7735_MADCTL); - writedata(0xC0); - } - - tabcolor = options; -} - - -void Adafruit_ST7735::setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1, - uint8_t y1) { - - writecommand(ST7735_CASET); // Column addr set - writedata(0x00); - writedata(x0+colstart); // XSTART - writedata(0x00); - writedata(x1+colstart); // XEND - - writecommand(ST7735_RASET); // Row addr set - writedata(0x00); - writedata(y0+rowstart); // YSTART - writedata(0x00); - writedata(y1+rowstart); // YEND - - writecommand(ST7735_RAMWR); // write to RAM -} - - -void Adafruit_ST7735::pushColor(uint16_t color) { -#if defined (SPI_HAS_TRANSACTION) - SPI.beginTransaction(mySPISettings); -#endif - *rsport |= rspinmask; - *csport &= ~cspinmask; - - spiwrite(color >> 8); - spiwrite(color); - - *csport |= cspinmask; -#if defined (SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - -void Adafruit_ST7735::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - - setAddrWindow(x,y,x+1,y+1); - -#if defined (SPI_HAS_TRANSACTION) - SPI.beginTransaction(mySPISettings); -#endif - *rsport |= rspinmask; - *csport &= ~cspinmask; - - spiwrite(color >> 8); - spiwrite(color); - - *csport |= cspinmask; -#if defined (SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - - -void Adafruit_ST7735::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((y+h-1) >= _height) h = _height-y; - setAddrWindow(x, y, x, y+h-1); - - uint8_t hi = color >> 8, lo = color; - -#if defined (SPI_HAS_TRANSACTION) - SPI.beginTransaction(mySPISettings); -#endif - *rsport |= rspinmask; - *csport &= ~cspinmask; - while (h--) { - spiwrite(hi); - spiwrite(lo); - } - *csport |= cspinmask; -#if defined (SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - - -void Adafruit_ST7735::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; - setAddrWindow(x, y, x+w-1, y); - - uint8_t hi = color >> 8, lo = color; - -#if defined (SPI_HAS_TRANSACTION) - SPI.beginTransaction(mySPISettings); -#endif - *rsport |= rspinmask; - *csport &= ~cspinmask; - while (w--) { - spiwrite(hi); - spiwrite(lo); - } - *csport |= cspinmask; -#if defined (SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - - - -void Adafruit_ST7735::fillScreen(uint16_t color) { - fillRect(0, 0, _width, _height, color); -} - - - -// fill a rectangle -void Adafruit_ST7735::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - setAddrWindow(x, y, x+w-1, y+h-1); - - uint8_t hi = color >> 8, lo = color; - -#if defined (SPI_HAS_TRANSACTION) - SPI.beginTransaction(mySPISettings); -#endif - *rsport |= rspinmask; - *csport &= ~cspinmask; - for(y=h; y>0; y--) { - for(x=w; x>0; x--) { - spiwrite(hi); - spiwrite(lo); - } - } - - *csport |= cspinmask; -#if defined (SPI_HAS_TRANSACTION) - SPI.endTransaction(); -#endif -} - - -// Pass 8-bit (each) R,G,B, get back 16-bit packed color -uint16_t Adafruit_ST7735::Color565(uint8_t r, uint8_t g, uint8_t b) { - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); -} - - -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 -#define MADCTL_RGB 0x00 -#define MADCTL_BGR 0x08 -#define MADCTL_MH 0x04 - -void Adafruit_ST7735::setRotation(uint8_t m) { - - writecommand(ST7735_MADCTL); - rotation = m % 4; // can't be higher than 3 - switch (rotation) { - case 0: - if (tabcolor == INITR_BLACKTAB) { - writedata(MADCTL_MX | MADCTL_MY | MADCTL_RGB); - } else { - writedata(MADCTL_MX | MADCTL_MY | MADCTL_BGR); - } - _width = ST7735_TFTWIDTH; - - if (tabcolor == INITR_144GREENTAB) - _height = ST7735_TFTHEIGHT_144; - else - _height = ST7735_TFTHEIGHT_18; - - break; - case 1: - if (tabcolor == INITR_BLACKTAB) { - writedata(MADCTL_MY | MADCTL_MV | MADCTL_RGB); - } else { - writedata(MADCTL_MY | MADCTL_MV | MADCTL_BGR); - } - - if (tabcolor == INITR_144GREENTAB) - _width = ST7735_TFTHEIGHT_144; - else - _width = ST7735_TFTHEIGHT_18; - - _height = ST7735_TFTWIDTH; - break; - case 2: - if (tabcolor == INITR_BLACKTAB) { - writedata(MADCTL_RGB); - } else { - writedata(MADCTL_BGR); - } - _width = ST7735_TFTWIDTH; - if (tabcolor == INITR_144GREENTAB) - _height = ST7735_TFTHEIGHT_144; - else - _height = ST7735_TFTHEIGHT_18; - - break; - case 3: - if (tabcolor == INITR_BLACKTAB) { - writedata(MADCTL_MX | MADCTL_MV | MADCTL_RGB); - } else { - writedata(MADCTL_MX | MADCTL_MV | MADCTL_BGR); - } - if (tabcolor == INITR_144GREENTAB) - _width = ST7735_TFTHEIGHT_144; - else - _width = ST7735_TFTHEIGHT_18; - - _height = ST7735_TFTWIDTH; - break; - } -} - - -void Adafruit_ST7735::invertDisplay(boolean i) { - writecommand(i ? ST7735_INVON : ST7735_INVOFF); -} - - -////////// stuff not actively being used, but kept for posterity -/* - - uint8_t Adafruit_ST7735::spiread(void) { - uint8_t r = 0; - if (_sid > 0) { - r = shiftIn(_sid, _sclk, MSBFIRST); - } else { - //SID_DDR &= ~_BV(SID); - //int8_t i; - //for (i=7; i>=0; i--) { - // SCLK_PORT &= ~_BV(SCLK); - // r <<= 1; - // r |= (SID_PIN >> SID) & 0x1; - // SCLK_PORT |= _BV(SCLK); - //} - //SID_DDR |= _BV(SID); - - } - return r; - } - - - void Adafruit_ST7735::dummyclock(void) { - - if (_sid > 0) { - digitalWrite(_sclk, LOW); - digitalWrite(_sclk, HIGH); - } else { - // SCLK_PORT &= ~_BV(SCLK); - //SCLK_PORT |= _BV(SCLK); - } - } - uint8_t Adafruit_ST7735::readdata(void) { - *portOutputRegister(rsport) |= rspin; - - *portOutputRegister(csport) &= ~ cspin; - - uint8_t r = spiread(); - - *portOutputRegister(csport) |= cspin; - - return r; - - } - - uint8_t Adafruit_ST7735::readcommand8(uint8_t c) { - digitalWrite(_rs, LOW); - - *portOutputRegister(csport) &= ~ cspin; - - spiwrite(c); - - digitalWrite(_rs, HIGH); - pinMode(_sid, INPUT); // input! - digitalWrite(_sid, LOW); // low - spiread(); - uint8_t r = spiread(); - - - *portOutputRegister(csport) |= cspin; - - - pinMode(_sid, OUTPUT); // back to output - return r; - } - - - uint16_t Adafruit_ST7735::readcommand16(uint8_t c) { - digitalWrite(_rs, LOW); - if (_cs) - digitalWrite(_cs, LOW); - - spiwrite(c); - pinMode(_sid, INPUT); // input! - uint16_t r = spiread(); - r <<= 8; - r |= spiread(); - if (_cs) - digitalWrite(_cs, HIGH); - - pinMode(_sid, OUTPUT); // back to output - return r; - } - - uint32_t Adafruit_ST7735::readcommand32(uint8_t c) { - digitalWrite(_rs, LOW); - if (_cs) - digitalWrite(_cs, LOW); - spiwrite(c); - pinMode(_sid, INPUT); // input! - - dummyclock(); - dummyclock(); - - uint32_t r = spiread(); - r <<= 8; - r |= spiread(); - r <<= 8; - r |= spiread(); - r <<= 8; - r |= spiread(); - if (_cs) - digitalWrite(_cs, HIGH); - - pinMode(_sid, OUTPUT); // back to output - return r; - } - - */ diff --git a/Sming/Libraries/Adafruit_ST7735/Adafruit_ST7735.h b/Sming/Libraries/Adafruit_ST7735/Adafruit_ST7735.h deleted file mode 100644 index 10e69a890e..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/Adafruit_ST7735.h +++ /dev/null @@ -1,187 +0,0 @@ -/*************************************************** - This is a library for the Adafruit 1.8" SPI display. - -This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 -The 1.8" TFT shield - ----> https://www.adafruit.com/product/802 -The 1.44" TFT breakout - ----> https://www.adafruit.com/product/2088 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ -/******************************** - * ported for Sming by H.Boettcher. - * hbottc@gmail.com - ********************************/ - -#ifndef _ADAFRUIT_ST7735H_ -#define _ADAFRUIT_ST7735H_ - -#if ARDUINO >= 100 - #include "Arduino.h" - #include "Print.h" -#else - #include "WProgram.h" -#endif - -#include "../Adafruit_GFX/Adafruit_GFX.h" - -#if defined(__SAM3X8E__) - #include - #define PROGMEM - #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) - #define pgm_read_word(addr) (*(const unsigned short *)(addr)) - typedef unsigned char prog_uchar; -#elif defined(__AVR__) - #include -#elif defined(ESP8266) - #include -#endif - -#if defined(__SAM3X8E__) - #undef __FlashStringHelper::F(string_literal) - #define F(string_literal) string_literal -#endif - -// some flags for initR() :( -#define INITR_GREENTAB 0x0 -#define INITR_REDTAB 0x1 -#define INITR_BLACKTAB 0x2 - -#define INITR_18GREENTAB INITR_GREENTAB -#define INITR_18REDTAB INITR_REDTAB -#define INITR_18BLACKTAB INITR_BLACKTAB -#define INITR_144GREENTAB 0x1 - -#define ST7735_TFTWIDTH 128 -// for 1.44" display -#define ST7735_TFTHEIGHT_144 128 -// for 1.8" display -#define ST7735_TFTHEIGHT_18 160 - -#define ST7735_NOP 0x00 -#define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 - -#define ST7735_SLPIN 0x10 -#define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 - -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 -#define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E - -#define ST7735_PTLAR 0x30 -#define ST7735_COLMOD 0x3A -#define ST7735_MADCTL 0x36 - -#define ST7735_FRMCTR1 0xB1 -#define ST7735_FRMCTR2 0xB2 -#define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 -#define ST7735_DISSET5 0xB6 - -#define ST7735_PWCTR1 0xC0 -#define ST7735_PWCTR2 0xC1 -#define ST7735_PWCTR3 0xC2 -#define ST7735_PWCTR4 0xC3 -#define ST7735_PWCTR5 0xC4 -#define ST7735_VMCTR1 0xC5 - -#define ST7735_RDID1 0xDA -#define ST7735_RDID2 0xDB -#define ST7735_RDID3 0xDC -#define ST7735_RDID4 0xDD - -#define ST7735_PWCTR6 0xFC - -#define ST7735_GMCTRP1 0xE0 -#define ST7735_GMCTRN1 0xE1 - -// Color definitions -#define ST7735_BLACK 0x0000 -#define ST7735_BLUE 0x001F -#define ST7735_RED 0xF800 -#define ST7735_GREEN 0x07E0 -#define ST7735_CYAN 0x07FF -#define ST7735_MAGENTA 0xF81F -#define ST7735_YELLOW 0xFFE0 -#define ST7735_WHITE 0xFFFF - - -class Adafruit_ST7735 : public Adafruit_GFX { - - public: - - Adafruit_ST7735(int8_t CS, int8_t RS, int8_t SID, int8_t SCLK, int8_t RST = -1); - Adafruit_ST7735(int8_t CS, int8_t RS, int8_t RST = -1); - - void initB(void), // for ST7735B displays - initR(uint8_t options = INITR_GREENTAB), // for ST7735R - setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1), - pushColor(uint16_t color), - fillScreen(uint16_t color), - drawPixel(int16_t x, int16_t y, uint16_t color), - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color), - setRotation(uint8_t r), - invertDisplay(boolean i); - uint16_t Color565(uint8_t r, uint8_t g, uint8_t b); - - /* These are not for current use, 8-bit protocol only! - uint8_t readdata(void), - readcommand8(uint8_t); - uint16_t readcommand16(uint8_t); - uint32_t readcommand32(uint8_t); - void dummyclock(void); - */ - - private: - uint8_t tabcolor; - - void spiwrite(uint8_t), - writecommand(uint8_t c), - writedata(uint8_t d), - commandList(const uint8_t *addr), - commonInit(const uint8_t *cmdList); -//uint8_t spiread(void); - - boolean hwSPI; - -#if defined(__AVR__) || defined(CORE_TEENSY) || defined (__ESP8266_EX__) - volatile uint8_t *dataport, *clkport, *csport, *rsport; - uint8_t _cs, _rs, _rst, _sid, _sclk, - datapinmask, clkpinmask, cspinmask, rspinmask, - colstart, rowstart; // some displays need this changed -#elif defined(__arm__) - volatile RwReg *dataport, *clkport, *csport, *rsport; - uint32_t _cs, _rs, _sid, _sclk, - datapinmask, clkpinmask, cspinmask, rspinmask, - colstart, rowstart; // some displays need this changed - int32_t _rst; // Must use signed type since a -1 sentinel is assigned. -#endif - - -}; - -#endif diff --git a/Sming/Libraries/Adafruit_ST7735/README.txt b/Sming/Libraries/Adafruit_ST7735/README.txt deleted file mode 100644 index e7881f6739..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/README.txt +++ /dev/null @@ -1,26 +0,0 @@ -This is a library for the Adafruit 1.8" SPI display. -This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 -The 1.8" TFT shield - ----> https://www.adafruit.com/product/802 -The 1.44" TFT breakout - ----> https://www.adafruit.com/product/2088 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - -Check out the links above for our tutorials and wiring diagrams. -These displays use SPI to communicate, 4 or 5 pins are required -to interface (RST is optional). -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing -products from Adafruit! - -Written by Limor Fried/Ladyada for Adafruit Industries. -MIT license, all text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_ST7735. Check that the Adafruit_ST7735 folder contains Adafruit_ST7735.cpp and Adafruit_ST7735. - -Place the Adafruit_ST7735 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE - -Also requires the Adafruit_GFX library for Arduino. diff --git a/Sming/Libraries/Adafruit_ST7735/examples/graphicstest/graphicstest.ino b/Sming/Libraries/Adafruit_ST7735/examples/graphicstest/graphicstest.ino deleted file mode 100644 index 11a0cf5b1d..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/examples/graphicstest/graphicstest.ino +++ /dev/null @@ -1,300 +0,0 @@ -/*************************************************** - This is a library for the Adafruit 1.8" SPI display. - -This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 -The 1.8" TFT shield - ----> https://www.adafruit.com/product/802 -The 1.44" TFT breakout - ----> https://www.adafruit.com/product/2088 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#include // Core graphics library -#include // Hardware-specific library -#include - - -// For the breakout, you can use any 2 or 3 pins -// These pins will also work for the 1.8" TFT shield -#define TFT_CS 10 -#define TFT_RST 9 // you can also connect this to the Arduino reset - // in which case, set this #define pin to 0! -#define TFT_DC 8 - -// Option 1 (recommended): must use the hardware SPI pins -// (for UNO thats sclk = 13 and sid = 11) and pin 10 must be -// an output. This is much faster - also required if you want -// to use the microSD card (see the image drawing example) -Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); - -// Option 2: use any pins but a little slower! -#define TFT_SCLK 13 // set these to be whatever pins you like! -#define TFT_MOSI 11 // set these to be whatever pins you like! -//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); - - -float p = 3.1415926; - -void setup(void) { - Serial.begin(9600); - Serial.print("Hello! ST7735 TFT Test"); - - // Use this initializer if you're using a 1.8" TFT - tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab - - // Use this initializer (uncomment) if you're using a 1.44" TFT - //tft.initR(INITR_144GREENTAB); // initialize a ST7735S chip, black tab - - Serial.println("Initialized"); - - uint16_t time = millis(); - tft.fillScreen(ST7735_BLACK); - time = millis() - time; - - Serial.println(time, DEC); - delay(500); - - // large block of text - tft.fillScreen(ST7735_BLACK); - testdrawtext("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a tortor imperdiet posuere. ", ST7735_WHITE); - delay(1000); - - // tft print function! - tftPrintTest(); - delay(4000); - - // a single pixel - tft.drawPixel(tft.width()/2, tft.height()/2, ST7735_GREEN); - delay(500); - - // line draw test - testlines(ST7735_YELLOW); - delay(500); - - // optimized lines - testfastlines(ST7735_RED, ST7735_BLUE); - delay(500); - - testdrawrects(ST7735_GREEN); - delay(500); - - testfillrects(ST7735_YELLOW, ST7735_MAGENTA); - delay(500); - - tft.fillScreen(ST7735_BLACK); - testfillcircles(10, ST7735_BLUE); - testdrawcircles(10, ST7735_WHITE); - delay(500); - - testroundrects(); - delay(500); - - testtriangles(); - delay(500); - - mediabuttons(); - delay(500); - - Serial.println("done"); - delay(1000); -} - -void loop() { - tft.invertDisplay(true); - delay(500); - tft.invertDisplay(false); - delay(500); -} - -void testlines(uint16_t color) { - tft.fillScreen(ST7735_BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(0, 0, x, tft.height()-1, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(0, 0, tft.width()-1, y, color); - } - - tft.fillScreen(ST7735_BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(tft.width()-1, 0, x, tft.height()-1, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(tft.width()-1, 0, 0, y, color); - } - - tft.fillScreen(ST7735_BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(0, tft.height()-1, x, 0, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(0, tft.height()-1, tft.width()-1, y, color); - } - - tft.fillScreen(ST7735_BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawLine(tft.width()-1, tft.height()-1, x, 0, color); - } - for (int16_t y=0; y < tft.height(); y+=6) { - tft.drawLine(tft.width()-1, tft.height()-1, 0, y, color); - } -} - -void testdrawtext(char *text, uint16_t color) { - tft.setCursor(0, 0); - tft.setTextColor(color); - tft.setTextWrap(true); - tft.print(text); -} - -void testfastlines(uint16_t color1, uint16_t color2) { - tft.fillScreen(ST7735_BLACK); - for (int16_t y=0; y < tft.height(); y+=5) { - tft.drawFastHLine(0, y, tft.width(), color1); - } - for (int16_t x=0; x < tft.width(); x+=5) { - tft.drawFastVLine(x, 0, tft.height(), color2); - } -} - -void testdrawrects(uint16_t color) { - tft.fillScreen(ST7735_BLACK); - for (int16_t x=0; x < tft.width(); x+=6) { - tft.drawRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color); - } -} - -void testfillrects(uint16_t color1, uint16_t color2) { - tft.fillScreen(ST7735_BLACK); - for (int16_t x=tft.width()-1; x > 6; x-=6) { - tft.fillRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color1); - tft.drawRect(tft.width()/2 -x/2, tft.height()/2 -x/2 , x, x, color2); - } -} - -void testfillcircles(uint8_t radius, uint16_t color) { - for (int16_t x=radius; x < tft.width(); x+=radius*2) { - for (int16_t y=radius; y < tft.height(); y+=radius*2) { - tft.fillCircle(x, y, radius, color); - } - } -} - -void testdrawcircles(uint8_t radius, uint16_t color) { - for (int16_t x=0; x < tft.width()+radius; x+=radius*2) { - for (int16_t y=0; y < tft.height()+radius; y+=radius*2) { - tft.drawCircle(x, y, radius, color); - } - } -} - -void testtriangles() { - tft.fillScreen(ST7735_BLACK); - int color = 0xF800; - int t; - int w = tft.width()/2; - int x = tft.height()-1; - int y = 0; - int z = tft.width(); - for(t = 0 ; t <= 15; t+=1) { - tft.drawTriangle(w, y, y, x, z, x, color); - x-=4; - y+=4; - z-=4; - color+=100; - } -} - -void testroundrects() { - tft.fillScreen(ST7735_BLACK); - int color = 100; - int i; - int t; - for(t = 0 ; t <= 4; t+=1) { - int x = 0; - int y = 0; - int w = tft.width()-2; - int h = tft.height()-2; - for(i = 0 ; i <= 16; i+=1) { - tft.drawRoundRect(x, y, w, h, 5, color); - x+=2; - y+=3; - w-=4; - h-=6; - color+=1100; - } - color+=100; - } -} - -void tftPrintTest() { - tft.setTextWrap(false); - tft.fillScreen(ST7735_BLACK); - tft.setCursor(0, 30); - tft.setTextColor(ST7735_RED); - tft.setTextSize(1); - tft.println("Hello World!"); - tft.setTextColor(ST7735_YELLOW); - tft.setTextSize(2); - tft.println("Hello World!"); - tft.setTextColor(ST7735_GREEN); - tft.setTextSize(3); - tft.println("Hello World!"); - tft.setTextColor(ST7735_BLUE); - tft.setTextSize(4); - tft.print(1234.567); - delay(1500); - tft.setCursor(0, 0); - tft.fillScreen(ST7735_BLACK); - tft.setTextColor(ST7735_WHITE); - tft.setTextSize(0); - tft.println("Hello World!"); - tft.setTextSize(1); - tft.setTextColor(ST7735_GREEN); - tft.print(p, 6); - tft.println(" Want pi?"); - tft.println(" "); - tft.print(8675309, HEX); // print 8,675,309 out in HEX! - tft.println(" Print HEX!"); - tft.println(" "); - tft.setTextColor(ST7735_WHITE); - tft.println("Sketch has been"); - tft.println("running for: "); - tft.setTextColor(ST7735_MAGENTA); - tft.print(millis() / 1000); - tft.setTextColor(ST7735_WHITE); - tft.print(" seconds."); -} - -void mediabuttons() { - // play - tft.fillScreen(ST7735_BLACK); - tft.fillRoundRect(25, 10, 78, 60, 8, ST7735_WHITE); - tft.fillTriangle(42, 20, 42, 60, 90, 40, ST7735_RED); - delay(500); - // pause - tft.fillRoundRect(25, 90, 78, 60, 8, ST7735_WHITE); - tft.fillRoundRect(39, 98, 20, 45, 5, ST7735_GREEN); - tft.fillRoundRect(69, 98, 20, 45, 5, ST7735_GREEN); - delay(500); - // play color - tft.fillTriangle(42, 20, 42, 60, 90, 40, ST7735_BLUE); - delay(50); - // pause color - tft.fillRoundRect(39, 98, 20, 45, 5, ST7735_RED); - tft.fillRoundRect(69, 98, 20, 45, 5, ST7735_RED); - // play color - tft.fillTriangle(42, 20, 42, 60, 90, 40, ST7735_GREEN); -} diff --git a/Sming/Libraries/Adafruit_ST7735/examples/rotationtest/rotationtest.ino b/Sming/Libraries/Adafruit_ST7735/examples/rotationtest/rotationtest.ino deleted file mode 100644 index 0357f59bd7..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/examples/rotationtest/rotationtest.ino +++ /dev/null @@ -1,285 +0,0 @@ -/*************************************************** - This is a library for the Adafruit 1.8" SPI display. - -This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 -The 1.8" TFT shield - ----> https://www.adafruit.com/product/802 -The 1.44" TFT breakout - ----> https://www.adafruit.com/product/2088 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#include // Core graphics library -#include // Hardware-specific library -#include - - -// For the breakout, you can use any 2 or 3 pins -// These pins will also work for the 1.8" TFT shield -#define TFT_CS 10 -#define TFT_RST 9 // you can also connect this to the Arduino reset - // in which case, set this #define pin to 0! -#define TFT_DC 8 - -// Option 1 (recommended): must use the hardware SPI pins -// (for UNO thats sclk = 13 and sid = 11) and pin 10 must be -// an output. This is much faster - also required if you want -// to use the microSD card (see the image drawing example) -Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); - -// Option 2: use any pins but a little slower! -#define TFT_SCLK 13 // set these to be whatever pins you like! -#define TFT_MOSI 11 // set these to be whatever pins you like! -//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); - -void setup(void) { - Serial.begin(9600); - Serial.print("Hello! Adafruit ST7735 rotation test"); - - // Use this initializer if you're using a 1.8" TFT - tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab - - // Use this initializer (uncomment) if you're using a 1.44" TFT - //tft.initR(INITR_144GREENTAB); // initialize a ST7735S chip, black tab - - Serial.println("init"); - - tft.setTextWrap(false); // Allow text to run off right edge - tft.fillScreen(ST7735_BLACK); - - Serial.println("This is a test of the rotation capabilities of the TFT library!"); - Serial.println("Press (or type a character) to advance"); -} - -void loop(void) { - rotateLine(); - rotateText(); - rotatePixel(); - rotateFastline(); - rotateDrawrect(); - rotateFillrect(); - rotateDrawcircle(); - rotateFillcircle(); - rotateTriangle(); - rotateFillTriangle(); - rotateRoundRect(); - rotateFillRoundRect(); - rotateChar(); - rotateString(); -} - -void rotateText() { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.setCursor(0, 30); - tft.setTextColor(ST7735_RED); - tft.setTextSize(1); - tft.println("Hello World!"); - tft.setTextColor(ST7735_YELLOW); - tft.setTextSize(2); - tft.println("Hello World!"); - tft.setTextColor(ST7735_GREEN); - tft.setTextSize(3); - tft.println("Hello World!"); - tft.setTextColor(ST7735_BLUE); - tft.setTextSize(4); - tft.print(1234.567); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateFillcircle(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.fillCircle(10, 30, 10, ST7735_YELLOW); - - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateDrawcircle(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawCircle(10, 30, 10, ST7735_YELLOW); - - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateFillrect(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.fillRect(10, 20, 10, 20, ST7735_GREEN); - - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateDrawrect(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawRect(10, 20, 10, 20, ST7735_GREEN); - - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateFastline(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawFastHLine(0, 20, tft.width(), ST7735_RED); - tft.drawFastVLine(20, 0, tft.height(), ST7735_BLUE); - - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateLine(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawLine(tft.width()/2, tft.height()/2, 0, 0, ST7735_RED); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotatePixel(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawPixel(10,20, ST7735_WHITE); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateTriangle(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawTriangle(20, 10, 10, 30, 30, 30, ST7735_GREEN); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateFillTriangle(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.fillTriangle(20, 10, 10, 30, 30, 30, ST7735_RED); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateRoundRect(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawRoundRect(20, 10, 25, 15, 5, ST7735_BLUE); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateFillRoundRect(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.fillRoundRect(20, 10, 25, 15, 5, ST7735_CYAN); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateChar(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.drawChar(25, 15, 'A', ST7735_WHITE, ST7735_WHITE, 1); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - -void rotateString(void) { - for (uint8_t i=0; i<4; i++) { - tft.fillScreen(ST7735_BLACK); - Serial.println(tft.getRotation(), DEC); - - tft.setCursor(8, 25); - tft.setTextSize(1); - tft.setTextColor(ST7735_WHITE); - tft.print("Adafruit Industries"); - while (!Serial.available()); - Serial.read(); Serial.read(); Serial.read(); - - tft.setRotation(tft.getRotation()+1); - } -} - diff --git a/Sming/Libraries/Adafruit_ST7735/examples/shieldtest/shieldtest.ino b/Sming/Libraries/Adafruit_ST7735/examples/shieldtest/shieldtest.ino deleted file mode 100644 index d88dbc6f21..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/examples/shieldtest/shieldtest.ino +++ /dev/null @@ -1,256 +0,0 @@ -/*************************************************** - This is an example sketch for the Adafruit 1.8" TFT shield with joystick - ----> http://www.adafruit.com/products/802 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 pins are required to - interface - One pin is also needed for the joystick, we use analog 3 - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#include -#include -#include -#include - -#if defined(__SAM3X8E__) - #undef __FlashStringHelper::F(string_literal) - #define F(string_literal) string_literal -#endif - -// TFT display and SD card will share the hardware SPI interface. -// Hardware SPI pins are specific to the Arduino board type and -// cannot be remapped to alternate pins. For Arduino Uno, -// Duemilanove, etc., pin 11 = MOSI, pin 12 = MISO, pin 13 = SCK. -#define SD_CS 4 // Chip select line for SD card -#define TFT_CS 10 // Chip select line for TFT display -#define TFT_DC 8 // Data/command line for TFT -#define TFT_RST -1 // Reset line for TFT (or connect to +5V) - -Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); - -#define BUTTON_NONE 0 -#define BUTTON_DOWN 1 -#define BUTTON_RIGHT 2 -#define BUTTON_SELECT 3 -#define BUTTON_UP 4 -#define BUTTON_LEFT 5 - -void setup(void) { - Serial.begin(9600); - - // Initialize 1.8" TFT - tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab - - Serial.println("OK!"); - tft.fillScreen(ST7735_BLACK); -} - - -uint8_t readButton(void) { - float a = analogRead(3); - - a *= 5.0; - a /= 1024.0; - - Serial.print("Button read analog = "); - Serial.println(a); - if (a < 0.2) return BUTTON_DOWN; - if (a < 1.0) return BUTTON_RIGHT; - if (a < 1.5) return BUTTON_SELECT; - if (a < 2.0) return BUTTON_UP; - if (a < 3.2) return BUTTON_LEFT; - else return BUTTON_NONE; -} - -uint8_t buttonhistory = 0; - -void loop() { - uint8_t b = readButton(); - tft.setTextSize(3); - if (b == BUTTON_DOWN) { - tft.setTextColor(ST7735_RED); - tft.setCursor(0, 10); - tft.print("Down "); - buttonhistory |= 1; - } - if (b == BUTTON_LEFT) { - tft.setTextColor(ST7735_YELLOW); - tft.setCursor(0, 35); - tft.print("Left "); - buttonhistory |= 2; - } - if (b == BUTTON_UP) { - tft.setTextColor(ST7735_GREEN); - tft.setCursor(0, 60); - tft.print("Up"); - buttonhistory |= 4; - } - if (b == BUTTON_RIGHT) { - tft.setTextColor(ST7735_BLUE); - tft.setCursor(0, 85); - tft.print("Right"); - buttonhistory |= 8; - } - if ((b == BUTTON_SELECT) && (buttonhistory == 0xF)) { - tft.setTextColor(ST7735_MAGENTA); - tft.setCursor(0, 110); - tft.print("SELECT"); - buttonhistory |= 8; - delay(2000); - Serial.print("Initializing SD card..."); - if (!SD.begin(SD_CS)) { - Serial.println("failed!"); - return; - } - bmpDraw("parrot.bmp", 0, 0); - while (1); - } - delay(100); -} - -// This function opens a Windows Bitmap (BMP) file and -// displays it at the given coordinates. It's sped up -// by reading many pixels worth of data at a time -// (rather than pixel by pixel). Increasing the buffer -// size takes more of the Arduino's precious RAM but -// makes loading a little faster. 20 pixels seems a -// good balance. - -#define BUFFPIXEL 20 - -void bmpDraw(char *filename, uint8_t x, uint8_t y) { - - File bmpFile; - int bmpWidth, bmpHeight; // W+H in pixels - uint8_t bmpDepth; // Bit depth (currently must be 24) - uint32_t bmpImageoffset; // Start of image data in file - uint32_t rowSize; // Not always = bmpWidth; may have padding - uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) - uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer - boolean goodBmp = false; // Set to true on valid header parse - boolean flip = true; // BMP is stored bottom-to-top - int w, h, row, col; - uint8_t r, g, b; - uint32_t pos = 0, startTime = millis(); - - if((x >= tft.width()) || (y >= tft.height())) return; - - Serial.println(); - Serial.print("Loading image '"); - Serial.print(filename); - Serial.println('\''); - - // Open requested file on SD card - if ((bmpFile = SD.open(filename)) == NULL) { - Serial.print("File not found"); - return; - } - - // Parse BMP header - if(read16(bmpFile) == 0x4D42) { // BMP signature - Serial.print("File size: "); Serial.println(read32(bmpFile)); - (void)read32(bmpFile); // Read & ignore creator bytes - bmpImageoffset = read32(bmpFile); // Start of image data - Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC); - // Read DIB header - Serial.print("Header size: "); Serial.println(read32(bmpFile)); - bmpWidth = read32(bmpFile); - bmpHeight = read32(bmpFile); - if(read16(bmpFile) == 1) { // # planes -- must be '1' - bmpDepth = read16(bmpFile); // bits per pixel - Serial.print("Bit Depth: "); Serial.println(bmpDepth); - if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed - - goodBmp = true; // Supported BMP format -- proceed! - Serial.print("Image size: "); - Serial.print(bmpWidth); - Serial.print('x'); - Serial.println(bmpHeight); - - // BMP rows are padded (if needed) to 4-byte boundary - rowSize = (bmpWidth * 3 + 3) & ~3; - - // If bmpHeight is negative, image is in top-down order. - // This is not canon but has been observed in the wild. - if(bmpHeight < 0) { - bmpHeight = -bmpHeight; - flip = false; - } - - // Crop area to be loaded - w = bmpWidth; - h = bmpHeight; - if((x+w-1) >= tft.width()) w = tft.width() - x; - if((y+h-1) >= tft.height()) h = tft.height() - y; - - // Set TFT address window to clipped image bounds - tft.setAddrWindow(x, y, x+w-1, y+h-1); - - for (row=0; row= sizeof(sdbuffer)) { // Indeed - bmpFile.read(sdbuffer, sizeof(sdbuffer)); - buffidx = 0; // Set index to beginning - } - - // Convert pixel from BMP to TFT format, push to display - b = sdbuffer[buffidx++]; - g = sdbuffer[buffidx++]; - r = sdbuffer[buffidx++]; - tft.pushColor(tft.Color565(r,g,b)); - } // end pixel - } // end scanline - Serial.print("Loaded in "); - Serial.print(millis() - startTime); - Serial.println(" ms"); - } // end goodBmp - } - } - - bmpFile.close(); - if(!goodBmp) Serial.println("BMP format not recognized."); -} - -// These read 16- and 32-bit types from the SD card file. -// BMP data is stored little-endian, Arduino is little-endian too. -// May need to reverse subscript order if porting elsewhere. - -uint16_t read16(File f) { - uint16_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); // MSB - return result; -} - -uint32_t read32(File f) { - uint32_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); - ((uint8_t *)&result)[2] = f.read(); - ((uint8_t *)&result)[3] = f.read(); // MSB - return result; -} diff --git a/Sming/Libraries/Adafruit_ST7735/examples/soft_spitftbitmap/soft_spitftbitmap.ino b/Sming/Libraries/Adafruit_ST7735/examples/soft_spitftbitmap/soft_spitftbitmap.ino deleted file mode 100644 index 89eb2e3b7e..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/examples/soft_spitftbitmap/soft_spitftbitmap.ino +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************** - This is an example sketch for the Adafruit 1.8" SPI display. - This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 - as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#include // Core graphics library -#include // Hardware-specific library -#include -#include - -#if defined(__SAM3X8E__) - #undef __FlashStringHelper::F(string_literal) - #define F(string_literal) string_literal -#endif - -// TFT display and SD card will share the hardware SPI interface. -// Hardware SPI pins are specific to the Arduino board type and -// cannot be remapped to alternate pins. For Arduino Uno, -// Duemilanove, etc., pin 11 = MOSI, pin 12 = MISO, pin 13 = SCK. -#define SPI_SCK 13 -#define SPI_DI 12 -#define SPI_DO 11 - -#define SD_CS 4 // Chip select line for SD card -//#define TFT_CS 10 // Chip select line for TFT display -//#define TFT_DC 9 // Data/command line for TFT -//#define TFT_RST 8 // Reset line for TFT (or connect to +5V) - -//Use these pins for the shield! -#define TFT_CS 10 -#define TFT_DC 8 -#define TFT_RST 0 // you can also connect this to the Arduino reset - -Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, SPI_DO, SPI_SCK, TFT_RST); - -void setup(void) { - Serial.begin(9600); - - // Our supplier changed the 1.8" display slightly after Jan 10, 2012 - // so that the alignment of the TFT had to be shifted by a few pixels - // this just means the init code is slightly different. Check the - // color of the tab to see which init code to try. If the display is - // cut off or has extra 'random' pixels on the top & left, try the - // other option! - // If you are seeing red and green color inversion, use Black Tab - - // If your TFT's plastic wrap has a Black Tab, use the following: - tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab - // If your TFT's plastic wrap has a Red Tab, use the following: - //tft.initR(INITR_REDTAB); // initialize a ST7735R chip, red tab - // If your TFT's plastic wrap has a Green Tab, use the following: - //tft.initR(INITR_GREENTAB); // initialize a ST7735R chip, green tab - - Serial.print("Initializing SD card..."); - if (!SD.begin(SD_CS, SPI_DO, SPI_DI, SPI_SCK)) { - Serial.println("failed!"); - return; - } - Serial.println("OK!"); - - bmpDraw("parrot.bmp", 0, 0); -} - -void loop() { -} - -// This function opens a Windows Bitmap (BMP) file and -// displays it at the given coordinates. It's sped up -// by reading many pixels worth of data at a time -// (rather than pixel by pixel). Increasing the buffer -// size takes more of the Arduino's precious RAM but -// makes loading a little faster. 20 pixels seems a -// good balance. - -#define BUFFPIXEL 20 - -void bmpDraw(char *filename, uint8_t x, uint8_t y) { - - File bmpFile; - int bmpWidth, bmpHeight; // W+H in pixels - uint8_t bmpDepth; // Bit depth (currently must be 24) - uint32_t bmpImageoffset; // Start of image data in file - uint32_t rowSize; // Not always = bmpWidth; may have padding - uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) - uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer - boolean goodBmp = false; // Set to true on valid header parse - boolean flip = true; // BMP is stored bottom-to-top - int w, h, row, col; - uint8_t r, g, b; - uint32_t pos = 0, startTime = millis(); - - if((x >= tft.width()) || (y >= tft.height())) return; - - Serial.println(); - Serial.print("Loading image '"); - Serial.print(filename); - Serial.println('\''); - - // Open requested file on SD card - if ((bmpFile = SD.open(filename)) == NULL) { - Serial.print("File not found"); - return; - } - - // Parse BMP header - if(read16(bmpFile) == 0x4D42) { // BMP signature - Serial.print("File size: "); Serial.println(read32(bmpFile)); - (void)read32(bmpFile); // Read & ignore creator bytes - bmpImageoffset = read32(bmpFile); // Start of image data - Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC); - // Read DIB header - Serial.print("Header size: "); Serial.println(read32(bmpFile)); - bmpWidth = read32(bmpFile); - bmpHeight = read32(bmpFile); - if(read16(bmpFile) == 1) { // # planes -- must be '1' - bmpDepth = read16(bmpFile); // bits per pixel - Serial.print("Bit Depth: "); Serial.println(bmpDepth); - if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed - - goodBmp = true; // Supported BMP format -- proceed! - Serial.print("Image size: "); - Serial.print(bmpWidth); - Serial.print('x'); - Serial.println(bmpHeight); - - // BMP rows are padded (if needed) to 4-byte boundary - rowSize = (bmpWidth * 3 + 3) & ~3; - - // If bmpHeight is negative, image is in top-down order. - // This is not canon but has been observed in the wild. - if(bmpHeight < 0) { - bmpHeight = -bmpHeight; - flip = false; - } - - // Crop area to be loaded - w = bmpWidth; - h = bmpHeight; - if((x+w-1) >= tft.width()) w = tft.width() - x; - if((y+h-1) >= tft.height()) h = tft.height() - y; - - // Set TFT address window to clipped image bounds - tft.setAddrWindow(x, y, x+w-1, y+h-1); - - for (row=0; row= sizeof(sdbuffer)) { // Indeed - bmpFile.read(sdbuffer, sizeof(sdbuffer)); - buffidx = 0; // Set index to beginning - } - - // Convert pixel from BMP to TFT format, push to display - b = sdbuffer[buffidx++]; - g = sdbuffer[buffidx++]; - r = sdbuffer[buffidx++]; - tft.pushColor(tft.Color565(r,g,b)); - } // end pixel - } // end scanline - Serial.print("Loaded in "); - Serial.print(millis() - startTime); - Serial.println(" ms"); - } // end goodBmp - } - } - - bmpFile.close(); - if(!goodBmp) Serial.println("BMP format not recognized."); -} - -// These read 16- and 32-bit types from the SD card file. -// BMP data is stored little-endian, Arduino is little-endian too. -// May need to reverse subscript order if porting elsewhere. - -uint16_t read16(File f) { - uint16_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); // MSB - return result; -} - -uint32_t read32(File f) { - uint32_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); - ((uint8_t *)&result)[2] = f.read(); - ((uint8_t *)&result)[3] = f.read(); // MSB - return result; -} - diff --git a/Sming/Libraries/Adafruit_ST7735/examples/spitftbitmap/spitftbitmap.ino b/Sming/Libraries/Adafruit_ST7735/examples/spitftbitmap/spitftbitmap.ino deleted file mode 100644 index 760a206a74..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/examples/spitftbitmap/spitftbitmap.ino +++ /dev/null @@ -1,215 +0,0 @@ -/*************************************************** - This is a library for the Adafruit 1.8" SPI display. - -This library works with the Adafruit 1.8" TFT Breakout w/SD card - ----> http://www.adafruit.com/products/358 -The 1.8" TFT shield - ----> https://www.adafruit.com/product/802 -The 1.44" TFT breakout - ----> https://www.adafruit.com/product/2088 -as well as Adafruit raw 1.8" TFT display - ----> http://www.adafruit.com/products/618 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#include // Core graphics library -#include // Hardware-specific library -#include -#include - -// TFT display and SD card will share the hardware SPI interface. -// Hardware SPI pins are specific to the Arduino board type and -// cannot be remapped to alternate pins. For Arduino Uno, -// Duemilanove, etc., pin 11 = MOSI, pin 12 = MISO, pin 13 = SCK. -#define TFT_CS 10 // Chip select line for TFT display -#define TFT_RST 9 // Reset line for TFT (or see below...) -#define TFT_DC 8 // Data/command line for TFT - -#define SD_CS 4 // Chip select line for SD card - -//Use this reset pin for the shield! -//#define TFT_RST 0 // you can also connect this to the Arduino reset! - -Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); - -void setup(void) { - Serial.begin(9600); - - // Use this initializer if you're using a 1.8" TFT - tft.initR(INITR_BLACKTAB); - - // Use this initializer (uncomment) if you're using a 1.44" TFT - //tft.initR(INITR_144GREENTAB); - - Serial.print("Initializing SD card..."); - if (!SD.begin(SD_CS)) { - Serial.println("failed!"); - return; - } - Serial.println("OK!"); - - // change the name here! - bmpDraw("parrot.bmp", 0, 0); - // wait 5 seconds - delay(5000); -} - -void loop() { -// uncomment these lines to draw bitmaps in different locations/rotations! -/* - tft.fillScreen(ST7735_BLACK); // Clear display - for(uint8_t i=0; i<4; i++) // Draw 4 parrots - bmpDraw("parrot.bmp", tft.width() / 4 * i, tft.height() / 4 * i); - delay(1000); - tft.setRotation(tft.getRotation() + 1); // Inc rotation 90 degrees -*/ -} - -// This function opens a Windows Bitmap (BMP) file and -// displays it at the given coordinates. It's sped up -// by reading many pixels worth of data at a time -// (rather than pixel by pixel). Increasing the buffer -// size takes more of the Arduino's precious RAM but -// makes loading a little faster. 20 pixels seems a -// good balance. - -#define BUFFPIXEL 20 - -void bmpDraw(char *filename, uint8_t x, uint8_t y) { - - File bmpFile; - int bmpWidth, bmpHeight; // W+H in pixels - uint8_t bmpDepth; // Bit depth (currently must be 24) - uint32_t bmpImageoffset; // Start of image data in file - uint32_t rowSize; // Not always = bmpWidth; may have padding - uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) - uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer - boolean goodBmp = false; // Set to true on valid header parse - boolean flip = true; // BMP is stored bottom-to-top - int w, h, row, col; - uint8_t r, g, b; - uint32_t pos = 0, startTime = millis(); - - if((x >= tft.width()) || (y >= tft.height())) return; - - Serial.println(); - Serial.print("Loading image '"); - Serial.print(filename); - Serial.println('\''); - - // Open requested file on SD card - if ((bmpFile = SD.open(filename)) == NULL) { - Serial.print("File not found"); - return; - } - - // Parse BMP header - if(read16(bmpFile) == 0x4D42) { // BMP signature - Serial.print("File size: "); Serial.println(read32(bmpFile)); - (void)read32(bmpFile); // Read & ignore creator bytes - bmpImageoffset = read32(bmpFile); // Start of image data - Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC); - // Read DIB header - Serial.print("Header size: "); Serial.println(read32(bmpFile)); - bmpWidth = read32(bmpFile); - bmpHeight = read32(bmpFile); - if(read16(bmpFile) == 1) { // # planes -- must be '1' - bmpDepth = read16(bmpFile); // bits per pixel - Serial.print("Bit Depth: "); Serial.println(bmpDepth); - if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed - - goodBmp = true; // Supported BMP format -- proceed! - Serial.print("Image size: "); - Serial.print(bmpWidth); - Serial.print('x'); - Serial.println(bmpHeight); - - // BMP rows are padded (if needed) to 4-byte boundary - rowSize = (bmpWidth * 3 + 3) & ~3; - - // If bmpHeight is negative, image is in top-down order. - // This is not canon but has been observed in the wild. - if(bmpHeight < 0) { - bmpHeight = -bmpHeight; - flip = false; - } - - // Crop area to be loaded - w = bmpWidth; - h = bmpHeight; - if((x+w-1) >= tft.width()) w = tft.width() - x; - if((y+h-1) >= tft.height()) h = tft.height() - y; - - // Set TFT address window to clipped image bounds - tft.setAddrWindow(x, y, x+w-1, y+h-1); - - for (row=0; row= sizeof(sdbuffer)) { // Indeed - bmpFile.read(sdbuffer, sizeof(sdbuffer)); - buffidx = 0; // Set index to beginning - } - - // Convert pixel from BMP to TFT format, push to display - b = sdbuffer[buffidx++]; - g = sdbuffer[buffidx++]; - r = sdbuffer[buffidx++]; - tft.pushColor(tft.Color565(r,g,b)); - } // end pixel - } // end scanline - Serial.print("Loaded in "); - Serial.print(millis() - startTime); - Serial.println(" ms"); - } // end goodBmp - } - } - - bmpFile.close(); - if(!goodBmp) Serial.println("BMP format not recognized."); -} - -// These read 16- and 32-bit types from the SD card file. -// BMP data is stored little-endian, Arduino is little-endian too. -// May need to reverse subscript order if porting elsewhere. - -uint16_t read16(File f) { - uint16_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); // MSB - return result; -} - -uint32_t read32(File f) { - uint32_t result; - ((uint8_t *)&result)[0] = f.read(); // LSB - ((uint8_t *)&result)[1] = f.read(); - ((uint8_t *)&result)[2] = f.read(); - ((uint8_t *)&result)[3] = f.read(); // MSB - return result; -} \ No newline at end of file diff --git a/Sming/Libraries/Adafruit_ST7735/library.properties b/Sming/Libraries/Adafruit_ST7735/library.properties deleted file mode 100644 index a8d97af887..0000000000 --- a/Sming/Libraries/Adafruit_ST7735/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=Adafruit ST7735 Library -version=1.0.4 -author=Adafruit -maintainer=Adafruit -sentence=This is a library for the Adafruit 1.8" SPI displays. -paragraph=This is a library for the Adafruit 1.8" SPI displays. -category=Display -url=https://github.com/adafruit/Adafruit-ST7735-Library -architectures=* diff --git a/Sming/Libraries/CapacitiveSensor/CapacitiveSensor.h b/Sming/Libraries/CapacitiveSensor/CapacitiveSensor.h index e9a84802ff..b19a7b62c0 100644 --- a/Sming/Libraries/CapacitiveSensor/CapacitiveSensor.h +++ b/Sming/Libraries/CapacitiveSensor/CapacitiveSensor.h @@ -24,7 +24,7 @@ #define PIN_TO_BASEREG(pin) (portOutputRegister(digitalPinToPort(pin))) #define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define IO_REG_TYPE uint8_t +#define IO_REG_TYPE GPIO_REG_TYPE #define IO_REG_ASM #define DIRECT_READ(base, mask) (((*((base)+GPIO_IN_ADDRESS)) & (mask)) ? 1 : 0) #define DIRECT_MODE_INPUT(base, mask) ((*((base)+GPIO_ENABLE_ADDRESS)) &= ~(mask)) diff --git a/Sming/Libraries/TFT_ILI9163C/TFT_ILI9163C.h b/Sming/Libraries/TFT_ILI9163C/TFT_ILI9163C.h index fc133ec401..036f530eee 100644 --- a/Sming/Libraries/TFT_ILI9163C/TFT_ILI9163C.h +++ b/Sming/Libraries/TFT_ILI9163C/TFT_ILI9163C.h @@ -295,9 +295,9 @@ class TFT_ILI9163C : public Adafruit_GFX { #if defined(__ESP8266_EX__) void spiwrite(uint8_t); - volatile uint8_t *csport, *rsport; + volatile GPIO_REG_TYPE *csport, *rsport; uint8_t _cs,_rs,_sid,_sclk,_rst; - uint8_t cspinmask, rspinmask; + GPIO_REG_TYPE cspinmask, rspinmask; #endif // #ifdef __ESP8266_EX__ }; #endif diff --git a/Sming/Makefile b/Sming/Makefile index 9119cfe618..1cfb9db6d2 100644 --- a/Sming/Makefile +++ b/Sming/Makefile @@ -148,9 +148,10 @@ endif # name for the target project TARGET = app - CUSTOM_TARGETS ?= +ARDUINO_LIBRARIES = $(shell git submodule status Libraries | cut -c2- | cut -f2 -d ' ' | sed -r 's/Libraries\/(.*?)/Libraries\/\1\/library.properties/g' ) + # which modules (subdirectories) of the project to include in compiling MODULES = system system/helpers Wiring appinit \ $(sort $(dir $(wildcard SmingCore/*/ SmingCore/*/*/ SmingCore/*/*/*/))) \ @@ -227,7 +228,8 @@ endif MFORCE32 := $(shell $(CC) --help=target | grep mforce-l32) # compiler flags using during compilation of source files. Add '-pg' for debugging -CFLAGS = -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections -D__ets__ -DICACHE_FLASH -DARDUINO=106 -DCOM_SPEED_SERIAL=$(COM_SPEED_SERIAL) -DENABLE_CMD_EXECUTOR=$(ENABLE_CMD_EXECUTOR) +CFLAGS = -Wpointer-arith -Wundef -Werror -Wl,-EL -nostdlib -mlongcalls -mtext-section-literals -finline-functions -fdata-sections -ffunction-sections \ + -D__ets__ -DICACHE_FLASH -DARDUINO=106 -DCOM_SPEED_SERIAL=$(COM_SPEED_SERIAL) -DENABLE_CMD_EXECUTOR=$(ENABLE_CMD_EXECUTOR) -DESP8266=1 ifeq ($(SMING_RELEASE),1) # See: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html # for full list of optimization options @@ -402,7 +404,7 @@ endif $(Q) cp -r $(APP_AR) $(USER_LIBDIR)/$(LIBSMING).a $(vecho) "Done" -checkdirs: $(THIRD_PARTY_DATA) reload $(BUILD_DIR) $(FW_BASE) $(CUSTOM_TARGETS) +checkdirs: $(ARDUINO_LIBRARIES) $(THIRD_PARTY_DATA) reload $(BUILD_DIR) $(FW_BASE) $(CUSTOM_TARGETS) $(BUILD_DIR): $(Q) mkdir -p $@ @@ -462,6 +464,16 @@ third-party/%: # For now we solve this by "reloading" the makefile after fetching a module. RELOAD_MKFILE=1 +Libraries/%: + $(vecho) "Fetching Arduino Library $(dir $@) ..." + $(Q) $(GIT) submodule update --init --recursive $(dir $@) + $(Q) touch $(patsubst Libraries/%/,Libraries/.patches/%.patch, $(dir $@)) + $(Q) -cd $(dir $@); $(GIT) apply -v $(patsubst Libraries/%/,$(SMING_HOME)/Libraries/.patches/%.patch, $(dir $@)) --ignore-whitespace --whitespace=nowarn +# if the new submodule brings source code files that need to be compiled inside Sming +# then we need somehow to be able to "see" these new files. +# For now we solve this by "reloading" the makefile after fetching a module. + RELOAD_MKFILE=1 + reload: $(Q) if [ $(RELOAD_MKFILE) -eq 1 ]; then \ $(MAKE) -C $(SMING_HOME) $(MAKECMDGOALS) RELOAD_MKFILE=0; \ @@ -482,8 +494,12 @@ third-party-clean: rm -rf third-party/$$dir; \ done $(Q) $(GIT) checkout third-party + +libraries-clean: + $(Q) rm -rf Libraries + $(Q) $(GIT) checkout Libraries -dist-clean: clean samples-clean third-party-clean +dist-clean: clean samples-clean third-party-clean libraries-clean $(Q) for file in $(shell ls $(USER_LIBDIR)/lib*.a ); do \ rm $$file; \ done diff --git a/Sming/Makefile-project.mk b/Sming/Makefile-project.mk index b75f059596..52090080b9 100644 --- a/Sming/Makefile-project.mk +++ b/Sming/Makefile-project.mk @@ -178,7 +178,10 @@ ifeq ($(ENABLE_CUSTOM_LWIP), 1) LWIP_INCDIR = $(SMING_HOME)/third-party/esp-open-lwip/include endif -EXTRA_INCDIR += $(SMING_HOME)/include $(SMING_HOME)/ $(LWIP_INCDIR) $(SMING_HOME)/system/include $(SMING_HOME)/Wiring $(SMING_HOME)/Libraries $(SMING_HOME)/SmingCore $(SMING_HOME)/Services/SpifFS $(SDK_BASE)/../include $(THIRD_PARTY_DIR)/rboot $(THIRD_PARTY_DIR)/rboot/appcode $(THIRD_PARTY_DIR)/spiffs/src +EXTRA_INCDIR += $(SMING_HOME)/include $(SMING_HOME)/ $(LWIP_INCDIR) $(SMING_HOME)/system/include \ + $(SMING_HOME)/Wiring $(SMING_HOME)/Libraries $(SMING_HOME)/Libraries/Adafruit_GFX \ + $(SMING_HOME)/SmingCore $(SMING_HOME)/Services/SpifFS $(SDK_BASE)/../include \ + $(THIRD_PARTY_DIR)/rboot $(THIRD_PARTY_DIR)/rboot/appcode $(THIRD_PARTY_DIR)/spiffs/src ENABLE_CUSTOM_HEAP ?= 0 diff --git a/Sming/Makefile-rboot.mk b/Sming/Makefile-rboot.mk index df6b5d3552..32ab0599c3 100644 --- a/Sming/Makefile-rboot.mk +++ b/Sming/Makefile-rboot.mk @@ -186,7 +186,10 @@ ifeq ($(ENABLE_CUSTOM_LWIP), 1) LWIP_INCDIR = $(SMING_HOME)/third-party/esp-open-lwip/include endif -EXTRA_INCDIR += $(SMING_HOME)/include $(SMING_HOME)/ $(LWIP_INCDIR) $(SMING_HOME)/system/include $(SMING_HOME)/Wiring $(SMING_HOME)/Libraries $(SMING_HOME)/SmingCore $(SMING_HOME)/Services/SpifFS $(SDK_BASE)/../include $(THIRD_PARTY_DIR)/rboot $(THIRD_PARTY_DIR)/rboot/appcode $(THIRD_PARTY_DIR)/spiffs/src +EXTRA_INCDIR += $(SMING_HOME)/include $(SMING_HOME)/ $(LWIP_INCDIR) $(SMING_HOME)/system/include \ + $(SMING_HOME)/Wiring $(SMING_HOME)/Libraries $(SMING_HOME)/Libraries/Adafruit_GFX \ + $(SMING_HOME)/SmingCore $(SMING_HOME)/Services/SpifFS $(SDK_BASE)/../include \ + $(THIRD_PARTY_DIR)/rboot $(THIRD_PARTY_DIR)/rboot/appcode $(THIRD_PARTY_DIR)/spiffs/src USER_LIBDIR = $(SMING_HOME)/compiler/lib/ diff --git a/Sming/SmingCore/ArduinoCompat.cpp b/Sming/SmingCore/ArduinoCompat.cpp new file mode 100644 index 0000000000..9af706db18 --- /dev/null +++ b/Sming/SmingCore/ArduinoCompat.cpp @@ -0,0 +1,21 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Arduino Compatibility Layer + * + * @author: 2017 - Slavey Karadzhov + * + ****/ + +#include "ArduinoCompat.h" + +/** + * @brief This method just feeds the software watchdog. It does not really switch the programming context as yield in Arduino does. + */ +void yield() +{ + system_soft_wdt_feed(); +} diff --git a/Sming/SmingCore/ArduinoCompat.h b/Sming/SmingCore/ArduinoCompat.h new file mode 100644 index 0000000000..02ce660e25 --- /dev/null +++ b/Sming/SmingCore/ArduinoCompat.h @@ -0,0 +1,29 @@ +/**** + * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. + * Created 2015 by Skurydin Alexey + * http://github.com/anakod/Sming + * All files of the Sming Core are provided under the LGPL v3 license. + * + * Arduino Compatibility Layer + * + * @author: 2017 - Slavey Karadzhov + * + ****/ + +#ifndef SMINGCORE_ARDUINOCOMPAT_H_ +#define SMINGCORE_ARDUINOCOMPAT_H_ + +#include "SmingCore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void yield(); + +#ifdef __cplusplus +} +#endif + + +#endif /* SMINGCORE_ARDUINOCOMPAT_H_ */ diff --git a/Sming/SmingCore/pgmspace.h b/Sming/SmingCore/pgmspace.h new file mode 100644 index 0000000000..311e0cfd0e --- /dev/null +++ b/Sming/SmingCore/pgmspace.h @@ -0,0 +1,2 @@ +#include "SmingCore.h" +#include "../Wiring/FakePgmSpace.h" diff --git a/Sming/SmingCore/pins_arduino.h b/Sming/SmingCore/pins_arduino.h index d674601df7..a7a0e7a05a 100644 --- a/Sming/SmingCore/pins_arduino.h +++ b/Sming/SmingCore/pins_arduino.h @@ -10,6 +10,8 @@ #ifndef WIRING_PINS_ARDUINO_H_ #define WIRING_PINS_ARDUINO_H_ +#include "espinc/peri.h" + extern const unsigned int A0; // Single ESP8266EX analog input pin (TOUT) 10 bit, 0..1v #define NOT_A_PIN 0 @@ -20,23 +22,16 @@ extern const unsigned int A0; // Single ESP8266EX analog input pin (TOUT) 10 bit #define PB 2 #define PC 3 -#define GPIO_REG_TYPE uint8_t +#define GPIO_REG_TYPE uint32_t // We use maximum compatibility to standard Arduino logic. -// Conversion disabled for now -#define digitalPinToTimer(P) ( NOT_ON_TIMER ) - -#define digitalPinToPort(P) ( P < 0 ? NOT_A_PIN : ( (int)P < 8 ? PA : ( (int)P < 16 ? PB : ( (int)P == 16 ? PC : NOT_A_PIN ) ) ) ) -#define digitalPinToBitMask(P) ( (int)P < 8 ? _BV((int)P) : ( P < 16 ? _BV( (int)P-8 ) : 1) ) - -#define STD_GPIO_OUT (PERIPHS_GPIO_BASEADDR + GPIO_OUT_ADDRESS) -#define STD_GPIO_IN (PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS) -#define STD_GPIO_ENABLE (PERIPHS_GPIO_BASEADDR + GPIO_ENABLE_ADDRESS) - -#define portOutputRegister(P) ( ((volatile uint8_t*)(P != PC ? STD_GPIO_OUT : RTC_GPIO_OUT)) + ( ( ((int)P) == PB ) ? 1 : 0) ) -#define portInputRegister(P) ( ((volatile uint8_t*)(P != PC ? STD_GPIO_IN : RTC_GPIO_IN_DATA)) + ( ( ((int)P) == PB ) ? 1 : 0) ) -#define portModeRegister(P) ( ((volatile uint8_t*)(P != PC ? STD_GPIO_ENABLE : RTC_GPIO_ENABLE)) + ( ( ((int)P) == PB ) ? 1 : 0) ) // Stored bits: 0=In, 1=Out +#define digitalPinToPort(pin) (0) +#define digitalPinToBitMask(pin) (1UL << (pin)) +#define digitalPinToTimer(pin) (NOT_ON_TIMER) +#define portOutputRegister(port) ((volatile uint32_t*) &GPO) +#define portInputRegister(port) ((volatile uint32_t*) &GPI) +#define portModeRegister(port) ((volatile uint32_t*) &GPE) #endif /* WIRING_PINS_ARDUINO_H_ */ diff --git a/Sming/Wiring/Arduino.h b/Sming/Wiring/Arduino.h index 67443b59d4..efb7103798 100644 --- a/Sming/Wiring/Arduino.h +++ b/Sming/Wiring/Arduino.h @@ -6,6 +6,7 @@ #include "../include/user_config.h" #include "../Wiring/WiringFrameworkDependencies.h" #include "../SmingCore/SmingCore.h" +#include "../SmingCore/ArduinoCompat.h" #endif /* INCLUDE_ARDUINO_H_ */ From c381740da7b9d8e8ca90f1762be80c54bf178019 Mon Sep 17 00:00:00 2001 From: slaff Date: Sun, 15 Oct 2017 21:11:32 +0200 Subject: [PATCH 24/33] Http(Client|Server): moved code out of IRAM. No visual performance slow downs. Freed IRAM. (#1260) --- Sming/SmingCore/Network/Http/HttpConnection.h | 18 +++++++++--------- .../Network/Http/HttpServerConnection.h | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Sming/SmingCore/Network/Http/HttpConnection.h b/Sming/SmingCore/Network/Http/HttpConnection.h index 019f71ee74..10c950aa6d 100644 --- a/Sming/SmingCore/Network/Http/HttpConnection.h +++ b/Sming/SmingCore/Network/Http/HttpConnection.h @@ -85,19 +85,19 @@ class HttpConnection : protected TcpClient { void cleanup(); private: - static int IRAM_ATTR staticOnMessageBegin(http_parser* parser); + static int staticOnMessageBegin(http_parser* parser); #ifndef COMPACT_MODE - static int IRAM_ATTR staticOnStatus(http_parser *parser, const char *at, size_t length); + static int staticOnStatus(http_parser *parser, const char *at, size_t length); #endif - static int IRAM_ATTR staticOnHeadersComplete(http_parser* parser); - static int IRAM_ATTR staticOnHeaderField(http_parser *parser, const char *at, size_t length); - static int IRAM_ATTR staticOnHeaderValue(http_parser *parser, const char *at, size_t length); - static int IRAM_ATTR staticOnBody(http_parser *parser, const char *at, size_t length); + static int staticOnHeadersComplete(http_parser* parser); + static int staticOnHeaderField(http_parser *parser, const char *at, size_t length); + static int staticOnHeaderValue(http_parser *parser, const char *at, size_t length); + static int staticOnBody(http_parser *parser, const char *at, size_t length); #ifndef COMPACT_MODE - static int IRAM_ATTR staticOnChunkHeader(http_parser* parser); - static int IRAM_ATTR staticOnChunkComplete(http_parser* parser); + static int staticOnChunkHeader(http_parser* parser); + static int staticOnChunkComplete(http_parser* parser); #endif - static int IRAM_ATTR staticOnMessageComplete(http_parser* parser); + static int staticOnMessageComplete(http_parser* parser); void sendRequestHeaders(HttpRequest* request); bool sendRequestBody(HttpRequest* request); diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.h b/Sming/SmingCore/Network/Http/HttpServerConnection.h index e9f0818de2..534df786d5 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.h +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.h @@ -56,13 +56,13 @@ class HttpServerConnection: public TcpClient const char * getStatus(enum http_status s); private: - static int IRAM_ATTR staticOnMessageBegin(http_parser* parser); - static int IRAM_ATTR staticOnPath(http_parser *parser, const char *at, size_t length); - static int IRAM_ATTR staticOnHeadersComplete(http_parser* parser); - static int IRAM_ATTR staticOnHeaderField(http_parser *parser, const char *at, size_t length); - static int IRAM_ATTR staticOnHeaderValue(http_parser *parser, const char *at, size_t length); - static int IRAM_ATTR staticOnBody(http_parser *parser, const char *at, size_t length); - static int IRAM_ATTR staticOnMessageComplete(http_parser* parser); + static int staticOnMessageBegin(http_parser* parser); + static int staticOnPath(http_parser *parser, const char *at, size_t length); + static int staticOnHeadersComplete(http_parser* parser); + static int staticOnHeaderField(http_parser *parser, const char *at, size_t length); + static int staticOnHeaderValue(http_parser *parser, const char *at, size_t length); + static int staticOnBody(http_parser *parser, const char *at, size_t length); + static int staticOnMessageComplete(http_parser* parser); void sendResponseHeaders(HttpResponse* response); bool sendResponseBody(HttpResponse* response); From 6ac7c4ab57502a7d610f9e0aea4beb94ff192527 Mon Sep 17 00:00:00 2001 From: slaff Date: Mon, 16 Oct 2017 21:56:59 +0200 Subject: [PATCH 25/33] Allow also polling to trigger sending of http client data. (#1261) --- .../SmingCore/Network/Http/HttpConnection.cpp | 49 ++++++++++++------- Sming/SmingCore/Network/Http/HttpRequest.cpp | 2 +- Sming/SmingCore/Network/Http/HttpRequest.h | 2 +- Sming/SmingCore/Network/HttpServer.h | 11 ++++- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/Sming/SmingCore/Network/Http/HttpConnection.cpp b/Sming/SmingCore/Network/Http/HttpConnection.cpp index 403069b02b..4f02c837d8 100644 --- a/Sming/SmingCore/Network/Http/HttpConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpConnection.cpp @@ -24,7 +24,8 @@ bool HttpConnection::parserSettingsInitialized = false; http_parser_settings HttpConnection::parserSettings; -HttpConnection::HttpConnection(RequestQueue* queue): TcpClient(false), mode(eHCM_String) { +HttpConnection::HttpConnection(RequestQueue* queue): TcpClient(false), mode(eHCM_String) +{ this->waitingQueue = queue; http_parser_init(&parser, HTTP_RESPONSE); @@ -55,7 +56,8 @@ HttpConnection::HttpConnection(RequestQueue* queue): TcpClient(false), mode(eHCM } } -bool HttpConnection::connect(const String& host, int port, bool useSsl /* = false */, uint32_t sslOptions /* = 0 */) { +bool HttpConnection::connect(const String& host, int port, bool useSsl /* = false */, uint32_t sslOptions /* = 0 */) +{ debugf("HttpConnection::connect: TCP state: %d, isStarted: %d, isActive: %d", (tcp != NULL? tcp->state : -1), (int)(getConnectionState() != eTCS_Ready), (int)isActive()); @@ -76,7 +78,8 @@ bool HttpConnection::connect(const String& host, int port, bool useSsl /* = fals return TcpClient::connect(host, port, useSsl, sslOptions); } -bool HttpConnection::isActive() { +bool HttpConnection::isActive() +{ if(tcp == NULL) { return false; } @@ -278,7 +281,8 @@ int HttpConnection::staticOnHeadersComplete(http_parser* parser) } #ifndef COMPACT_MODE -int HttpConnection::staticOnStatus(http_parser *parser, const char *at, size_t length) { +int HttpConnection::staticOnStatus(http_parser *parser, const char *at, size_t length) +{ return 0; } #endif @@ -348,22 +352,21 @@ int HttpConnection::staticOnBody(http_parser *parser, const char *at, size_t len } #ifndef COMPACT_MODE -int HttpConnection::staticOnChunkHeader(http_parser* parser) { +int HttpConnection::staticOnChunkHeader(http_parser* parser) +{ debugf("On chunk header"); return 0; } -int HttpConnection::staticOnChunkComplete(http_parser* parser) { +int HttpConnection::staticOnChunkComplete(http_parser* parser) +{ debugf("On chunk complete"); return 0; } #endif -void HttpConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) { - - if(!(sourceEvent == eTCE_Connected || sourceEvent == eTCE_Sent)) { - return; - } +void HttpConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) +{ debugf("HttpConnection::onReadyToSendData: waitingQueue.count: %d", waitingQueue->count()); @@ -434,7 +437,8 @@ void HttpConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) { TcpClient::onReadyToSendData(sourceEvent); } -void HttpConnection::sendRequestHeaders(HttpRequest* request) { +void HttpConnection::sendRequestHeaders(HttpRequest* request) +{ sendString(http_method_str(request->method) + String(" ") + request->uri.getPathWithQuery() + " HTTP/1.1\r\nHost: " + request->uri.Host + "\r\n"); // TODO: represent the post params as stream ... @@ -469,7 +473,8 @@ void HttpConnection::sendRequestHeaders(HttpRequest* request) { sendString("\r\n"); } -bool HttpConnection::sendRequestBody(HttpRequest* request) { +bool HttpConnection::sendRequestBody(HttpRequest* request) +{ if(state == eHCS_StartBody) { state = eHCS_SendingBody; // if there is input raw data -> send it @@ -520,11 +525,13 @@ bool HttpConnection::sendRequestBody(HttpRequest* request) { return true; } -HttpRequest* HttpConnection::getRequest() { +HttpRequest* HttpConnection::getRequest() +{ return incomingRequest; } -HttpResponse* HttpConnection::getResponse() { +HttpResponse* HttpConnection::getResponse() +{ HttpResponse* response = new HttpResponse(); response->code = code; response->headers = responseHeaders; @@ -548,7 +555,8 @@ HttpResponse* HttpConnection::getResponse() { // end of public methods for HttpConnection -err_t HttpConnection::onReceive(pbuf *buf) { +err_t HttpConnection::onReceive(pbuf *buf) +{ if (buf == NULL) { // Disconnected, close it @@ -584,12 +592,14 @@ err_t HttpConnection::onReceive(pbuf *buf) { return ERR_OK; } -void HttpConnection::onError(err_t err) { +void HttpConnection::onError(err_t err) +{ cleanup(); TcpClient::onError(err); } -void HttpConnection::cleanup() { +void HttpConnection::cleanup() +{ // TODO: clean the current request reset(); @@ -601,7 +611,8 @@ void HttpConnection::cleanup() { } } -HttpConnection::~HttpConnection() { +HttpConnection::~HttpConnection() +{ cleanup(); } diff --git a/Sming/SmingCore/Network/Http/HttpRequest.cpp b/Sming/SmingCore/Network/Http/HttpRequest.cpp index c11de48432..722609b35b 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.cpp +++ b/Sming/SmingCore/Network/Http/HttpRequest.cpp @@ -56,7 +56,7 @@ HttpRequest::~HttpRequest() { stream = NULL; } -HttpRequest* HttpRequest::setURL(URL uri) { +HttpRequest* HttpRequest::setURL(const URL& uri) { this->uri = uri; return this; } diff --git a/Sming/SmingCore/Network/Http/HttpRequest.h b/Sming/SmingCore/Network/Http/HttpRequest.h index 59de80a991..1156fb30d5 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.h +++ b/Sming/SmingCore/Network/Http/HttpRequest.h @@ -41,7 +41,7 @@ class HttpRequest { HttpRequest& operator = (const HttpRequest& rhs); ~HttpRequest(); - HttpRequest* setURL(URL uri); + HttpRequest* setURL(const URL& uri); HttpRequest* setMethod(const HttpMethod method); diff --git a/Sming/SmingCore/Network/HttpServer.h b/Sming/SmingCore/Network/HttpServer.h index dfb68a555a..02f6c00c4a 100644 --- a/Sming/SmingCore/Network/HttpServer.h +++ b/Sming/SmingCore/Network/HttpServer.h @@ -49,11 +49,20 @@ class HttpServer: public TcpServer HttpServer(HttpServerSettings settings); virtual ~HttpServer(); - /* + /** * @brief Allows changing the server configuration */ void configure(HttpServerSettings settings); + /** + * @briefs Allows content-type specific parsing of the body based on content-type. + * + * @param const String& contentType. Can be full content-type like 'application/json', or 'application/*' or '*'. + * If there is exact match for the content-type wildcard content-types will not be used. + * There can be only one catch-all '*' body parser and that will be the last registered + * + * @param HttpBodyParserDelegate parser + */ void setBodyParser(const String& contentType, HttpBodyParserDelegate parser); /** From 77cc289a5a7e4d33ccca073c0dd6f9970e9aec84 Mon Sep 17 00:00:00 2001 From: slaff Date: Wed, 18 Oct 2017 10:20:07 +0200 Subject: [PATCH 26/33] HttpServer:WebSocket support: (#1265) - Fixes #1262 - Fixed memory leak(s). Core: Added "endless" memory stream. --- Sming/SmingCore/DataSourceStream.cpp | 62 +++++++++++++++++++ Sming/SmingCore/DataSourceStream.h | 38 +++++++++++- Sming/SmingCore/Network/Http/HttpResource.h | 4 ++ .../Network/Http/HttpServerConnection.cpp | 3 + .../Http/Websocket/WebSocketConnection.cpp | 25 ++++---- .../Http/Websocket/WebSocketConnection.h | 6 +- .../Http/Websocket/WebsocketResource.cpp | 8 ++- .../Http/Websocket/WebsocketResource.h | 2 + 8 files changed, 130 insertions(+), 18 deletions(-) diff --git a/Sming/SmingCore/DataSourceStream.cpp b/Sming/SmingCore/DataSourceStream.cpp index 070e0bb051..7cc53ceef7 100644 --- a/Sming/SmingCore/DataSourceStream.cpp +++ b/Sming/SmingCore/DataSourceStream.cpp @@ -133,6 +133,9 @@ uint16_t FileStream::readMemoryBlock(char* data, int bufSize) int len = min(bufSize, size - pos); int available = fileRead(handle, data, len); fileSeek(handle, pos, eSO_FileStart); // Don't move cursor now (waiting seek) + if(available < 0) { + available = 0; + } return available; } @@ -359,3 +362,62 @@ int JsonObjectStream::length() return rootNode.measureLength(); } + +EndlessMemoryStream::~EndlessMemoryStream() +{ + delete stream; + stream = NULL; +} + +StreamType EndlessMemoryStream::getStreamType() +{ + return eSST_Memory; +} + +uint16_t EndlessMemoryStream::readMemoryBlock(char* data, int bufSize) +{ + if(stream == NULL) { + return 0; + } + + return stream->readMemoryBlock(data, bufSize); +} + +//Use base class documentation +bool EndlessMemoryStream::seek(int len) +{ + if(stream == NULL) { + return false; + } + + int res = stream->seek(len); + if(stream->isFinished()) { + delete stream; + stream = NULL; + } + + return res; +} + +size_t EndlessMemoryStream::write(uint8_t charToWrite) +{ + if(stream == NULL) { + stream = new MemoryDataStream(); + } + + return stream->write(charToWrite); +} + +size_t EndlessMemoryStream::write(const uint8_t *buffer, size_t size) +{ + if(stream == NULL) { + stream = new MemoryDataStream(); + } + + return stream->write(buffer, size); +} + +bool EndlessMemoryStream::isFinished() +{ + return false; +} diff --git a/Sming/SmingCore/DataSourceStream.h b/Sming/SmingCore/DataSourceStream.h index e0b2a48cc1..e9c7fbcadf 100644 --- a/Sming/SmingCore/DataSourceStream.h +++ b/Sming/SmingCore/DataSourceStream.h @@ -98,7 +98,7 @@ class ReadWriteStream : public IDataSourceStream /** @brief Write chars to stream * @param buffer Pointer to buffer to write to the stream - * @param size Quantity of chars to writen + * @param size Quantity of chars to write * @retval size_t Quantity of chars written to stream */ virtual size_t write(const uint8_t *buffer, size_t size) = 0; @@ -145,7 +145,7 @@ class MemoryDataStream : public Print, public ReadWriteStream /** @brief Write chars to stream * @param buffer Pointer to buffer to write to the stream - * @param size Quantity of chars to writen + * @param size Quantity of chars to write * @retval size_t Quantity of chars written to stream */ virtual size_t write(const uint8_t *buffer, size_t size); @@ -256,7 +256,7 @@ class TemplateFileStream : public FileStream /** @brief Set value of a variable in the template file * @param name Name of variable * @param value Value to assign to the variable - * @note Sets and existing varible or adds a new variable if variable does not already exist + * @note Sets and existing variable or adds a new variable if variable does not already exist */ void setVar(String name, String value); @@ -317,5 +317,37 @@ class JsonObjectStream : public MemoryDataStream bool send; }; +class EndlessMemoryStream: public ReadWriteStream +{ +public: + virtual ~EndlessMemoryStream(); + + //Use base class documentation + virtual StreamType getStreamType(); + + virtual uint16_t readMemoryBlock(char* data, int bufSize); + + //Use base class documentation + virtual bool seek(int len); + + /** @brief Write a single char to stream + * @param charToWrite Char to write to the stream + * @retval size_t Quantity of chars written to stream (always 1) + */ + virtual size_t write(uint8_t charToWrite); + + /** @brief Write chars to stream + * @param buffer Pointer to buffer to write to the stream + * @param size Quantity of chars to write + * @retval size_t Quantity of chars written to stream + */ + virtual size_t write(const uint8_t *buffer, size_t size); + + virtual bool isFinished(); + +private: + MemoryDataStream* stream = NULL; +}; + /** @} */ #endif /* _SMING_CORE_DATASTREAM_H_ */ diff --git a/Sming/SmingCore/Network/Http/HttpResource.h b/Sming/SmingCore/Network/Http/HttpResource.h index 4dc6078906..ffcd885977 100644 --- a/Sming/SmingCore/Network/Http/HttpResource.h +++ b/Sming/SmingCore/Network/Http/HttpResource.h @@ -30,6 +30,10 @@ typedef Delegate HttpPathDelegate; // << depr class HttpResource { public: virtual ~HttpResource() {} + /** + * @brief Takes care to cleanup the connection + */ + virtual void shutdown(HttpServerConnection& connection) {} public: HttpServerConnectionBodyDelegate onBody = 0; // << called when the resource wants to process the raw body data diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp index 4dc2c14185..6857e4954f 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp @@ -46,6 +46,9 @@ HttpServerConnection::HttpServerConnection(tcp_pcb *clientTcp) HttpServerConnection::~HttpServerConnection() { + if(this->resource) { + this->resource->shutdown(*this); + } } void HttpServerConnection::setResourceTree(ResourceTree* resourceTree) diff --git a/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp b/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp index 274a1070d0..4fa6aefa83 100644 --- a/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp +++ b/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp @@ -18,7 +18,7 @@ WebSocketConnection::WebSocketConnection(HttpServerConnection* conn) WebSocketConnection::~WebSocketConnection() { - websocketList.removeElement(*this); + websocketList.removeElement(this); } bool WebSocketConnection::initialize(HttpRequest& request, HttpResponse& response) @@ -41,9 +41,11 @@ bool WebSocketConnection::initialize(HttpRequest& request, HttpResponse& respons response.setHeader("Upgrade", "websocket"); response.setHeader("Sec-WebSocket-Accept", secure); - connection->userData = (void *)this; + delete stream; + stream = new EndlessMemoryStream(); + response.sendDataStream(stream); - websocketList.addElement(*this); + connection->userData = (void *)this; memset(&parserSettings, 0, sizeof(parserSettings)); parserSettings.on_data_begin = staticOnDataBegin; @@ -56,6 +58,7 @@ bool WebSocketConnection::initialize(HttpRequest& request, HttpResponse& respons ws_parser_init(&parser, &parserSettings); parser.user_data = (void*)this; + websocketList.addElement(this); if(wsConnect) { wsConnect(*this); } @@ -152,19 +155,21 @@ int WebSocketConnection::staticOnControlEnd(void* userData) void WebSocketConnection::send(const char* message, int length, wsFrameType type /* = WS_TEXT_FRAME*/) { + if(stream == NULL) { + return; + } + uint8_t frameHeader[16] = {0}; size_t headSize = sizeof(frameHeader); wsMakeFrame(nullptr, length, frameHeader, &headSize, type); - connection->send((const char* )frameHeader, (uint16_t )headSize); - if(length > 0) { - connection->send((const char* )message, (uint16_t )length); - } + stream->write((uint8_t *)frameHeader, (uint16_t )headSize); + stream->write((uint8_t *)message, (uint16_t )length); } void WebSocketConnection::broadcast(const char* message, int length, wsFrameType type /* = WS_TEXT_FRAME*/) { for (int i = 0; i < websocketList.count(); i++) { - websocketList[i].send(message, length, type); + websocketList[i]->send(message, length, type); } } @@ -190,9 +195,8 @@ WebSocketsList& WebSocketConnection::getActiveWebSockets() void WebSocketConnection::close() { - websocketList.removeElement((const WebSocketConnection)*this); + websocketList.removeElement(this); state = eWSCS_Closed; - if(wsDisconnect) { wsDisconnect(*this); } @@ -210,7 +214,6 @@ void* WebSocketConnection::getUserData() return userData; } - void WebSocketConnection::setConnectionHandler(WebSocketDelegate handler) { wsConnect = handler; diff --git a/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.h b/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.h index 0412fb3140..dc90541c19 100644 --- a/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.h +++ b/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.h @@ -17,7 +17,7 @@ extern "C" { class WebSocketConnection; -typedef Vector WebSocketsList; +typedef Vector WebSocketsList; typedef Delegate WebSocketDelegate; typedef Delegate WebSocketMessageDelegate; @@ -89,9 +89,9 @@ class WebSocketConnection ws_parser_t parser; ws_parser_callbacks_t parserSettings; -// @deprecated static WebSocketsList websocketList; -// @end deprecated + + EndlessMemoryStream* stream = NULL; }; #endif /* SMINGCORE_NETWORK_WEBSOCKETCONNECTION_H_ */ diff --git a/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.cpp b/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.cpp index bc487ad8e5..5b404766dd 100644 --- a/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.cpp +++ b/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.cpp @@ -32,13 +32,19 @@ int WebsocketResource::checkHeaders(HttpServerConnection& connection, HttpReques } connection.setTimeOut(USHRT_MAX); //Disable disconnection on connection idle (no rx/tx) - connection.userData = (void *)socket; // TODO: Re-Enable Command Executor... return 0; } +void WebsocketResource::shutdown(HttpServerConnection& connection) +{ + WebSocketConnection* socket = (WebSocketConnection *)connection.userData; + delete socket; + connection.userData = NULL; +} + int WebsocketResource::processData(HttpServerConnection& connection, HttpRequest& request, char *at, int size) { WebSocketConnection *socket = (WebSocketConnection *)connection.userData; diff --git a/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.h b/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.h index e69359993d..fe1ae89c08 100644 --- a/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.h +++ b/Sming/SmingCore/Network/Http/Websocket/WebsocketResource.h @@ -20,6 +20,8 @@ class WebsocketResource: public HttpResource { int checkHeaders(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response); int processData(HttpServerConnection& connection, HttpRequest& request, char *at, int size); + virtual void shutdown(HttpServerConnection& connection); + void setConnectionHandler(WebSocketDelegate handler); void setMessageHandler(WebSocketMessageDelegate handler); void setBinaryHandler(WebSocketBinaryDelegate handler); From be670971c9ff735031143790057a16d11a5d5165 Mon Sep 17 00:00:00 2001 From: slaff Date: Thu, 19 Oct 2017 09:42:42 +0200 Subject: [PATCH 27/33] Allow also poll to trigger sending of data. (#1266) --- Sming/SmingCore/Network/Http/HttpServerConnection.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp index 6857e4954f..3baa6afdf9 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp @@ -368,10 +368,6 @@ err_t HttpServerConnection::onReceive(pbuf *buf) void HttpServerConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) { - if(sourceEvent == eTCE_Poll) { - return; - } - if(state == eHCS_Sent) { state = eHCS_Ready; } From 09be6f481bb3d1f048f5ae7aca7ead8d4932ad48 Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 20 Oct 2017 11:42:28 +0200 Subject: [PATCH 28/33] HttpServer: WS: Fixed calling twice wsDisconnect callback. (#1267) --- .../Http/Websocket/WebSocketConnection.cpp | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp b/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp index 4fa6aefa83..a8c72b781f 100644 --- a/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp +++ b/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp @@ -18,7 +18,9 @@ WebSocketConnection::WebSocketConnection(HttpServerConnection* conn) WebSocketConnection::~WebSocketConnection() { - websocketList.removeElement(this); + state = eWSCS_Closed; + stream = NULL; + close(); } bool WebSocketConnection::initialize(HttpRequest& request, HttpResponse& response) @@ -58,7 +60,10 @@ bool WebSocketConnection::initialize(HttpRequest& request, HttpResponse& respons ws_parser_init(&parser, &parserSettings); parser.user_data = (void*)this; - websocketList.addElement(this); + if(!websocketList.contains(this)) { + websocketList.addElement(this); + } + if(wsConnect) { wsConnect(*this); } @@ -123,9 +128,6 @@ int WebSocketConnection::staticOnControlBegin(void* userData, ws_frame_type_t ty connection->controlFrameType = type; if (type == WS_FRAME_CLOSE) { - if(connection->wsDisconnect) { - connection->wsDisconnect(*connection); - } connection->close(); } @@ -196,9 +198,13 @@ WebSocketsList& WebSocketConnection::getActiveWebSockets() void WebSocketConnection::close() { websocketList.removeElement(this); - state = eWSCS_Closed; - if(wsDisconnect) { - wsDisconnect(*this); + if(state != eWSCS_Closed) { + state = eWSCS_Closed; + send((const char* )NULL, 0, WS_CLOSING_FRAME); + stream = NULL; + if(wsDisconnect) { + wsDisconnect(*this); + } } connection->setTimeOut(1); From a1bca65d9636a711099de5a84293fb9d0609cfdc Mon Sep 17 00:00:00 2001 From: slaff Date: Fri, 20 Oct 2017 11:50:33 +0200 Subject: [PATCH 29/33] Changed the testing MQTT server. (#1268) --- samples/MqttClient_Hello/app/application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/MqttClient_Hello/app/application.cpp b/samples/MqttClient_Hello/app/application.cpp index b534d8f43f..216104d85c 100644 --- a/samples/MqttClient_Hello/app/application.cpp +++ b/samples/MqttClient_Hello/app/application.cpp @@ -15,7 +15,7 @@ // ... and/or MQTT host and port #ifndef MQTT_HOST - #define MQTT_HOST "test.mosquitto.org" + #define MQTT_HOST "attachix.com" #ifndef ENABLE_SSL #define MQTT_PORT 1883 #else From e0d987556aa1486e5fb0c026091f9494f6afc004 Mon Sep 17 00:00:00 2001 From: slaff Date: Wed, 25 Oct 2017 19:47:24 +0200 Subject: [PATCH 30/33] Changed a TcpClient message to be less confusing. (#1271) --- Sming/SmingCore/Network/TcpClient.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Sming/SmingCore/Network/TcpClient.cpp b/Sming/SmingCore/Network/TcpClient.cpp index b327af36eb..cfc72c1301 100644 --- a/Sming/SmingCore/Network/TcpClient.cpp +++ b/Sming/SmingCore/Network/TcpClient.cpp @@ -46,11 +46,8 @@ TcpClient::TcpClient(TcpClientDataDelegate onReceive) TcpClient::~TcpClient() { - if (stream != NULL) - { - delete[] stream; - stream = NULL; - } + delete stream; + stream = NULL; } bool TcpClient::connect(String server, int port, boolean useSsl /* = false */, uint32_t sslOptions /* = 0 */) @@ -178,7 +175,7 @@ void TcpClient::pushAsyncPart() if (stream->isFinished()) { flush(); - debugf("TcpClient request completed"); + debugf("TcpClient stream finished"); delete stream; // Free memory now! stream = NULL; } From 932af744e4c246121072e1c4fbf98bbddf7b00f6 Mon Sep 17 00:00:00 2001 From: frankdownunder Date: Wed, 1 Nov 2017 21:22:24 +1100 Subject: [PATCH 31/33] Fix Memory Leak in Mqtt (#1273) --- Sming/Services/libemqtt/libemqtt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sming/Services/libemqtt/libemqtt.c b/Sming/Services/libemqtt/libemqtt.c index 28a97a14c6..de86c37525 100644 --- a/Sming/Services/libemqtt/libemqtt.c +++ b/Sming/Services/libemqtt/libemqtt.c @@ -215,6 +215,7 @@ int mqtt_set_clientid(mqtt_broker_handle_t* broker, const char* clientid) { int mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const char* password) { if(username && username[0] != '\0') { + free(broker->username); broker->username = (char *)malloc(strlen(username)+1); if(broker->username==NULL) { return -1; @@ -224,6 +225,7 @@ int mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const cha } if(password && password[0] != '\0') { + free(broker->username); broker->password = (char *)malloc(strlen(password)+1); if (broker->password == NULL) { return -1; From c2687b9ebc4147055d4d46c323d3408fcca31312 Mon Sep 17 00:00:00 2001 From: frankdownunder Date: Mon, 6 Nov 2017 06:08:00 +1100 Subject: [PATCH 32/33] Mqtt memory fix: Fix copy and paste error (#1276) --- Sming/Services/libemqtt/libemqtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sming/Services/libemqtt/libemqtt.c b/Sming/Services/libemqtt/libemqtt.c index de86c37525..0278f2c4b3 100644 --- a/Sming/Services/libemqtt/libemqtt.c +++ b/Sming/Services/libemqtt/libemqtt.c @@ -225,7 +225,7 @@ int mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const cha } if(password && password[0] != '\0') { - free(broker->username); + free(broker->password); broker->password = (char *)malloc(strlen(password)+1); if (broker->password == NULL) { return -1; From f09b9e7bf2cd43de616295109b495b7a636dd0f4 Mon Sep 17 00:00:00 2001 From: slaff Date: Mon, 6 Nov 2017 04:37:54 -0800 Subject: [PATCH 33/33] Preparation for release 3.4.0. (#1277) --- Readme.md | 2 +- Sming/SmingCore/SmingCore.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 274774e2a2..7780969bee 100644 --- a/Readme.md +++ b/Readme.md @@ -43,7 +43,7 @@ SDK = Software Development Kit n/a = The selected SDK is not available on that OS ## Latest Stable Release -- [Sming V3.3.0](https://github.com/SmingHub/Sming/releases/tag/3.3.0) +- [Sming V3.4.0](https://github.com/SmingHub/Sming/releases/tag/3.4.0) ## Getting started - [Windows](https://github.com/SmingHub/Sming/wiki/Windows-Quickstart) diff --git a/Sming/SmingCore/SmingCore.h b/Sming/SmingCore/SmingCore.h index cc5de45cd6..ae33fe81c7 100644 --- a/Sming/SmingCore/SmingCore.h +++ b/Sming/SmingCore/SmingCore.h @@ -8,7 +8,7 @@ #ifndef _NET_WIRING_ #define _NET_WIRING_ -#define SMING_VERSION "3.3.0" // Major Minor Sub +#define SMING_VERSION "3.4.0" // Major Minor Sub #include "../Wiring/WiringFrameworkIncludes.h"