diff --git a/.gitmodules b/.gitmodules index 83c49dc50d..8e6b426425 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,3 +33,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/.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 diff --git a/Readme.md b/Readme.md index 4d2ef01ecf..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) @@ -62,6 +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 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 separately for Sming and your application code. 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/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/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 28e4ba65fc..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/*/*/*/))) \ @@ -221,12 +222,14 @@ 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) # 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 @@ -277,6 +280,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)) @@ -336,12 +344,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 @@ -390,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 $@ @@ -450,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; \ @@ -470,12 +494,18 @@ 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 $(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))) diff --git a/Sming/Makefile-project.mk b/Sming/Makefile-project.mk index 03e7b76c53..52090080b9 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 @@ -175,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 @@ -205,6 +211,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 +230,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) @@ -259,6 +271,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) @@ -353,12 +367,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 @@ -367,9 +389,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 +495,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) @@ -485,3 +526,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 b26f761668..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/ @@ -205,6 +208,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 +259,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) @@ -422,12 +432,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 @@ -527,10 +545,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) @@ -552,3 +570,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/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/Services/libemqtt/libemqtt.c b/Sming/Services/libemqtt/libemqtt.c index 28a97a14c6..0278f2c4b3 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->password); broker->password = (char *)malloc(strlen(password)+1); if (broker->password == NULL) { return -1; 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/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..7cc53ceef7 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; } @@ -135,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; } @@ -361,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 fd81116c66..e9c7fbcadf 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 write + * @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; } @@ -127,7 +145,7 @@ class MemoryDataStream : public Print, 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); @@ -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(); @@ -238,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); @@ -299,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/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/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..4f02c837d8 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" @@ -23,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); @@ -54,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()); @@ -75,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; } @@ -136,9 +140,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 +173,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 +196,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 +263,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; } @@ -277,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 @@ -326,8 +331,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 +340,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; } } @@ -347,68 +352,111 @@ 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 -err_t HttpConnection::onConnected(err_t err) { - if (err == ERR_OK) { - debugf("HttpConnection::onConnected: waitingQueue.count: %d", waitingQueue->count()); +void HttpConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) +{ + + debugf("HttpConnection::onReadyToSendData: waitingQueue.count: %d", waitingQueue->count()); - do { + 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,75 +471,67 @@ void HttpConnection::send(HttpRequest* request) { sendString(write.c_str()); } sendString("\r\n"); +} - // Send content - - // 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); +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; + + 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; +HttpRequest* HttpConnection::getRequest() +{ + return incomingRequest; } -HttpResponse* HttpConnection::getResponse() { +HttpResponse* HttpConnection::getResponse() +{ HttpResponse* response = new HttpResponse(); response->code = code; response->headers = responseHeaders; @@ -508,14 +548,15 @@ 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; } // end of public methods for HttpConnection -err_t HttpConnection::onReceive(pbuf *buf) { +err_t HttpConnection::onReceive(pbuf *buf) +{ if (buf == NULL) { // Disconnected, close it @@ -551,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(); @@ -568,7 +611,8 @@ void HttpConnection::cleanup() { } } -HttpConnection::~HttpConnection() { +HttpConnection::~HttpConnection() +{ cleanup(); } diff --git a/Sming/SmingCore/Network/Http/HttpConnection.h b/Sming/SmingCore/Network/Http/HttpConnection.h index 2ea81f7072..10c950aa6d 100644 --- a/Sming/SmingCore/Network/Http/HttpConnection.h +++ b/Sming/SmingCore/Network/Http/HttpConnection.h @@ -77,30 +77,30 @@ 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: - 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); protected: HttpClientMode mode; @@ -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..722609b35b 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; } @@ -50,12 +50,13 @@ 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) { +HttpRequest* HttpRequest::setURL(const URL& uri) { this->uri = uri; return this; } @@ -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; @@ -209,7 +211,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 +221,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..1156fb30d5 100644 --- a/Sming/SmingCore/Network/Http/HttpRequest.h +++ b/Sming/SmingCore/Network/Http/HttpRequest.h @@ -35,13 +35,13 @@ 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); ~HttpRequest(); - HttpRequest* setURL(URL uri); + HttpRequest* setURL(const URL& uri); HttpRequest* setMethod(const HttpMethod method); @@ -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/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/HttpResponse.cpp b/Sming/SmingCore/Network/Http/HttpResponse.cpp index 1715b23b70..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) @@ -55,22 +53,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(); + } - return true; + MemoryDataStream *writable = static_cast(stream); + bool success = (writable->write((const uint8_t*)text.c_str(), text.length()) == text.length()); + + return success; } bool HttpResponse::hasHeader(const String& name) @@ -164,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..3baa6afdf9 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; @@ -45,6 +46,9 @@ HttpServerConnection::HttpServerConnection(tcp_pcb *clientTcp) HttpServerConnection::~HttpServerConnection() { + if(this->resource) { + this->resource->shutdown(*this); + } } void HttpServerConnection::setResourceTree(ResourceTree* resourceTree) @@ -73,7 +77,6 @@ int HttpServerConnection::staticOnMessageBegin(http_parser* parser) connection->response.stream = NULL; } - connection->headersSent = false; connection->state = eHCS_Ready; // ... and Request @@ -199,8 +202,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); } } @@ -347,101 +368,145 @@ err_t HttpServerConnection::onReceive(pbuf *buf) void HttpServerConnection::onReadyToSendData(TcpConnectionEvent sourceEvent) { - if(state != eHCS_Sending) { - TcpClient::onReadyToSendData(sourceEvent); - return; + if(state == eHCS_Sent) { + state = eHCS_Ready; } - bool sendContent = (request.method != HTTP_HEAD); + do { - 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 + '"'); - } + 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; + } + + 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("Content-Length") && response.stream == NULL) { - response.headers["Content-Length"] = "0"; + } + + 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(!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 +525,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..534df786d5 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: @@ -63,13 +56,16 @@ 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); 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/Http/Websocket/WebSocketConnection.cpp b/Sming/SmingCore/Network/Http/Websocket/WebSocketConnection.cpp index 274a1070d0..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) @@ -41,9 +43,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 +60,10 @@ bool WebSocketConnection::initialize(HttpRequest& request, HttpResponse& respons ws_parser_init(&parser, &parserSettings); parser.user_data = (void*)this; + if(!websocketList.contains(this)) { + websocketList.addElement(this); + } + if(wsConnect) { wsConnect(*this); } @@ -120,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(); } @@ -152,19 +157,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,11 +197,14 @@ WebSocketsList& WebSocketConnection::getActiveWebSockets() void WebSocketConnection::close() { - websocketList.removeElement((const WebSocketConnection)*this); - state = eWSCS_Closed; - - if(wsDisconnect) { - wsDisconnect(*this); + websocketList.removeElement(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); @@ -210,7 +220,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); 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); /** 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; } 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/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..2f0363c3e6 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,24 @@ 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 + */ + 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 +252,9 @@ class StationClass : protected ISystemReadyHandler private: ScanCompletedDelegate scanCompletedCallback; SmartConfigDelegate smartConfigCallback = NULL; +#ifdef ENABLE_WPS + WPSConfigDelegate wpsConfigCallback = NULL; +#endif bool runScan; }; 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" 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/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_ */ 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/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; + } } /** 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; + 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 diff --git a/Sming/third-party/axtls-8266/crypto/rsa.c b/Sming/third-party/axtls-8266/crypto/rsa.c index ab74b4d3be..5651a69c00 100644 --- a/Sming/third-party/axtls-8266/crypto/rsa.c +++ b/Sming/third-party/axtls-8266/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/Sming/third-party/axtls-8266/ssl/x509.c b/Sming/third-party/axtls-8266/ssl/x509.c index 35bd7281e5..f76fa5e5d5 100644 --- a/Sming/third-party/axtls-8266/ssl/x509.c +++ b/Sming/third-party/axtls-8266/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; diff --git a/Sming/third-party/esp-open-lwip/include/lwip/igmp.h b/Sming/third-party/esp-open-lwip/include/lwip/igmp.h index c90adcdce4..f0c9dea3fa 100644 --- a/Sming/third-party/esp-open-lwip/include/lwip/igmp.h +++ b/Sming/third-party/esp-open-lwip/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 diff --git a/Sming/third-party/spiffs/.travis.yml b/Sming/third-party/spiffs/.travis.yml index fe7cb23e42..8c36dc5723 100644 --- a/Sming/third-party/spiffs/.travis.yml +++ b/Sming/third-party/spiffs/.travis.yml @@ -5,4 +5,4 @@ compiler: before_script: -script: make all && make clean && make test && make build-all +script: make all && make clean && make test && make build-all && make clean test FLAGS=-DSPIFFS_OBJ_META_LEN=8 diff --git a/Sming/third-party/spiffs/FUZZING.md b/Sming/third-party/spiffs/FUZZING.md new file mode 100644 index 0000000000..f517800501 --- /dev/null +++ b/Sming/third-party/spiffs/FUZZING.md @@ -0,0 +1,47 @@ +# Fuzzing SPIFFS + +The SPIFFS test suite includes a test program designed for fuzzing with +[AFL](http://lcamtuf.coredump.cx/afl/). This automatically exercises the +SPIFFS API and verifies that the file system does not crash or interact incorrectly +with the flash chip. + +There are two steps to fuzzing. The first is to build the test suite with +the AFL version of gcc. The CC variable should point to your copy of afl-gcc. + +``` +make clean test CC=/usr/local/bin/afl-gcc +``` + +There is a new test `afl_test` that reads from stdin a list of commands +and arguments. These are interpreted and executed on the API. The `afltests` +directory contains a number of test cases that can be fed to the `afl_test` test. + + +The second is to run this test suite under afl as follows (where findings is +the output directory): + +``` +afl-fuzz -i afltests -o findings ./build/linux_spiffs_test -f afl_test +``` + +This run will take hours (or days) and will (hopefully) not find any crashes. +If a crash (or hang) is found, then the input file that caused the crash is +saved. This allows the specific test case to be debugged. + +## Reducing the size of the file + +AFL comes with `afl-tmin` which can reduce the size of the test input file to +make it easier to debug. + +``` +afl-tmin -i findings/crashes/ -o smalltest -- build/linux_spiffs_test -f afl_test +``` + +This will write a short version of the testcase file to `smalltest`. This can then be +fed into the test program for debugging: + +``` +build/linux_spiffs_test -f afl_test < smalltest +``` + +This should still crash, but allows it to be run under a debugger. diff --git a/Sming/third-party/spiffs/LICENSE b/Sming/third-party/spiffs/LICENSE index c32f3f0473..5fb2427b41 100644 --- a/Sming/third-party/spiffs/LICENSE +++ b/Sming/third-party/spiffs/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976gmail.com) +Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/Sming/third-party/spiffs/README.md b/Sming/third-party/spiffs/README.md index 63ab3f68b1..64ffcc36b3 100644 --- a/Sming/third-party/spiffs/README.md +++ b/Sming/third-party/spiffs/README.md @@ -1,9 +1,9 @@ # SPIFFS (SPI Flash File System) -**V0.3.6** +**V0.3.7** [![Build Status](https://travis-ci.org/pellepl/spiffs.svg?branch=master)](https://travis-ci.org/pellepl/spiffs) -Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976 at gmail.com) +Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976 at gmail.com) For legal stuff, see [LICENSE](https://github.com/pellepl/spiffs/blob/master/LICENSE). Basically, you may do whatever you want with the source. Use, modify, sell, print it out, roll it and smoke it - as long as I won't be held responsible. @@ -23,6 +23,13 @@ Spiffs is designed with following characteristics in mind: - Wear leveling +## BUILDING + +`mkdir build; make` + +Otherwise, configure the `builddir` variable towards the top of `makefile` as something opposed to the default `build`. Sanity check on the host via `make test` and refer to `.travis.yml` for the official in-depth testing procedure. See the wiki for [integrating](https://github.com/pellepl/spiffs/wiki/Integrate-spiffs) spiffs into projects and [spiffsimg](https://github.com/nodemcu/nodemcu-firmware/tree/master/tools/spiffsimg) from [nodemcu](https://github.com/nodemcu) is a good example on the subject. + + ## FEATURES What spiffs does: @@ -53,6 +60,25 @@ For a generic spi flash driver, see [this](https://github.com/pellepl/spiflash_d ## HISTORY +### 0.3.7 +- fixed prevent seeking to negative offsets #158 +- fixed file descriptor offsets not updated for multiple fds on same file #157 +- fixed cache page not closed for removed files #156 +- fixed a lseek bug when seeking exactly to end of a fully indexed first level LUT #148 +- fixed wear leveling issue #145 +- fixed attempt to write out of bounds in flash #130, +- set file offset when seeking over end #121 (thanks @sensslen) +- fixed seeking in virgin files #120 (thanks @sensslen) +- Optional file metadata #128 (thanks @cesanta) +- AFL testing framework #100 #143 (thanks @pjsg) +- Testframe updates + +New API functions: +- `SPIFFS_update_meta, SPIFFS_fupdate_meta` - updates metadata for a file + +New config defines: +- `SPIFFS_OBJ_META_LEN` - enable possibility to add extra metadata to files + ### 0.3.6 - Fix range bug in index memory mapping #98 - Add index memory mapping #97 diff --git a/Sming/third-party/spiffs/afltests/100 b/Sming/third-party/spiffs/afltests/100 new file mode 100644 index 0000000000..6bb223914e --- /dev/null +++ b/Sming/third-party/spiffs/afltests/100 @@ -0,0 +1,15 @@ +‰5S-C4 +d5rh +OlWkR#C4 +d5rh +O4W4R4O4W4êC4#d5rh +O4d5rh +OlWkRh +O4Y5rh +OlWkR4C44R45ŠË +O4W4ê4C4C4 +O4O4W4R4O4W4êC4#d5rh +O4d5rh +W4R45rË +O4W4ê4#d5rh +rz diff --git a/Sming/third-party/spiffs/afltests/200 b/Sming/third-party/spiffs/afltests/200 new file mode 100644 index 0000000000..90143128ac Binary files /dev/null and b/Sming/third-party/spiffs/afltests/200 differ diff --git a/Sming/third-party/spiffs/afltests/a b/Sming/third-party/spiffs/afltests/a new file mode 100644 index 0000000000..24e3a21253 --- /dev/null +++ b/Sming/third-party/spiffs/afltests/a @@ -0,0 +1,18 @@ + b55 +O4W4R4C4D4 +b45 +d5rh +O4W4R4f4C4 +baaU +d5rh +OaWaRafaCa +cd5rh +OaWaRafaCa +O4S4W4R4C4 +d5rh +O4W4S4R4C4 +d5rh +O4W4R4S4C4 +d5rh +O4W4R4C4 +d5rh diff --git a/Sming/third-party/spiffs/afltests/b b/Sming/third-party/spiffs/afltests/b new file mode 100644 index 0000000000..1f9577484b --- /dev/null +++ b/Sming/third-party/spiffs/afltests/b @@ -0,0 +1,15 @@ +b55 +O4 +W?W?W?W?W?f4 +WW:W;f4 +C4 +b45 +d5rh +O4W?R4f4C4 +baa +d5rh +OaWaRafaCa +d5rh +OaWaRafaCa +O4W?R4C4 +d5rh diff --git a/Sming/third-party/spiffs/makefile b/Sming/third-party/spiffs/makefile index 13ebd96e49..355b467909 100644 --- a/Sming/third-party/spiffs/makefile +++ b/Sming/third-party/spiffs/makefile @@ -16,12 +16,12 @@ builddir = build # ############# -CC = gcc $(COMPILEROPTIONS) -LD = ld -GDB = gdb -OBJCOPY = objcopy -OBJDUMP = objdump -MKDIR = mkdir -p +CC ?= gcc +LD ?= ld +GDB ?= gdb +OBJCOPY ?= objcopy +OBJDUMP ?= objdump +MKDIR ?= mkdir -p ############### # @@ -43,12 +43,13 @@ CFILES_TEST = main.c \ test_bugreports.c \ testsuites.c \ testrunner.c +CFLAGS += -D_SPIFFS_TEST endif include files.mk INCLUDE_DIRECTIVES = -I./${sourcedir} -I./${sourcedir}/default -I./${sourcedir}/test COMPILEROPTIONS = $(INCLUDE_DIRECTIVES) -COMPILEROPTIONS_APP = \ +COMPILEROPTIONS_APP = $(INCLUDE_DIRECTIVES) \ -Wall -Wno-format-y2k -W -Wstrict-prototypes -Wmissing-prototypes \ -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch \ -Wshadow -Wcast-align -Wchar-subscripts -Winline -Wnested-externs\ @@ -89,7 +90,7 @@ $(OBJFILES) : ${builddir}/%.o:%.c $(OBJFILES_TEST) : ${builddir}/%.o:%.c @echo "... compile $@" - @${CC} $(CFLAGS) -g -c -o $@ $< + @${CC} ${COMPILEROPTIONS} $(CFLAGS) -g -c -o $@ $< # make dependencies # @echo "... depend $@"; diff --git a/Sming/third-party/spiffs/src/default/spiffs_config.h b/Sming/third-party/spiffs/src/default/spiffs_config.h index 008a5d084e..ce562bfa20 100644 --- a/Sming/third-party/spiffs/src/default/spiffs_config.h +++ b/Sming/third-party/spiffs/src/default/spiffs_config.h @@ -17,26 +17,70 @@ #include #include #include +#ifdef _SPIFFS_TEST +#include "testrunner.h" +#endif // ----------- >8 ------------ // compile time switches // Set generic spiffs debug output call. #ifndef SPIFFS_DBG -#define SPIFFS_DBG(...) //printf(__VA_ARGS__) +#define SPIFFS_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) #endif // Set spiffs debug output call for garbage collecting. #ifndef SPIFFS_GC_DBG -#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__) +#define SPIFFS_GC_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) #endif // Set spiffs debug output call for caching. #ifndef SPIFFS_CACHE_DBG -#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__) +#define SPIFFS_CACHE_DBG(_f, ...) //printf(_f, ## __VA_ARGS__) #endif // Set spiffs debug output call for system consistency checks. #ifndef SPIFFS_CHECK_DBG -#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__) +#define SPIFFS_CHECK_DBG(_f, ...) //printf(_f, ## __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 + + + +// Defines spiffs debug print formatters +// some general signed number +#ifndef _SPIPRIi +#define _SPIPRIi "%d" +#endif +// address +#ifndef _SPIPRIad +#define _SPIPRIad "%08x" +#endif +// block +#ifndef _SPIPRIbl +#define _SPIPRIbl "%04x" #endif +// page +#ifndef _SPIPRIpg +#define _SPIPRIpg "%04x" +#endif +// span index +#ifndef _SPIPRIsp +#define _SPIPRIsp "%04x" +#endif +// file descriptor +#ifndef _SPIPRIfd +#define _SPIPRIfd "%d" +#endif +// file object id +#ifndef _SPIPRIid +#define _SPIPRIid "%04x" +#endif +// file flags +#ifndef _SPIPRIfl +#define _SPIPRIfl "%02x" +#endif + // Enable/disable API functions to determine exact number of bytes // for filedescriptor and cache buffers. Once decided for a configuration, @@ -107,6 +151,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/src/spiffs.h b/Sming/third-party/spiffs/src/spiffs.h index bea90b3f34..534c3df8bd 100644 --- a/Sming/third-party/spiffs/src/spiffs.h +++ b/Sming/third-party/spiffs/src/spiffs.h @@ -60,6 +60,9 @@ extern "C" { #define SPIFFS_ERR_IX_MAP_MAPPED -10038 #define SPIFFS_ERR_IX_MAP_BAD_RANGE -10039 +#define SPIFFS_ERR_SEEK_BOUNDS -10040 + + #define SPIFFS_ERR_INTERNAL -10050 #define SPIFFS_ERR_TEST -10100 @@ -137,7 +140,7 @@ typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, #ifndef SPIFFS_DBG #define SPIFFS_DBG(...) \ - print(__VA_ARGS__) + printf(__VA_ARGS__) #endif #ifndef SPIFFS_GC_DBG #define SPIFFS_GC_DBG(...) printf(__VA_ARGS__) @@ -297,6 +300,9 @@ typedef struct { spiffs_obj_type type; spiffs_page_ix pix; u8_t name[SPIFFS_OBJ_NAME_LEN]; +#if SPIFFS_OBJ_META_LEN + u8_t meta[SPIFFS_OBJ_META_LEN]; +#endif } spiffs_stat; struct spiffs_dirent { @@ -305,6 +311,9 @@ struct spiffs_dirent { spiffs_obj_type type; u32_t size; spiffs_page_ix pix; +#if SPIFFS_OBJ_META_LEN + u8_t meta[SPIFFS_OBJ_META_LEN]; +#endif }; typedef struct { @@ -525,6 +534,24 @@ s32_t SPIFFS_close(spiffs *fs, spiffs_file fh); */ s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath); +#if SPIFFS_OBJ_META_LEN +/** + * Updates file's metadata + * @param fs the file system struct + * @param path path to the file + * @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long. + */ +s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta); + +/** + * Updates file's metadata + * @param fs the file system struct + * @param fh file handle of the file + * @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long. + */ +s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta); +#endif + /** * Returns last error of last file operation. * @param fs the file system struct diff --git a/Sming/third-party/spiffs/src/spiffs_cache.c b/Sming/third-party/spiffs/src/spiffs_cache.c index b508ad5894..e7cd4b7376 100644 --- a/Sming/third-party/spiffs/src/spiffs_cache.c +++ b/Sming/third-party/spiffs/src/spiffs_cache.c @@ -20,12 +20,12 @@ static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) if ((cache->cpage_use_map & (1<flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && cp->pix == pix ) { - SPIFFS_CACHE_DBG("CACHE_GET: have cache page %i for %04x\n", i, pix); + //SPIFFS_CACHE_DBG("CACHE_GET: have cache page "_SPIPRIi" for "_SPIPRIpg"\n", i, pix); cp->last_access = cache->last_access; return cp; } } - //SPIFFS_CACHE_DBG("CACHE_GET: no cache for %04x\n", pix); + //SPIFFS_CACHE_DBG("CACHE_GET: no cache for "_SPIPRIpg"\n", pix); return 0; } @@ -39,17 +39,20 @@ static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) { (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 && (cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) { u8_t *mem = spiffs_get_cache_page(fs, cache, ix); + SPIFFS_CACHE_DBG("CACHE_FREE: write cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix); res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem); } - cp->flags = 0; - cache->cpage_use_map &= ~(1 << ix); - +#if SPIFFS_CACHE_WR if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) { - SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i objid %04x\n", ix, cp->obj_id); - } else { - SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i pix %04x\n", ix, cp->pix); + SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" objid "_SPIPRIid"\n", ix, cp->obj_id); + } else +#endif + { + SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix); } + cache->cpage_use_map &= ~(1 << ix); + cp->flags = 0; } return res; @@ -98,7 +101,7 @@ static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) { spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i); cache->cpage_use_map |= (1<last_access = cache->last_access; - SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %i\n", i); + //SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi"\n", i); return cp; } } @@ -136,7 +139,7 @@ s32_t spiffs_phys_rd( #endif cp->last_access = cache->last_access; u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); - memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); + _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); } else { if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) { // for second layer lookup functions, we do not cache in order to prevent shredding @@ -153,6 +156,7 @@ s32_t spiffs_phys_rd( if (cp) { cp->flags = SPIFFS_CACHE_FLAG_WRTHRU; cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr); + SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for pix "_SPIPRIpg "\n", cp->ix, cp->pix); s32_t res2 = SPIFFS_HAL_READ(fs, addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr), @@ -163,7 +167,7 @@ s32_t spiffs_phys_rd( res = res2; } u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); - memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); + _SPIFFS_MEMCPY(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len); } else { // this will never happen, last resort for sake of symmetry s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst); @@ -201,7 +205,7 @@ s32_t spiffs_phys_wr( } u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix); - memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len); + _SPIFFS_MEMCPY(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len); cache->last_access++; cp->last_access = cache->last_access; @@ -256,6 +260,7 @@ spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) { cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR; cp->obj_id = fd->obj_id; fd->cache_page = cp; + SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi" for fd "_SPIPRIfd ":"_SPIPRIid "\n", cp->ix, fd->file_nbr, fd->obj_id); return cp; } @@ -299,7 +304,7 @@ void spiffs_cache_init(spiffs *fs) { cache.cpage_use_map = 0xffffffff; cache.cpage_use_mask = cache_mask; - memcpy(fs->cache, &cache, sizeof(spiffs_cache)); + _SPIFFS_MEMCPY(fs->cache, &cache, sizeof(spiffs_cache)); spiffs_cache *c = spiffs_get_cache(fs); diff --git a/Sming/third-party/spiffs/src/spiffs_check.c b/Sming/third-party/spiffs/src/spiffs_check.c index 1222dea3d8..dde85eff3c 100644 --- a/Sming/third-party/spiffs/src/spiffs_check.c +++ b/Sming/third-party/spiffs/src/spiffs_check.c @@ -182,7 +182,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) || ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) { // look up entry deleted / free but used in page header - SPIFFS_CHECK_DBG("LU: pix %04x deleted/free in lu but not on page\n", cur_pix); + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" deleted/free in lu but not on page\n", cur_pix); *reload_lu = 1; delete_page = 1; if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) { @@ -199,14 +199,14 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s // copy page to new place and re-write the object index to new place spiffs_page_ix new_pix; res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); - SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix); SPIFFS_CHECK_RES(res); *reload_lu = 1; - SPIFFS_CHECK_DBG("LU: FIXUP: %04x rewritten to %04x, affected objix_pix %04x\n", cur_pix, new_pix, objix_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg" rewritten to "_SPIPRIpg", affected objix_pix "_SPIPRIpg"\n", cur_pix, new_pix, objix_pix); res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix); if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { // index bad also, cannot mend this file - SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res); + SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); res = spiffs_page_delete(fs, new_pix); SPIFFS_CHECK_RES(res); res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id); @@ -229,7 +229,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s // got a data page also, assume lu corruption only, rewrite to new page spiffs_page_ix new_pix; res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix); - SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix); SPIFFS_CHECK_RES(res); *reload_lu = 1; CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); @@ -242,7 +242,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) { // look up entry used if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) { - SPIFFS_CHECK_DBG("LU: pix %04x differ in obj_id lu:%04x ph:%04x\n", cur_pix, lu_obj_id, p_hdr->obj_id); + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" differ in obj_id lu:"_SPIPRIid" ph:"_SPIPRIid"\n", cur_pix, lu_obj_id, p_hdr->obj_id); delete_page = 1; if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 || (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) || @@ -265,7 +265,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix); if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { // index bad also, cannot mend this file - SPIFFS_CHECK_DBG("LU: FIXUP: index bad %i, cannot mend!\n", res); + SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); res = spiffs_page_delete(fs, new_pix); SPIFFS_CHECK_RES(res); res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id); @@ -321,7 +321,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s // rewrite as obj_id_ph new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG; res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix); - SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid" to pix "_SPIPRIpg"\n", cur_pix, new_ph.obj_id, new_pix); CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); SPIFFS_CHECK_RES(res); *reload_lu = 1; @@ -330,7 +330,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s // got a data page for look up obj id // rewrite as obj_id_lu new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG; - SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id); + SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid"\n", cur_pix, new_ph.obj_id); CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix); res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix); SPIFFS_CHECK_RES(res); @@ -344,7 +344,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s } } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) || ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) { - SPIFFS_CHECK_DBG("LU: %04x lu/page index marking differ\n", cur_pix); + SPIFFS_CHECK_DBG("LU: "_SPIPRIpg" lu/page index marking differ\n", cur_pix); spiffs_page_ix data_pix, objix_pix_d; // see if other data page exists for given obj id and span index res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix); @@ -402,10 +402,10 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s } } else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) { - SPIFFS_CHECK_DBG("LU: pix %04x busy in lu but deleted on page\n", cur_pix); + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy in lu but deleted on page\n", cur_pix); delete_page = 1; } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) { - SPIFFS_CHECK_DBG("LU: pix %04x busy but not final\n", cur_pix); + SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy but not final\n", cur_pix); // page can be removed if not referenced by object index *reload_lu = 1; res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix); @@ -433,7 +433,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s } if (delete_page) { - SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix); + SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix); CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0); res = spiffs_page_delete(fs, cur_pix); SPIFFS_CHECK_RES(res); @@ -530,7 +530,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block; while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) { //if ((cur_pix & 0xff) == 0) - // SPIFFS_CHECK_DBG("PA: processing pix %08x, block %08x of pix %08x, block %08x\n", + // SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n", // cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count); // read header @@ -589,7 +589,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) { // bad reference - SPIFFS_CHECK_DBG("PA: pix %04x bad pix / LU referenced from page %04x\n", + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n", rpix, cur_pix); // check for data page elsewhere spiffs_page_ix data_pix; @@ -608,15 +608,15 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { new_ph.span_ix = data_spix_offset + i; res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix); SPIFFS_CHECK_RES(res); - SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ %04x\n", data_pix); + SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg"\n", data_pix); } // remap index - SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix %04x\n", cur_pix); + SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg"\n", cur_pix); res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i, data_pix, cur_pix); if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { // index bad also, cannot mend this file - SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res); + SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend - delete object\n", res); CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0); // delete file res = spiffs_page_delete(fs, cur_pix); @@ -640,7 +640,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { rp_hdr.span_ix != data_spix_offset + i || (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) != (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) { - SPIFFS_CHECK_DBG("PA: pix %04x has inconsistent page header ix id/span:%04x/%04x, ref id/span:%04x/%04x flags:%02x\n", + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" has inconsistent page header ix id/span:"_SPIPRIid"/"_SPIPRIsp", ref id/span:"_SPIPRIid"/"_SPIPRIsp" flags:"_SPIPRIfl"\n", rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i, rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags); // try finding correct page @@ -654,19 +654,19 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { SPIFFS_CHECK_RES(res); if (data_pix == 0) { // not found, this index is badly borked - SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id); + SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid"\n", p_hdr.obj_id); CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); SPIFFS_CHECK_RES(res); break; } else { // found it, so rewrite index - SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix %04x, rewrite ix pix %04x id %04x\n", + SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg", rewrite ix pix "_SPIPRIpg" id "_SPIPRIid"\n", data_pix, cur_pix, p_hdr.obj_id); res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix); if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { // index bad also, cannot mend this file - SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res); + SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); } else { @@ -681,12 +681,12 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits); const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits; if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) { - SPIFFS_CHECK_DBG("PA: pix %04x multiple referenced from page %04x\n", + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" multiple referenced from page "_SPIPRIpg"\n", rpix, cur_pix); // Here, we should have fixed all broken references - getting this means there // must be multiple files with same object id. Only solution is to delete // the object which is referring to this page - SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n", + SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid" and page "_SPIPRIpg"\n", p_hdr.obj_id, cur_pix); CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id); @@ -725,7 +725,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { if (bitmask == 0x1) { // 001 - SPIFFS_CHECK_DBG("PA: pix %04x USED, UNREFERENCED, not index\n", cur_pix); + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, UNREFERENCED, not index\n", cur_pix); u8_t rewrite_ix_to_this = 0; u8_t delete_page = 0; @@ -741,7 +741,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) { // pointing to a bad page altogether, rewrite index to this rewrite_ix_to_this = 1; - SPIFFS_CHECK_DBG("PA: corresponding ref is bad: %04x, rewrite to this %04x\n", rpix, cur_pix); + SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg", rewrite to this "_SPIPRIpg"\n", rpix, cur_pix); } else { // pointing to something else, check what spiffs_page_header rp_hdr; @@ -752,12 +752,12 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) == (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) { // pointing to something else valid, just delete this page then - SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: %04x, delete this %04x\n", rpix, cur_pix); + SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg", delete this "_SPIPRIpg"\n", rpix, cur_pix); delete_page = 1; } else { // pointing to something weird, update index to point to this page instead if (rpix != cur_pix) { - SPIFFS_CHECK_DBG("PA: corresponding ref is weird: %04x %s%s%s%s, rewrite this %04x\n", rpix, + SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg" %s%s%s%s, rewrite this "_SPIPRIpg"\n", rpix, (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ", (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ", (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "", @@ -770,19 +770,19 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { } } } else if (res == SPIFFS_ERR_NOT_FOUND) { - SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete %04x\n", cur_pix); + SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg"\n", cur_pix); delete_page = 1; res = SPIFFS_OK; } if (rewrite_ix_to_this) { // if pointing to invalid page, redirect index to this page - SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id %04x data spix %04x to point to this pix: %04x\n", + SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid" data spix "_SPIPRIsp" to point to this pix: "_SPIPRIpg"\n", p_hdr.obj_id, p_hdr.span_ix, cur_pix); res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix); if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) { // index bad also, cannot mend this file - SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res); + SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res); CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0); res = spiffs_page_delete(fs, cur_pix); SPIFFS_CHECK_RES(res); @@ -794,7 +794,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { restart = 1; continue; } else if (delete_page) { - SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix); + SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix); CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0); res = spiffs_page_delete(fs, cur_pix); } @@ -803,7 +803,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { if (bitmask == 0x2) { // 010 - SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, not index\n", cur_pix); + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, not index\n", cur_pix); // no op, this should be taken care of when checking valid references } @@ -813,7 +813,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { if (bitmask == 0x4) { // 100 - SPIFFS_CHECK_DBG("PA: pix %04x FREE, unreferenced, INDEX\n", cur_pix); + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, unreferenced, INDEX\n", cur_pix); // this should never happen, major fubar } @@ -823,14 +823,14 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { if (bitmask == 0x6) { // 110 - SPIFFS_CHECK_DBG("PA: pix %04x FREE, REFERENCED, INDEX\n", cur_pix); + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, INDEX\n", cur_pix); // no op, this should be taken care of when checking valid references } if (bitmask == 0x7) { // 111 - SPIFFS_CHECK_DBG("PA: pix %04x USED, REFERENCED, INDEX\n", cur_pix); + SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, REFERENCED, INDEX\n", cur_pix); // no op, this should be taken care of when checking valid references } @@ -838,7 +838,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) { } } - SPIFFS_CHECK_DBG("PA: processed %04x, restart %i\n", pix_offset, restart); + SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg", restart "_SPIPRIi"\n", pix_offset, restart); // next page range if (!restart) { pix_offset += pages_per_scan; @@ -898,7 +898,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o if (p_hdr.span_ix == 0 && (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) == (SPIFFS_PH_FLAG_DELET)) { - SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n", + SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" header not fully deleted - deleting\n", cur_pix, obj_id, p_hdr.span_ix); CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id); res = spiffs_page_delete(fs, cur_pix); @@ -954,7 +954,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o } if (delete) { - SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n", + SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" is orphan index - deleting\n", cur_pix, obj_id, p_hdr.span_ix); CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id); res = spiffs_page_delete(fs, cur_pix); diff --git a/Sming/third-party/spiffs/src/spiffs_gc.c b/Sming/third-party/spiffs/src/spiffs_gc.c index 3b5f305b63..db1af4ccf6 100644 --- a/Sming/third-party/spiffs/src/spiffs_gc.c +++ b/Sming/third-party/spiffs/src/spiffs_gc.c @@ -11,7 +11,7 @@ static s32_t spiffs_gc_erase_block( spiffs_block_ix bix) { s32_t res; - SPIFFS_GC_DBG("gc: erase block %i\n", bix); + SPIFFS_GC_DBG("gc: erase block "_SPIPRIbl"\n", bix); res = spiffs_erase_block(fs, bix); SPIFFS_CHECK_RES(res); @@ -122,19 +122,19 @@ s32_t spiffs_gc_check( u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs); // if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) { -// SPIFFS_GC_DBG("gc: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); +// SPIFFS_GC_DBG("gc: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); // return SPIFFS_ERR_FULL; // } if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) { - SPIFFS_GC_DBG("gc_check: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); + SPIFFS_GC_DBG("gc_check: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted); return SPIFFS_ERR_FULL; } do { - SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n", + SPIFFS_GC_DBG("\ngc_check #"_SPIPRIi": run gc free_blocks:"_SPIPRIi" pfree:"_SPIPRIi" pallo:"_SPIPRIi" pdele:"_SPIPRIi" ["_SPIPRIi"] len:"_SPIPRIi" of "_SPIPRIi"\n", tries, fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted), - len, free_pages*SPIFFS_DATA_PAGE_SIZE(fs)); + len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs))); spiffs_block_ix *cands; int count; @@ -152,13 +152,13 @@ s32_t spiffs_gc_check( #endif cand = cands[0]; fs->cleaning = 1; - //printf("gcing: cleaning block %i\n", cand); + //SPIFFS_GC_DBG("gcing: cleaning block "_SPIPRIi"\n", cand); res = spiffs_gc_clean(fs, cand); fs->cleaning = 0; if (res < 0) { - SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res); + SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res); } else { - SPIFFS_GC_DBG("gc_check: cleaning block %i, result %i\n", cand, res); + SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res); } SPIFFS_CHECK_RES(res); @@ -188,7 +188,7 @@ s32_t spiffs_gc_check( res = SPIFFS_ERR_FULL; } - SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n", + SPIFFS_GC_DBG("gc_check: finished, "_SPIPRIi" dirty, blocks "_SPIPRIi" free, "_SPIPRIi" pages free, "_SPIPRIi" tries, res "_SPIPRIi"\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, free_pages, tries, res); @@ -226,7 +226,7 @@ s32_t spiffs_gc_erase_page_stats( } // per entry obj_lookup_page++; } // per object lookup page - SPIFFS_GC_DBG("gc_check: wipe pallo:%i pdele:%i\n", allo, dele); + SPIFFS_GC_DBG("gc_check: wipe pallo:"_SPIPRIi" pdele:"_SPIPRIi"\n", allo, dele); fs->stats_p_allocated -= allo; fs->stats_p_deleted -= dele; return res; @@ -294,7 +294,7 @@ s32_t spiffs_gc_find_candidate( // calculate score and insert into candidate table // stoneage sort, but probably not so many blocks - if (res == SPIFFS_OK && deleted_pages_in_block > 0) { + if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) { // read erase count spiffs_obj_id erase_count; res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, @@ -314,7 +314,7 @@ s32_t spiffs_gc_find_candidate( used_pages_in_block * SPIFFS_GC_HEUR_W_USED + erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE); int cand_ix = 0; - SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); + SPIFFS_GC_DBG("gc_check: bix:"_SPIPRIbl" del:"_SPIPRIi" use:"_SPIPRIi" score:"_SPIPRIi"\n", cur_block, deleted_pages_in_block, used_pages_in_block, score); while (cand_ix < max_candidates) { if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) { cand_blocks[cand_ix] = cur_block; @@ -385,7 +385,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work; spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work; - SPIFFS_GC_DBG("gc_clean: cleaning block %i\n", bix); + SPIFFS_GC_DBG("gc_clean: cleaning block "_SPIPRIbl"\n", bix); memset(&gc, 0, sizeof(spiffs_gc)); gc.state = FIND_OBJ_DATA; @@ -394,11 +394,11 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { // move free cursor to next block, cannot use free pages from the block we want to clean fs->free_cursor_block_ix = (bix+1)%fs->block_count; fs->free_cursor_obj_lu_entry = 0; - SPIFFS_GC_DBG("gc_clean: move free cursor to block %i\n", fs->free_cursor_block_ix); + SPIFFS_GC_DBG("gc_clean: move free cursor to block "_SPIPRIbl"\n", fs->free_cursor_block_ix); } while (res == SPIFFS_OK && gc.state != FINISHED) { - SPIFFS_GC_DBG("gc_clean: state = %i entry:%i\n", gc.state, cur_entry); + SPIFFS_GC_DBG("gc_clean: state = "_SPIPRIi" entry:"_SPIPRIi"\n", gc.state, cur_entry); gc.obj_id_found = 0; // reset (to no found data page) // scan through lookup pages @@ -423,7 +423,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE && ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) { // found a data page, stop scanning and handle in switch case below - SPIFFS_GC_DBG("gc_clean: FIND_DATA state:%i - found obj id %04x\n", gc.state, obj_id); + SPIFFS_GC_DBG("gc_clean: FIND_DATA state:"_SPIPRIi" - found obj id "_SPIPRIid"\n", gc.state, obj_id); gc.obj_id_found = 1; gc.cur_obj_id = obj_id; gc.cur_data_pix = cur_pix; @@ -438,7 +438,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); SPIFFS_CHECK_RES(res); - SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page %04x:%04x @ %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page "_SPIPRIid":"_SPIPRIsp" @ "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix); if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) { SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n"); } else { @@ -446,7 +446,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { // move page res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix); - SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix %04x:%04x page %04x to %04x\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix); SPIFFS_CHECK_RES(res); // move wipes obj_lu, reload it res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, @@ -457,7 +457,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { // page is deleted but not deleted in lookup, scrap it - // might seem unnecessary as we will erase this block, but // we might get aborted - SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix); res = spiffs_page_delete(fs, cur_pix); SPIFFS_CHECK_RES(res); new_data_pix = SPIFFS_OBJ_ID_FREE; @@ -466,11 +466,11 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { if (gc.cur_objix_spix == 0) { // update object index header page ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix; - SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); } else { // update object index page ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix; - SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)); } } } @@ -489,7 +489,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) { // move page res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix); - SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix %04x:%04x page %04x to %04x\n", obj_id, p_hdr.span_ix, cur_pix, new_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix); SPIFFS_CHECK_RES(res); spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&p_hdr, SPIFFS_EV_IX_MOV, obj_id, p_hdr.span_ix, new_pix, 0); @@ -502,7 +502,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { // page is deleted but not deleted in lookup, scrap it - // might seem unnecessary as we will erase this block, but // we might get aborted - SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\n", obj_id, p_hdr.span_ix, cur_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix); res = spiffs_page_delete(fs, cur_pix); if (res == SPIFFS_OK) { spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0, @@ -537,13 +537,13 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr); SPIFFS_CHECK_RES(res); gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix); - SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:%04x\n", gc.cur_objix_spix); + SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:"_SPIPRIsp"\n", gc.cur_objix_spix); res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix); if (res == SPIFFS_ERR_NOT_FOUND) { // on borked systems we might get an ERR_NOT_FOUND here - // this is handled by simply deleting the page as it is not referenced // from anywhere - SPIFFS_GC_DBG("gc_clean: FIND_OBJ_DATA objix not found! Wipe page %04x\n", gc.cur_data_pix); + SPIFFS_GC_DBG("gc_clean: FIND_OBJ_DATA objix not found! Wipe page "_SPIPRIpg"\n", gc.cur_data_pix); res = spiffs_page_delete(fs, gc.cur_data_pix); SPIFFS_CHECK_RES(res); // then we restore states and continue scanning for data pages @@ -552,7 +552,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { break; // done } SPIFFS_CHECK_RES(res); - SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page %04x\n", objix_pix); + SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page "_SPIPRIpg"\n", objix_pix); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -575,13 +575,13 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { cur_entry = gc.stored_scan_entry_index; // pop cursor if (gc.cur_objix_spix == 0) { // store object index header page - res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, &new_objix_pix); - SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\n", new_objix_pix, 0); + res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, 0); SPIFFS_CHECK_RES(res); } else { // store object index page res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix); - SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, %04x:%04x\n", new_objix_pix, objix->p_hdr.span_ix); + SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix); SPIFFS_CHECK_RES(res); spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work, SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); @@ -596,7 +596,7 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { cur_entry = 0; break; } // switch gc.state - SPIFFS_GC_DBG("gc_clean: state-> %i\n", gc.state); + SPIFFS_GC_DBG("gc_clean: state-> "_SPIPRIi"\n", gc.state); } // while state != FINISHED diff --git a/Sming/third-party/spiffs/src/spiffs_hydrogen.c b/Sming/third-party/spiffs/src/spiffs_hydrogen.c index 1cf64ff220..235aaaa60f 100644 --- a/Sming/third-party/spiffs/src/spiffs_hydrogen.c +++ b/Sming/third-party/spiffs/src/spiffs_hydrogen.c @@ -8,14 +8,6 @@ #include "spiffs.h" #include "spiffs_nucleus.h" -#if SPIFFS_FILEHDL_OFFSET -#define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0) -#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0) -#else -#define SPIFFS_FH_OFFS(fs, fh) (fh) -#define SPIFFS_FH_UNOFFS(fs, fh) (fh) -#endif - #if SPIFFS_CACHE == 1 static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh); #endif @@ -69,6 +61,7 @@ s32_t SPIFFS_format(spiffs *fs) { #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 s32_t SPIFFS_probe_fs(spiffs_config *config) { + SPIFFS_API_DBG("%s\n", __func__); s32_t res = spiffs_probe(config); return res; } @@ -79,11 +72,23 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, u8_t *fd_space, u32_t fd_space_size, void *cache, u32_t cache_size, spiffs_check_callback check_cb_f) { + SPIFFS_API_DBG("%s " + " sz:"_SPIPRIi " logpgsz:"_SPIPRIi " logblksz:"_SPIPRIi " perasz:"_SPIPRIi + " addr:"_SPIPRIad + " fdsz:"_SPIPRIi " cachesz:"_SPIPRIi + "\n", + __func__, + SPIFFS_CFG_PHYS_SZ(fs), + SPIFFS_CFG_LOG_PAGE_SZ(fs), + SPIFFS_CFG_LOG_BLOCK_SZ(fs), + SPIFFS_CFG_PHYS_ERASE_SZ(fs), + SPIFFS_CFG_PHYS_ADDR(fs), + fd_space_size, cache_size); void *user_data; SPIFFS_LOCK(fs); user_data = fs->user_data; memset(fs, 0, sizeof(spiffs)); - memcpy(&fs->cfg, config, sizeof(spiffs_config)); + _SPIFFS_MEMCPY(&fs->cfg, config, sizeof(spiffs_config)); fs->user_data = user_data; fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs); fs->work = &work[0]; @@ -129,14 +134,14 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, res = spiffs_obj_lu_scan(fs); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs)); - SPIFFS_DBG("object lookup pages: %i\n", SPIFFS_OBJ_LOOKUP_PAGES(fs)); - SPIFFS_DBG("page pages per block: %i\n", SPIFFS_PAGES_PER_BLOCK(fs)); - SPIFFS_DBG("page header length: %i\n", sizeof(spiffs_page_header)); - SPIFFS_DBG("object header index entries: %i\n", SPIFFS_OBJ_HDR_IX_LEN(fs)); - SPIFFS_DBG("object index entries: %i\n", SPIFFS_OBJ_IX_LEN(fs)); - SPIFFS_DBG("available file descriptors: %i\n", fs->fd_count); - SPIFFS_DBG("free blocks: %i\n", fs->free_blocks); + SPIFFS_DBG("page index byte len: "_SPIPRIi"\n", (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)); + SPIFFS_DBG("object lookup pages: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_LOOKUP_PAGES(fs)); + SPIFFS_DBG("page pages per block: "_SPIPRIi"\n", (u32_t)SPIFFS_PAGES_PER_BLOCK(fs)); + SPIFFS_DBG("page header length: "_SPIPRIi"\n", (u32_t)sizeof(spiffs_page_header)); + SPIFFS_DBG("object header index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_HDR_IX_LEN(fs)); + SPIFFS_DBG("object index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_IX_LEN(fs)); + SPIFFS_DBG("available file descriptors: "_SPIPRIi"\n", (u32_t)fs->fd_count); + SPIFFS_DBG("free blocks: "_SPIPRIi"\n", (u32_t)fs->free_blocks); fs->check_cb_f = check_cb_f; @@ -148,6 +153,7 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, } void SPIFFS_unmount(spiffs *fs) { + SPIFFS_API_DBG("%s\n", __func__); if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return; SPIFFS_LOCK(fs); u32_t i; @@ -171,10 +177,12 @@ s32_t SPIFFS_errno(spiffs *fs) { } void SPIFFS_clearerr(spiffs *fs) { + SPIFFS_API_DBG("%s\n", __func__); fs->err_code = SPIFFS_OK; } s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) { + SPIFFS_API_DBG("%s '%s'\n", __func__, path); #if SPIFFS_READ_ONLY (void)fs; (void)path; (void)mode; return SPIFFS_ERR_RO_NOT_IMPL; @@ -191,7 +199,7 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) { res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t*)path); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_create(fs, obj_id, (const u8_t*)path, SPIFFS_TYPE_FILE, 0); + res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, 0); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); SPIFFS_UNLOCK(fs); return 0; @@ -199,6 +207,7 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) { } spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_DBG("%s '%s' "_SPIPRIfl "\n", __func__, path, flags); (void)mode; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -243,7 +252,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_create(fs, obj_id, (const u8_t*)path, SPIFFS_TYPE_FILE, &pix); + res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, &pix); if (res < SPIFFS_OK) { spiffs_fd_return(fs, fd->file_nbr); } @@ -279,6 +288,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs } spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_DBG("%s '%s':"_SPIPRIid " "_SPIPRIfl "\n", __func__, e->name, e->obj_id, flags); SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -311,6 +321,7 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl } spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_DBG("%s "_SPIPRIpg " "_SPIPRIfl "\n", __func__, page_ix, flags); SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -356,7 +367,7 @@ spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags return SPIFFS_FH_OFFS(fs, fd->file_nbr); } -s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { +static s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -410,6 +421,16 @@ s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { return len; } +s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len); + s32_t res = spiffs_hydro_read(fs, fh, buf, len); + if (res == SPIFFS_ERR_END_OF_OBJECT) { + res = 0; + } + return res; +} + + #if !SPIFFS_READ_ONLY static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) { (void)fs; @@ -435,6 +456,7 @@ static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offs #endif // !SPIFFS_READ_ONLY s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len); #if SPIFFS_READ_ONLY (void)fs; (void)fh; (void)buf; (void)len; return SPIFFS_ERR_RO_NOT_IMPL; @@ -459,7 +481,6 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { if ((fd->flags & SPIFFS_O_APPEND)) { fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size; } - offset = fd->fdoffset; #if SPIFFS_CACHE_WR @@ -493,7 +514,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page { // boundary violation, write back cache first and allocate new - SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, boundary viol, offs:%i size:%i\n", + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", boundary viol, offs:"_SPIPRIi" size:"_SPIPRIi"\n", fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); res = spiffs_hydro_write(fs, fd, spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), @@ -511,19 +532,30 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { if (fd->cache_page) { fd->cache_page->offset = offset; fd->cache_page->size = 0; - SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page %i for fd %i:%04x\n", + SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid"\n", fd->cache_page->ix, fd->file_nbr, fd->obj_id); } } if (fd->cache_page) { u32_t offset_in_cpage = offset - fd->cache_page->offset; - SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page %i for fd %i:%04x, offs %i:%i len %i\n", + SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", offs "_SPIPRIi":"_SPIPRIi" len "_SPIPRIi"\n", fd->cache_page->ix, fd->file_nbr, fd->obj_id, offset, offset_in_cpage, len); spiffs_cache *cache = spiffs_get_cache(fs); u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix); - memcpy(&cpage_data[offset_in_cpage], buf, len); +#ifdef _SPIFFS_TEST + { + intptr_t __a1 = (u8_t*)&cpage_data[offset_in_cpage]-(u8_t*)cache; + intptr_t __a2 = (u8_t*)&cpage_data[offset_in_cpage]+len-(u8_t*)cache; + intptr_t __b = sizeof(spiffs_cache) + cache->cpage_count * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs)); + if (__a1 > __b || __a2 > __b) { + printf("FATAL OOB: CACHE_WR: memcpy to cache buffer ixs:%4ld..%4ld of %4ld\n", __a1, __a2, __b); + ERREXIT(); + } + } +#endif + _SPIFFS_MEMCPY(&cpage_data[offset_in_cpage], buf, len); fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len); fd->fdoffset += len; SPIFFS_UNLOCK(fs); @@ -539,7 +571,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { // big write, no need to cache it - but first check if there is a cached write already if (fd->cache_page) { // write back cache first - SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, big write, offs:%i size:%i\n", + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", big write, offs:"_SPIPRIi" size:"_SPIPRIi"\n", fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); res = spiffs_hydro_write(fs, fd, spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), @@ -563,6 +595,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { } s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " %s\n", __func__, fh, offs, (const char* []){"SET","CUR","END","???"}[MIN(whence,3)]); SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -577,21 +610,26 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { spiffs_fflush_cache(fs, fh); #endif + s32_t file_size = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size; + switch (whence) { case SPIFFS_SEEK_CUR: offs = fd->fdoffset+offs; break; case SPIFFS_SEEK_END: - offs = (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size) + offs; + offs = file_size + offs; break; } - - if ((offs > (s32_t)fd->size) && (SPIFFS_UNDEFINED_LEN != fd->size)) { + if (offs < 0) { + SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_SEEK_BOUNDS); + } + if (offs > file_size) { + fd->fdoffset = file_size; res = SPIFFS_ERR_END_OF_OBJECT; } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - spiffs_span_ix data_spix = offs / SPIFFS_DATA_PAGE_SIZE(fs); + spiffs_span_ix data_spix = (offs > 0 ? (offs-1) : 0) / SPIFFS_DATA_PAGE_SIZE(fs); spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix); if (fd->cursor_objix_spix != objix_spix) { spiffs_page_ix pix; @@ -609,6 +647,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { } s32_t SPIFFS_remove(spiffs *fs, const char *path) { + SPIFFS_API_DBG("%s '%s'\n", __func__, path); #if SPIFFS_READ_ONLY (void)fs; (void)path; return SPIFFS_ERR_RO_NOT_IMPL; @@ -651,6 +690,7 @@ s32_t SPIFFS_remove(spiffs *fs, const char *path) { } s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); #if SPIFFS_READ_ONLY (void)fs; (void)fh; return SPIFFS_ERR_RO_NOT_IMPL; @@ -703,11 +743,15 @@ static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spi s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; s->pix = pix; strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN); +#if SPIFFS_OBJ_META_LEN + _SPIFFS_MEMCPY(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN); +#endif return res; } s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) { + SPIFFS_API_DBG("%s '%s'\n", __func__, path); SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { @@ -729,6 +773,7 @@ s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) { } s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -770,7 +815,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd); } if (fd->cache_page) { - SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, flush, offs:%i size:%i\n", + SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", flush, offs:"_SPIPRIi" size:"_SPIPRIi"\n", fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size); res = spiffs_hydro_write(fs, fd, spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), @@ -788,6 +833,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { #endif s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); (void)fh; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -804,6 +850,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -824,6 +871,7 @@ s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) { + SPIFFS_API_DBG("%s %s %s\n", __func__, old_path, new_path); #if SPIFFS_READ_ONLY (void)fs; (void)old_path; (void)new_path; return SPIFFS_ERR_RO_NOT_IMPL; @@ -860,7 +908,7 @@ s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) { SPIFFS_API_CHECK_RES_UNLOCK(fs, res); res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t*)new_path, - 0, &pix_dummy); + 0, 0, &pix_dummy); #if SPIFFS_TEMPORAL_FD_CACHE if (res == SPIFFS_OK) { spiffs_fd_temporal_cache_rehash(fs, old_path, new_path); @@ -877,7 +925,80 @@ s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) { #endif // SPIFFS_READ_ONLY } +#if SPIFFS_OBJ_META_LEN +s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta) { +#if SPIFFS_READ_ONLY + (void)fs; (void)name; (void)meta; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_page_ix pix, pix_dummy; + spiffs_fd *fd; + + s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)name, &pix); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_fd_find_new(fs, &fd, 0); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_open_by_page(fs, pix, fd, 0, 0); + if (res != SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta, + 0, &pix_dummy); + + spiffs_fd_return(fs, fd->file_nbr); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +#endif // SPIFFS_READ_ONLY +} + +s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) { +#if SPIFFS_READ_ONLY + (void)fs; (void)fh; (void)meta; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + s32_t res; + spiffs_fd *fd; + spiffs_page_ix pix_dummy; + + fh = SPIFFS_FH_UNOFFS(fs, fh); + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if ((fd->flags & SPIFFS_O_WRONLY) == 0) { + res = SPIFFS_ERR_NOT_WRITABLE; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta, + 0, &pix_dummy); + + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +#endif // SPIFFS_READ_ONLY +} +#endif // SPIFFS_OBJ_META_LEN + spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) { + SPIFFS_API_DBG("%s\n", __func__); (void)name; if (!SPIFFS_CHECK_CFG((fs))) { @@ -925,12 +1046,16 @@ static s32_t spiffs_read_dir_v( e->type = objix_hdr.type; e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; e->pix = pix; +#if SPIFFS_OBJ_META_LEN + _SPIFFS_MEMCPY(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN); +#endif return SPIFFS_OK; } return SPIFFS_VIS_COUNTINUE; } struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { + SPIFFS_API_DBG("%s\n", __func__); if (!SPIFFS_CHECK_MOUNT(d->fs)) { d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return 0; @@ -955,6 +1080,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { if (res == SPIFFS_OK) { d->block = bix; d->entry = entry + 1; + e->obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG; ret = e; } else { d->fs->err_code = res; @@ -964,12 +1090,14 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { } s32_t SPIFFS_closedir(spiffs_DIR *d) { + SPIFFS_API_DBG("%s\n", __func__); SPIFFS_API_CHECK_CFG(d->fs); SPIFFS_API_CHECK_MOUNT(d->fs); return 0; } s32_t SPIFFS_check(spiffs *fs) { + SPIFFS_API_DBG("%s\n", __func__); #if SPIFFS_READ_ONLY (void)fs; return SPIFFS_ERR_RO_NOT_IMPL; @@ -993,6 +1121,7 @@ s32_t SPIFFS_check(spiffs *fs) { } s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { + SPIFFS_API_DBG("%s\n", __func__); s32_t res = SPIFFS_OK; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -1017,6 +1146,7 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { } s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) { + SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, max_free_pages); #if SPIFFS_READ_ONLY (void)fs; (void)max_free_pages; return SPIFFS_ERR_RO_NOT_IMPL; @@ -1036,6 +1166,7 @@ s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) { s32_t SPIFFS_gc(spiffs *fs, u32_t size) { + SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, size); #if SPIFFS_READ_ONLY (void)fs; (void)size; return SPIFFS_ERR_RO_NOT_IMPL; @@ -1054,6 +1185,7 @@ s32_t SPIFFS_gc(spiffs *fs, u32_t size) { } s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); s32_t res; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -1077,6 +1209,7 @@ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); s32_t res; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -1100,6 +1233,7 @@ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) { + SPIFFS_API_DBG("%s\n", __func__); SPIFFS_LOCK(fs); fs->file_cb_f = cb_func; SPIFFS_UNLOCK(fs); @@ -1110,6 +1244,7 @@ s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) { s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map, u32_t offset, u32_t len, spiffs_page_ix *map_buf) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " "_SPIPRIi "\n", __func__, fh, offset, len); s32_t res; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -1142,6 +1277,7 @@ s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map, } s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh) { + SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh); s32_t res; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -1164,6 +1300,7 @@ s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh) { } s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) { + SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, offset); s32_t res = SPIFFS_OK; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -1263,7 +1400,7 @@ s32_t SPIFFS_vis(spiffs *fs) { cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) { spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset]; if (cur_entry == 0) { - spiffs_printf("%4i ", bix); + spiffs_printf(_SPIPRIbl" ", bix); } else if ((cur_entry & 0x3f) == 0) { spiffs_printf(" "); } @@ -1291,7 +1428,7 @@ s32_t SPIFFS_vis(spiffs *fs) { SPIFFS_CHECK_RES(res); if (erase_count != (spiffs_obj_id)-1) { - spiffs_printf("\tera_cnt: %i\n", erase_count); + spiffs_printf("\tera_cnt: "_SPIPRIi"\n", erase_count); } else { spiffs_printf("\tera_cnt: N/A\n"); } @@ -1299,16 +1436,16 @@ s32_t SPIFFS_vis(spiffs *fs) { bix++; } // per block - spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count); - spiffs_printf("last_errno: %i\n", fs->err_code); - spiffs_printf("blocks: %i\n", fs->block_count); - spiffs_printf("free_blocks: %i\n", fs->free_blocks); - spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated); - spiffs_printf("page_delet: %i\n", fs->stats_p_deleted); + spiffs_printf("era_cnt_max: "_SPIPRIi"\n", fs->max_erase_count); + spiffs_printf("last_errno: "_SPIPRIi"\n", fs->err_code); + spiffs_printf("blocks: "_SPIPRIi"\n", fs->block_count); + spiffs_printf("free_blocks: "_SPIPRIi"\n", fs->free_blocks); + spiffs_printf("page_alloc: "_SPIPRIi"\n", fs->stats_p_allocated); + spiffs_printf("page_delet: "_SPIPRIi"\n", fs->stats_p_deleted); SPIFFS_UNLOCK(fs); u32_t total, used; SPIFFS_info(fs, &total, &used); - spiffs_printf("used: %i of %i\n", used, total); + spiffs_printf("used: "_SPIPRIi" of "_SPIPRIi"\n", used, total); return res; } #endif diff --git a/Sming/third-party/spiffs/src/spiffs_nucleus.c b/Sming/third-party/spiffs/src/spiffs_nucleus.c index 35fe0d46c5..27ecdff2a6 100644 --- a/Sming/third-party/spiffs/src/spiffs_nucleus.c +++ b/Sming/third-party/spiffs/src/spiffs_nucleus.c @@ -232,7 +232,7 @@ s32_t spiffs_erase_block( // here we ignore res, just try erasing the block while (size > 0) { - SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + SPIFFS_DBG("erase "_SPIPRIad":"_SPIPRIi"\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); @@ -270,7 +270,7 @@ s32_t spiffs_probe( s32_t res; u32_t paddr; spiffs dummy_fs; // create a dummy fs struct just to be able to use macros - memcpy(&dummy_fs.cfg, cfg, sizeof(spiffs_config)); + _SPIFFS_MEMCPY(&dummy_fs.cfg, cfg, sizeof(spiffs_config)); dummy_fs.block_count = 0; // Read three magics, as one block may be in an aborted erase state. @@ -407,7 +407,7 @@ s32_t spiffs_obj_lu_scan( #if SPIFFS_USE_MAGIC if (unerased_bix != (spiffs_block_ix)-1) { // found one unerased block, remedy - SPIFFS_DBG("mount: erase block %i\n", bix); + SPIFFS_DBG("mount: erase block "_SPIPRIbl"\n", bix); #if SPIFFS_READ_ONLY res = SPIFFS_ERR_RO_ABORTED_OPERATION; #else @@ -645,7 +645,7 @@ static void spiffs_update_ix_map(spiffs *fs, } map->map_buf[map_spix - map->start_spix] = objix_data_pix; - SPIFFS_DBG("map %04x:%04x (%04x--%04x) objix.spix:%04x to pix %04x\n", + SPIFFS_DBG("map "_SPIPRIid":"_SPIPRIsp" ("_SPIPRIsp"--"_SPIPRIsp") objix.spix:"_SPIPRIsp" to pix "_SPIPRIpg"\n", fd->obj_id, map_spix - map->start_spix, map->start_spix, map->end_spix, objix->p_hdr.span_ix, @@ -696,7 +696,7 @@ static s32_t spiffs_populate_ix_map_v( spiffs_update_ix_map(fs, state->fd, objix->p_hdr.span_ix, objix); state->remaining_objix_pages_to_visit--; - SPIFFS_DBG("map %04x (%04x--%04x) remaining objix pages %i\n", + SPIFFS_DBG("map "_SPIPRIid" ("_SPIPRIsp"--"_SPIPRIsp") remaining objix pages "_SPIPRIi"\n", state->fd->obj_id, state->fd->ix_map->start_spix, state->fd->ix_map->end_spix, state->remaining_objix_pages_to_visit); @@ -713,8 +713,8 @@ s32_t spiffs_populate_ix_map(spiffs *fs, spiffs_fd *fd, u32_t vec_entry_start, u s32_t res; spiffs_ix_map *map = fd->ix_map; spiffs_ix_map_populate_state state; - vec_entry_start = MIN((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_start); - vec_entry_end = MAX((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_end); + vec_entry_start = MIN((u32_t)(map->end_spix - map->start_spix), vec_entry_start); + vec_entry_end = MAX((u32_t)(map->end_spix - map->start_spix), vec_entry_end); if (vec_entry_start > vec_entry_end) { return SPIFFS_ERR_IX_MAP_BAD_RANGE; } @@ -907,7 +907,8 @@ s32_t spiffs_page_delete( s32_t spiffs_object_create( spiffs *fs, spiffs_obj_id obj_id, - const u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[], + const u8_t meta[], spiffs_obj_type type, spiffs_page_ix *objix_hdr_pix) { s32_t res = SPIFFS_OK; @@ -923,7 +924,7 @@ s32_t spiffs_object_create( // find free entry res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry); SPIFFS_CHECK_RES(res); - SPIFFS_DBG("create: found free page @ %04x bix:%i entry:%i\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry); + SPIFFS_DBG("create: found free page @ "_SPIPRIpg" bix:"_SPIPRIbl" entry:"_SPIPRIsp"\n", (spiffs_page_ix)SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry); // occupy page in object lookup res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT, @@ -938,8 +939,16 @@ s32_t spiffs_object_create( oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED); oix_hdr.type = type; oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page - strncpy((char*)&oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN); - + strncpy((char*)oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN); +#if SPIFFS_OBJ_META_LEN + if (meta) { + _SPIFFS_MEMCPY(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN); + } else { + memset(oix_hdr.meta, 0xff, SPIFFS_OBJ_META_LEN); + } +#else + (void) meta; +#endif // update page res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, @@ -968,7 +977,8 @@ s32_t spiffs_object_update_index_hdr( spiffs_obj_id obj_id, spiffs_page_ix objix_hdr_pix, u8_t *new_objix_hdr_data, - const u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[], + const u8_t meta[], u32_t size, spiffs_page_ix *new_pix) { s32_t res = SPIFFS_OK; @@ -994,6 +1004,13 @@ s32_t spiffs_object_update_index_hdr( if (name) { strncpy((char*)objix_hdr->name, (const char*)name, SPIFFS_OBJ_NAME_LEN); } +#if SPIFFS_OBJ_META_LEN + if (meta) { + _SPIFFS_MEMCPY(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN); + } +#else + (void) meta; +#endif if (size) { objix_hdr->size = size; } @@ -1031,34 +1048,66 @@ void spiffs_cb_object_event( spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG; u32_t i; spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + SPIFFS_DBG(" CALLBACK %s obj_id:"_SPIPRIid" spix:"_SPIPRIsp" npix:"_SPIPRIpg" nsz:"_SPIPRIi"\n", (const char *[]){"UPD", "NEW", "DEL", "MOV", "HUP","???"}[MIN(ev,5)], + obj_id_raw, spix, new_pix, new_size); for (i = 0; i < fs->fd_count; i++) { spiffs_fd *cur_fd = &fds[i]; -#if SPIFFS_TEMPORAL_FD_CACHE - if (cur_fd->score == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; -#else - if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; + if ((cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; // fd not related to updated file +#if !SPIFFS_TEMPORAL_FD_CACHE + if (cur_fd->file_nbr == 0) continue; // fd closed #endif - if (spix == 0) { + if (spix == 0) { // object index header update if (ev != SPIFFS_EV_IX_DEL) { - SPIFFS_DBG(" callback: setting fd %i:%04x objix_hdr_pix to %04x, size:%i\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size); +#if SPIFFS_TEMPORAL_FD_CACHE + if (cur_fd->score == 0) continue; // never used fd +#endif + SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid"(fdoffs:"_SPIPRIi" offs:"_SPIPRIi") objix_hdr_pix to "_SPIPRIpg", size:"_SPIPRIi"\n", + SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, cur_fd->fdoffset, cur_fd->offset, new_pix, new_size); cur_fd->objix_hdr_pix = new_pix; if (new_size != 0) { + // update size and offsets for fds to this file cur_fd->size = new_size; + u32_t act_new_size = new_size == SPIFFS_UNDEFINED_LEN ? 0 : new_size; +#if SPIFFS_CACHE_WR + if (act_new_size > 0 && cur_fd->cache_page) { + act_new_size = MAX(act_new_size, cur_fd->cache_page->offset + cur_fd->cache_page->size); + } +#endif + if (cur_fd->offset > act_new_size) { + cur_fd->offset = act_new_size; + } + if (cur_fd->fdoffset > act_new_size) { + cur_fd->fdoffset = act_new_size; + } +#if SPIFFS_CACHE_WR + if (cur_fd->cache_page && cur_fd->cache_page->offset > act_new_size+1) { + SPIFFS_CACHE_DBG("CACHE_DROP: file trunced, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix); + spiffs_cache_fd_release(fs, cur_fd->cache_page); + } +#endif } } else { + // removing file +#if SPIFFS_CACHE_WR + if (cur_fd->file_nbr && cur_fd->cache_page) { + SPIFFS_CACHE_DBG("CACHE_DROP: file deleted, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix); + spiffs_cache_fd_release(fs, cur_fd->cache_page); + } +#endif + SPIFFS_DBG(" callback: release fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix, new_pix); cur_fd->file_nbr = 0; cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED; } - } + } // object index header update if (cur_fd->cursor_objix_spix == spix) { if (ev != SPIFFS_EV_IX_DEL) { - SPIFFS_DBG(" callback: setting fd %i:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix); + SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix, new_pix); cur_fd->cursor_objix_pix = new_pix; } else { cur_fd->cursor_objix_pix = 0; } } - } + } // fd update loop #if SPIFFS_IX_MAP @@ -1070,7 +1119,7 @@ void spiffs_cb_object_event( if (cur_fd->file_nbr == 0 || cur_fd->ix_map == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; - SPIFFS_DBG(" callback: map ix update fd %i:%04x span:%04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix); + SPIFFS_DBG(" callback: map ix update fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix); spiffs_update_ix_map(fs, cur_fd, spix, objix); } } @@ -1089,7 +1138,7 @@ void spiffs_cb_object_event( } else if (ev == SPIFFS_EV_IX_DEL) { op = SPIFFS_CB_DELETED; } else { - SPIFFS_DBG(" callback: WARNING unknown callback event %02x\n", ev); + SPIFFS_DBG(" callback: WARNING unknown callback event "_SPIPRIi"\n", ev); return; // bail out } fs->file_cb_f(fs, op, obj_id, new_pix); @@ -1147,7 +1196,7 @@ s32_t spiffs_object_open_by_page( SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0); - SPIFFS_DBG("open: fd %i is obj id %04x\n", fd->file_nbr, fd->obj_id); + SPIFFS_DBG("open: fd "_SPIPRIfd" is obj id "_SPIPRIid"\n", SPIFFS_FH_OFFS(fs, fd->file_nbr), fd->obj_id); return res; } @@ -1160,7 +1209,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { s32_t res = SPIFFS_OK; u32_t written = 0; - SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size); + SPIFFS_DBG("append: "_SPIPRIi" bytes @ offs "_SPIPRIi" of size "_SPIPRIi"\n", len, offset, fd->size); if (offset > fd->size) { SPIFFS_DBG("append: offset reversed to size\n"); @@ -1169,7 +1218,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta if (res != SPIFFS_OK) { - SPIFFS_DBG("append: gc check fail %i\n", res); + SPIFFS_DBG("append: gc check fail "_SPIPRIi"\n", res); } SPIFFS_CHECK_RES(res); @@ -1197,7 +1246,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { // within this clause we return directly if something fails, object index mess-up if (written > 0) { // store previous object index page, unless first pass - SPIFFS_DBG("append: %04x store objix %04x:%04x, written %i\n", fd->obj_id, + SPIFFS_DBG("append: "_SPIPRIid" store objix "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, cur_objix_pix, prev_objix_spix, written); if (prev_objix_spix == 0) { // this is an update to object index header page @@ -1212,9 +1261,9 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { } else { // was a nonempty object, update to new page res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page); + fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page); SPIFFS_CHECK_RES(res); - SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %i\n", fd->obj_id, + SPIFFS_DBG("append: "_SPIPRIid" store new objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, new_objix_hdr_page, 0, written); } } else { @@ -1229,9 +1278,9 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { SPIFFS_EV_IX_UPD,fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0); // update length in object index header page res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page); + fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page); SPIFFS_CHECK_RES(res); - SPIFFS_DBG("append: %04x store new size I %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id, + SPIFFS_DBG("append: "_SPIPRIid" store new size I "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, offset+written, new_objix_hdr_page, 0, written); } fd->size = offset+written; @@ -1241,7 +1290,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { // create or load new object index page if (cur_objix_spix == 0) { // load object index header page, must always exist - SPIFFS_DBG("append: %04x load objixhdr page %04x:%04x\n", fd->obj_id, cur_objix_pix, cur_objix_spix); + SPIFFS_DBG("append: "_SPIPRIid" load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", fd->obj_id, cur_objix_pix, cur_objix_spix); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -1258,22 +1307,22 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { SPIFFS_CHECK_RES(res); // quick "load" of new object index page memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); - memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header)); + _SPIFFS_MEMCPY(fs->work, &p_hdr, sizeof(spiffs_page_header)); spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work, SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0); - SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %i\n", fd->obj_id + SPIFFS_DBG("append: "_SPIPRIid" create objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id , cur_objix_pix, cur_objix_spix, written); } else { // on first pass, we load existing object index page spiffs_page_ix pix; - SPIFFS_DBG("append: %04x find objix span_ix:%04x\n", fd->obj_id, cur_objix_spix); + SPIFFS_DBG("append: "_SPIPRIid" find objix span_ix:"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix); if (fd->cursor_objix_spix == cur_objix_spix) { pix = fd->cursor_objix_pix; } else { res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); SPIFFS_CHECK_RES(res); } - SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\n", fd->obj_id, pix, fd->size); + SPIFFS_DBG("append: "_SPIPRIid" found object index at page "_SPIPRIpg" [fd size "_SPIPRIi"]\n", fd->obj_id, pix, fd->size); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -1297,7 +1346,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, &p_hdr, &data[written], to_write, page_offs, 1, &data_page); - SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id, + SPIFFS_DBG("append: "_SPIPRIid" store new data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id, data_page, data_spix, page_offs, to_write, written); } else { // append to existing page, fill out free data in existing page @@ -1314,7 +1363,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]); - SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id + SPIFFS_DBG("append: "_SPIPRIid" store to existing data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id , data_page, data_spix, page_offs, to_write, written); } @@ -1324,14 +1373,14 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { if (cur_objix_spix == 0) { // update object index header page ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page; - SPIFFS_DBG("append: %04x wrote page %04x to objix_hdr entry %02x in mem\n", fd->obj_id + SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", fd->obj_id , data_page, data_spix); objix_hdr->size = offset+written; } else { // update object index page ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page; - SPIFFS_DBG("append: %04x wrote page %04x to objix entry %02x in mem\n", fd->obj_id - , data_page, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", fd->obj_id + , data_page, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); } // update internals @@ -1350,7 +1399,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { if (cur_objix_spix != 0) { // wrote beyond object index header page // write last modified object index page, unless object header index page - SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %i\n", fd->obj_id, + SPIFFS_DBG("append: "_SPIPRIid" store objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id, cur_objix_pix, cur_objix_spix, written); res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); @@ -1364,8 +1413,8 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { // update size in object header index page res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page); - SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id + fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_DBG("append: "_SPIPRIid" store new size II "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi", res "_SPIPRIi"\n", fd->obj_id , offset+written, new_objix_hdr_page, 0, written, res2); SPIFFS_CHECK_RES(res2); } else { @@ -1373,7 +1422,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { if (offset == 0) { // wrote to empty object - simply update size and write whole page objix_hdr->size = offset+written; - SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %i\n", fd->obj_id + SPIFFS_DBG("append: "_SPIPRIid" store fresh objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id , cur_objix_pix, cur_objix_spix, written); res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix); @@ -1388,8 +1437,8 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { } else { // modifying object index header page, update size and make new copy res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page); - SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %i\n", fd->obj_id + fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page); + SPIFFS_DBG("append: "_SPIPRIid" store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id , new_objix_hdr_page, 0, written); SPIFFS_CHECK_RES(res2); } @@ -1438,8 +1487,8 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { if (prev_objix_spix == 0) { // store previous object index header page res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix); - SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written); + fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix); + SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written); SPIFFS_CHECK_RES(res); } else { // store new version of previous object index page @@ -1449,7 +1498,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { SPIFFS_CHECK_RES(res); res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix); - SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %i\n", new_objix_pix, objix->p_hdr.span_ix, written); + SPIFFS_DBG("modify: store previous modified objix page, "_SPIPRIid":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, objix->p_hdr.span_ix, written); SPIFFS_CHECK_RES(res); spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); @@ -1459,7 +1508,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { // load next object index page if (cur_objix_spix == 0) { // load object index header page, must exist - SPIFFS_DBG("modify: load objixhdr page %04x:%04x\n", cur_objix_pix, cur_objix_spix); + SPIFFS_DBG("modify: load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", cur_objix_pix, cur_objix_spix); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -1467,14 +1516,14 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { } else { // load existing object index page on first pass spiffs_page_ix pix; - SPIFFS_DBG("modify: find objix span_ix:%04x\n", cur_objix_spix); + SPIFFS_DBG("modify: find objix span_ix:"_SPIPRIsp"\n", cur_objix_spix); if (fd->cursor_objix_spix == cur_objix_spix) { pix = fd->cursor_objix_pix; } else { res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix); SPIFFS_CHECK_RES(res); } - SPIFFS_DBG("modify: found object index at page %04x\n", pix); + SPIFFS_DBG("modify: found object index at page "_SPIPRIpg"\n", pix); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -1505,7 +1554,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { // a full page, allocate and write a new page of data res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, &p_hdr, &data[written], to_write, page_offs, 1, &data_pix); - SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%i, len %i, written %i\n", data_pix, data_spix, page_offs, to_write, written); + SPIFFS_DBG("modify: store new data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", data_pix, data_spix, page_offs, to_write, written); } else { // write to existing page, allocate new and copy unmodified data @@ -1546,7 +1595,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { (u8_t *)&p_hdr.flags); if (res != SPIFFS_OK) break; - SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%i, len %i, written %i\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written); + SPIFFS_DBG("modify: store to existing data page, src:"_SPIPRIpg", dst:"_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written); } // delete original data page @@ -1556,11 +1605,11 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { if (cur_objix_spix == 0) { // update object index header page ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix; - SPIFFS_DBG("modify: wrote page %04x to objix_hdr entry %02x in mem\n", data_pix, data_spix); + SPIFFS_DBG("modify: wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", data_pix, data_spix); } else { // update object index page ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix; - SPIFFS_DBG("modify: wrote page %04x to objix entry %02x in mem\n", data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + SPIFFS_DBG("modify: wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); } // update internals @@ -1585,7 +1634,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { SPIFFS_CHECK_RES(res2); res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix); - SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %i\n", new_objix_pix, cur_objix_spix, written); + SPIFFS_DBG("modify: store modified objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, cur_objix_spix, written); fd->cursor_objix_pix = new_objix_pix; fd->cursor_objix_spix = cur_objix_spix; SPIFFS_CHECK_RES(res2); @@ -1595,8 +1644,8 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { } else { // wrote within object index header page res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix); - SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written); + fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix); + SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written); SPIFFS_CHECK_RES(res2); } @@ -1716,7 +1765,7 @@ s32_t spiffs_object_truncate( if (prev_objix_spix != cur_objix_spix) { if (prev_objix_spix != (spiffs_span_ix)-1) { // remove previous object index page - SPIFFS_DBG("truncate: delete objix page %04x:%04x\n", objix_pix, prev_objix_spix); + SPIFFS_DBG("truncate: delete objix page "_SPIPRIpg":"_SPIPRIsp"\n", objix_pix, prev_objix_spix); res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix); SPIFFS_CHECK_RES(res); @@ -1733,9 +1782,9 @@ s32_t spiffs_object_truncate( // Hence, take the risk - if aborted, a file check would free the lost pages and mend things // as the file is marked as fully deleted in the beginning. if (remove_full == 0) { - SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %i\n", fd->objix_hdr_pix, prev_objix_spix, cur_size); + SPIFFS_DBG("truncate: update objix hdr page "_SPIPRIpg":"_SPIPRIsp" to size "_SPIPRIi"\n", fd->objix_hdr_pix, prev_objix_spix, cur_size); res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix); + fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix); SPIFFS_CHECK_RES(res); } fd->size = cur_size; @@ -1749,7 +1798,7 @@ s32_t spiffs_object_truncate( SPIFFS_CHECK_RES(res); } - SPIFFS_DBG("truncate: load objix page %04x:%04x for data spix:%04x\n", objix_pix, cur_objix_spix, data_spix); + SPIFFS_DBG("truncate: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -1771,20 +1820,20 @@ s32_t spiffs_object_truncate( ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE; } - SPIFFS_DBG("truncate: got data pix %04x\n", data_pix); + SPIFFS_DBG("truncate: got data pix "_SPIPRIpg"\n", data_pix); if (new_size == 0 || remove_full || cur_size - new_size >= SPIFFS_DATA_PAGE_SIZE(fs)) { // delete full data page res = spiffs_page_data_check(fs, fd, data_pix, data_spix); if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) { - SPIFFS_DBG("truncate: err validating data pix %i\n", res); + SPIFFS_DBG("truncate: err validating data pix "_SPIPRIi"\n", res); break; } if (res == SPIFFS_OK) { res = spiffs_page_delete(fs, data_pix); if (res != SPIFFS_OK) { - SPIFFS_DBG("truncate: err deleting data pix %i\n", res); + SPIFFS_DBG("truncate: err deleting data pix "_SPIPRIi"\n", res); break; } } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) { @@ -1799,13 +1848,13 @@ s32_t spiffs_object_truncate( } fd->size = cur_size; fd->offset = cur_size; - SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%i\n", data_pix, data_spix, cur_size); + SPIFFS_DBG("truncate: delete data page "_SPIPRIpg" for data spix:"_SPIPRIsp", cur_size:"_SPIPRIi"\n", data_pix, data_spix, cur_size); } else { // delete last page, partially spiffs_page_header p_hdr; spiffs_page_ix new_data_pix; u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs)); - SPIFFS_DBG("truncate: delete %i bytes from data page %04x for data spix:%04x, cur_size:%i\n", bytes_to_remove, data_pix, data_spix, cur_size); + SPIFFS_DBG("truncate: delete "_SPIPRIi" bytes from data page "_SPIPRIpg" for data spix:"_SPIPRIsp", cur_size:"_SPIPRIi"\n", bytes_to_remove, data_pix, data_spix, cur_size); res = spiffs_page_data_check(fs, fd, data_pix, data_spix); if (res != SPIFFS_OK) break; @@ -1837,11 +1886,11 @@ s32_t spiffs_object_truncate( if (cur_objix_spix == 0) { // update object index header page ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix; - SPIFFS_DBG("truncate: wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + SPIFFS_DBG("truncate: wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); } else { // update object index page ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix; - SPIFFS_DBG("truncate: wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); + SPIFFS_DBG("truncate: wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix)); } cur_size = new_size; fd->size = new_size; @@ -1857,7 +1906,7 @@ s32_t spiffs_object_truncate( if (cur_size == 0) { if (remove_full) { // remove object altogether - SPIFFS_DBG("truncate: remove object index header page %04x\n", objix_pix); + SPIFFS_DBG("truncate: remove object index header page "_SPIPRIpg"\n", objix_pix); res = spiffs_page_index_check(fs, fd, objix_pix, 0); SPIFFS_CHECK_RES(res); @@ -1868,18 +1917,18 @@ s32_t spiffs_object_truncate( SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0); } else { // make uninitialized object - SPIFFS_DBG("truncate: reset objix_hdr page %04x\n", objix_pix); + SPIFFS_DBG("truncate: reset objix_hdr page "_SPIPRIpg"\n", objix_pix); memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header)); res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - objix_pix, fs->work, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix); + objix_pix, fs->work, 0, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix); SPIFFS_CHECK_RES(res); } } else { // update object index header page SPIFFS_DBG("truncate: update object index header page with indices and size\n"); res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - objix_pix, fs->work, 0, cur_size, &new_objix_hdr_pix); + objix_pix, fs->work, 0, 0, cur_size, &new_objix_hdr_pix); SPIFFS_CHECK_RES(res); } } else { @@ -1894,13 +1943,13 @@ s32_t spiffs_object_truncate( SPIFFS_CHECK_RES(res); spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0); - SPIFFS_DBG("truncate: store modified objix page, %04x:%04x\n", new_objix_pix, cur_objix_spix); + SPIFFS_DBG("truncate: store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, cur_objix_spix); fd->cursor_objix_pix = new_objix_pix; fd->cursor_objix_spix = cur_objix_spix; fd->offset = cur_size; // update object index header page with new size res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix); + fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix); SPIFFS_CHECK_RES(res); } fd->size = cur_size; @@ -1940,7 +1989,7 @@ s32_t spiffs_object_read( if (cur_objix_spix == 0) { objix_pix = fd->objix_hdr_pix; } else { - SPIFFS_DBG("read: find objix %04x:%04x\n", fd->obj_id, cur_objix_spix); + SPIFFS_DBG("read: find objix "_SPIPRIid":"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix); if (fd->cursor_objix_spix == cur_objix_spix) { objix_pix = fd->cursor_objix_pix; } else { @@ -1948,7 +1997,7 @@ s32_t spiffs_object_read( SPIFFS_CHECK_RES(res); } } - SPIFFS_DBG("read: load objix page %04x:%04x for data spix:%04x\n", objix_pix, cur_objix_spix, data_spix); + SPIFFS_DBG("read: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix); res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work); SPIFFS_CHECK_RES(res); @@ -1977,8 +2026,8 @@ s32_t spiffs_object_read( len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))); // remaining data in file len_to_read = MIN(len_to_read, fd->size); - SPIFFS_DBG("read: offset:%i rd:%i data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix, - SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))); + SPIFFS_DBG("read: offset:"_SPIPRIi" rd:"_SPIPRIi" data spix:"_SPIPRIsp" is data_pix:"_SPIPRIpg" addr:"_SPIPRIad"\n", cur_offset, len_to_read, data_spix, data_pix, + (u32_t)(SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)))); if (len_to_read <= 0) { res = SPIFFS_ERR_END_OF_OBJECT; break; @@ -2064,7 +2113,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id if (id >= state->min_obj_id && id <= state->max_obj_id) { u8_t *map = (u8_t *)fs->work; int ix = (id - state->min_obj_id) / state->compaction; - //SPIFFS_DBG("free_obj_id: add ix %i for id %04x min:%04x max%04x comp:%i\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction); + //SPIFFS_DBG("free_obj_id: add ix "_SPIPRIi" for id "_SPIPRIid" min"_SPIPRIid" max"_SPIPRIid" comp:"_SPIPRIi"\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction); map[ix]++; } } @@ -2092,7 +2141,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8 if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) { // possible to represent in bitmap u32_t i, j; - SPIFFS_DBG("free_obj_id: BITM min:%04x max:%04x\n", state.min_obj_id, state.max_obj_id); + SPIFFS_DBG("free_obj_id: BITM min:"_SPIPRIid" max:"_SPIPRIid"\n", state.min_obj_id, state.max_obj_id); memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, @@ -2137,14 +2186,14 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8 return SPIFFS_ERR_FULL; } - SPIFFS_DBG("free_obj_id: COMP select index:%i min_count:%i min:%04x max:%04x compact:%i\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction); + SPIFFS_DBG("free_obj_id: COMP select index:"_SPIPRIi" min_count:"_SPIPRIi" min:"_SPIPRIid" max:"_SPIPRIid" compact:"_SPIPRIi"\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction); if (min_count == 0) { // no id in this range, skip compacting and use directly *obj_id = min_i * state.compaction + state.min_obj_id; return SPIFFS_OK; } else { - SPIFFS_DBG("free_obj_id: COMP SEL chunk:%04x min:%04x -> %04x\n", state.compaction, state.min_obj_id, state.min_obj_id + min_i * state.compaction); + SPIFFS_DBG("free_obj_id: COMP SEL chunk:"_SPIPRIi" min:"_SPIPRIid" -> "_SPIPRIid"\n", state.compaction, state.min_obj_id, state.min_obj_id + min_i * state.compaction); state.min_obj_id += min_i * state.compaction; state.max_obj_id = state.min_obj_id + state.compaction; // decrease compaction @@ -2157,7 +2206,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8 // in a work memory of log_page_size bytes, we may fit in log_page_size ids // todo what if compaction is > 255 - then we cannot fit it in a byte state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t))); - SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%i\n", state.min_obj_id, state.max_obj_id, state.compaction); + SPIFFS_DBG("free_obj_id: COMP min:"_SPIPRIid" max:"_SPIPRIid" compact:"_SPIPRIi"\n", state.min_obj_id, state.max_obj_id, state.compaction); memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, &state, 0, 0, 0); @@ -2205,7 +2254,7 @@ s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) { } } - // find the free fd with least score + // find the free fd with least score or name match for (i = 0; i < fs->fd_count; i++) { spiffs_fd *cur_fd = &fds[i]; if (cur_fd->file_nbr == 0) { diff --git a/Sming/third-party/spiffs/src/spiffs_nucleus.h b/Sming/third-party/spiffs/src/spiffs_nucleus.h index 0fa1cb3788..dd1c414bc7 100644 --- a/Sming/third-party/spiffs/src/spiffs_nucleus.h +++ b/Sming/third-party/spiffs/src/spiffs_nucleus.h @@ -141,6 +141,22 @@ #define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0) #define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1) + + +#if defined(__GNUC__) || defined(__clang__) + /* For GCC and clang */ +#define SPIFFS_PACKED __attribute__((packed)) +#elif defined(__ICCARM__) || defined(__CC_ARM) + /* For IAR ARM and Keil MDK-ARM compilers */ +#define SPIFFS_PACKED + +#else + /* Unknown compiler */ +#define SPIFFS_PACKED +#endif + + + #if SPIFFS_USE_MAGIC #if !SPIFFS_USE_MAGIC_LENGTH #define SPIFFS_MAGIC(fs, bix) \ @@ -242,6 +258,15 @@ #define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \ ( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) ) +#if SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0) +#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0) +#else +#define SPIFFS_FH_OFFS(fs, fh) (fh) +#define SPIFFS_FH_UNOFFS(fs, fh) (fh) +#endif + + #define SPIFFS_OP_T_OBJ_LU (0<<0) #define SPIFFS_OP_T_OBJ_LU2 (1<<0) #define SPIFFS_OP_T_OBJ_IX (2<<0) @@ -430,7 +455,7 @@ typedef struct { spiffs_span_ix cursor_objix_spix; // current absolute offset u32_t offset; - // current file descriptor offset + // current file descriptor offset (cached) u32_t fdoffset; // fd flags spiffs_flags flags; @@ -455,7 +480,7 @@ typedef struct { // page header, part of each page except object lookup pages // NB: this is always aligned when the data page is an object index, // as in this case struct spiffs_page_object_ix is used -typedef struct __attribute(( packed )) { +typedef struct SPIFFS_PACKED { // object id spiffs_obj_id obj_id; // object span index @@ -465,7 +490,7 @@ typedef struct __attribute(( packed )) { } spiffs_page_header; // object index header page header -typedef struct __attribute(( packed )) +typedef struct SPIFFS_PACKED #if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES __attribute(( aligned(sizeof(spiffs_page_ix)) )) #endif @@ -480,10 +505,14 @@ typedef struct __attribute(( packed )) spiffs_obj_type type; // name of object u8_t name[SPIFFS_OBJ_NAME_LEN]; +#if SPIFFS_OBJ_META_LEN + // metadata. not interpreted by SPIFFS in any way. + u8_t meta[SPIFFS_OBJ_META_LEN]; +#endif } spiffs_page_object_ix_header; // object index page header -typedef struct __attribute(( packed )) { +typedef struct SPIFFS_PACKED { spiffs_page_header p_hdr; u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))]; } spiffs_page_object_ix; @@ -634,7 +663,8 @@ s32_t spiffs_page_delete( s32_t spiffs_object_create( spiffs *fs, spiffs_obj_id obj_id, - const u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[], + const u8_t meta[], spiffs_obj_type type, spiffs_page_ix *objix_hdr_pix); @@ -644,7 +674,8 @@ s32_t spiffs_object_update_index_hdr( spiffs_obj_id obj_id, spiffs_page_ix objix_hdr_pix, u8_t *new_objix_hdr_data, - const u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[], + const u8_t meta[], u32_t size, spiffs_page_ix *new_pix); @@ -788,4 +819,24 @@ s32_t spiffs_page_consistency_check( s32_t spiffs_object_index_consistency_check( spiffs *fs); +// memcpy macro, +// checked in test builds, otherwise plain memcpy (unless already defined) +#ifdef _SPIFFS_TEST +#define _SPIFFS_MEMCPY(__d, __s, __l) do { \ + intptr_t __a1 = (intptr_t)((u8_t*)(__s)); \ + intptr_t __a2 = (intptr_t)((u8_t*)(__s)+(__l)); \ + intptr_t __b1 = (intptr_t)((u8_t*)(__d)); \ + intptr_t __b2 = (intptr_t)((u8_t*)(__d)+(__l)); \ + if (__a1 <= __b2 && __b1 <= __a2) { \ + printf("FATAL OVERLAP: memcpy from %lx..%lx to %lx..%lx\n", __a1, __a2, __b1, __b2); \ + ERREXIT(); \ + } \ + memcpy((__d),(__s),(__l)); \ +} while (0) +#else +#ifndef _SPIFFS_MEMCPY +#define _SPIFFS_MEMCPY(__d, __s, __l) do{memcpy((__d),(__s),(__l));}while(0) +#endif +#endif //_SPIFFS_TEST + #endif /* SPIFFS_NUCLEUS_H_ */ diff --git a/Sming/third-party/spiffs/src/test/params_test.h b/Sming/third-party/spiffs/src/test/params_test.h index 0e7710d770..74f553ffaa 100644 --- a/Sming/third-party/spiffs/src/test/params_test.h +++ b/Sming/third-party/spiffs/src/test/params_test.h @@ -67,10 +67,11 @@ extern void test_unlock(struct spiffs_t *fs); #endif // dbg output -#define SPIFFS_DBG(...) //printf(__VA_ARGS__) -#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__) -#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__) -#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__) +#define SPIFFS_DBG(_f, ...) //printf("\x1b[32m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_API_DBG(_f, ...) //printf("\n\x1b[1m\x1b[7m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_GC_DBG(_f, ...) //printf("\x1b[36m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_CACHE_DBG(_f, ...) //printf("\x1b[33m" _f "\x1b[0m", ## __VA_ARGS__) +#define SPIFFS_CHECK_DBG(_f, ...) //printf("\x1b[31m" _f "\x1b[0m", ## __VA_ARGS__) // needed types typedef signed int s32_t; diff --git a/Sming/third-party/spiffs/src/test/test_bugreports.c b/Sming/third-party/spiffs/src/test/test_bugreports.c index 8ea5f7485f..e9b59d18c6 100644 --- a/Sming/third-party/spiffs/src/test/test_bugreports.c +++ b/Sming/third-party/spiffs/src/test/test_bugreports.c @@ -17,6 +17,14 @@ #include #include +/* The follow defines control details of how the fuzzer can exercise the API. If you + * undef any of these, then the fuzzer is less brutal. FOr example, if you undef + * HAVE_REMOVE_OPEN, then the fuzzer will not attempt to remove (or rename) an open file + */ +#define HAVE_REMOVE_OPEN +#define HAVE_MULTIPLE_OPEN +#define NO_FORCE_CHECK + SUITE(bug_tests) static void setup() { _setup_test_only(); @@ -194,7 +202,6 @@ TEST(nodemcu_309) { fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_DIRECT, 0); TEST_CHECK(fd > 0); int i; - spiffs_stat s; res = SPIFFS_OK; u8_t err = 0; for (i = 1; i <= 1280; i++) { @@ -247,7 +254,6 @@ TEST(robert) { sprintf(fname, "test.txt"); fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); TEST_CHECK(fd > 0); - int i; res = SPIFFS_OK; char buf[500]; memset(buf, 0xaa, 500); @@ -345,7 +351,7 @@ TEST(zero_sized_file_44) { u8_t buf[8]; res = SPIFFS_read(FS, fd, buf, 8); - TEST_CHECK_LT(res, 0); + TEST_CHECK_EQ(res, 0); TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_END_OF_OBJECT); res = SPIFFS_read(FS, fd, buf, 0); @@ -373,7 +379,7 @@ TEST(zero_sized_file_44) { TEST_CHECK_EQ(b, 2); res = SPIFFS_read(FS, fd, buf, 8); - TEST_CHECK_LT(res, 0); + TEST_CHECK_EQ(res, 0); TEST_CHECK_EQ(SPIFFS_errno(FS), SPIFFS_ERR_END_OF_OBJECT); return TEST_RES_OK; @@ -542,8 +548,6 @@ TEST(spiffs_dup_file_74) { TEST(temporal_fd_cache) { fs_reset_specific(0, 0, 1024*1024, 4096, 2*4096, 256); - spiffs_file fd; - int res; (FS)->fd_count = 4; char *fcss = "blaha.css"; @@ -574,8 +578,6 @@ TEST(temporal_fd_cache) { int run = 0; do { - u8_t buf[256]; - // open & read an html int dice = rand() % 100; int probability = 0; @@ -597,6 +599,461 @@ TEST(temporal_fd_cache) { return TEST_RES_OK; } TEST_END +static int run_fuzz_test(FILE *f, int maxfds, int debuglog) { + // There are a bunch of arbitrary constants in this test case. Changing them will + // almost certainly change the effets of an input file. It *may* be worth + // making some of these constants to come from the input file. + int setup = fgetc(f); + + int page_size = 128 << (setup & 3); + setup >>= 2; + int erase_size = 4096 << (setup & 3); + setup >>= 2; + int block_size = erase_size << (setup & 1); + setup >>= 1; + int blocks = 4 + (setup & 7); + fs_reset_specific(0, 0, blocks * block_size, erase_size, block_size, page_size); + int res; + (FS)->fd_count = 4; + + int c; + + spiffs_file fd[4]; + memset(fd, -1, sizeof(fd)); + int openindex[4]; + memset(openindex, -1, sizeof(openindex)); + char *filename[8]; + + int i; + + for (i = 0; i < 8; i++) { + char buff[128]; + sprintf(buff, "%dfile%d.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxasdasdasdadxxxxxxxxxxxxxxxxxxx", i, i); + buff[9 + 2 * i] = 0; + filename[i] = strdup(buff); + } + + // The list of 8 modes that are chosen. SPIFFS_EXCL is not present -- it probably ought to be. + int modes[8] = {SPIFFS_RDONLY, SPIFFS_RDWR, SPIFFS_RDWR|SPIFFS_TRUNC, SPIFFS_RDWR|SPIFFS_CREAT, SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_TRUNC, + SPIFFS_WRONLY|SPIFFS_CREAT|SPIFFS_TRUNC, SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_TRUNC|SPIFFS_DIRECT, SPIFFS_WRONLY}; + + char buff[2048]; + for (i = 0; i < sizeof(buff); i++) { + buff[i] = i * 19; + } + +#define LOGOP if (debuglog) printf + + while ((c = fgetc(f)) >= 0) { + int add; + char rbuff[2048]; + if (c <= ' ') { + continue; + } + int arg = fgetc(f); + if (arg < 0) { + break; + } + int fdn = ((arg >> 6) & 3) % maxfds; + int rc; + switch(c) { + case 'O': + if (fd[fdn] >= 0) { + LOGOP(" close(%d)\n", fd[fdn]); + SPIFFS_close(FS, fd[fdn]); + openindex[fdn] = -1; + fd[fdn] = -1; + } +#ifndef HAVE_MULTIPLE_OPEN + { + int index = (arg >> 3) & 7; + for (i = 0; i < sizeof(openindex) / sizeof(openindex[0]); i++) { + if (openindex[i] == index) { + break; + } + } + if (i < sizeof(openindex) / sizeof(openindex[0])) { + break; + } + } +#endif + LOGOP(" open(\"%s\", 0x%x)", filename[(arg>>3) & 7], modes[arg & 7]); + fd[fdn] = SPIFFS_open(FS, filename[(arg>>3) & 7], modes[arg & 7], 0); + if (fd[fdn] >= 0) { + openindex[fdn] = (arg >> 3) & 7; + } + LOGOP(" -> %d\n", fd[fdn]); + break; + + case 'S': + if (fd[fdn] >= 0) { + int offset = (14 << (arg & 7)) + arg; + if (arg & 16) { + offset = -offset; + } + int whence = (arg & 63) % 3; + LOGOP(" lseek(%d, %d, %d)\n", fd[fdn], offset, whence); + SPIFFS_lseek(FS, fd[fdn], offset, whence); + } + break; + + case 'R': + if (fd[fdn] >= 0) { + LOGOP(" read(%d, , %d)", fd[fdn], (15 << (arg & 7)) + (arg & 127)); + int rlen = SPIFFS_read(FS, fd[fdn], rbuff, (15 << (arg & 7)) + (arg & 127)); + LOGOP(" -> %d\n", rlen); + } + break; + + case 'W': + if (fd[fdn] >= 0) { + LOGOP(" write(%d, , %d)", fd[fdn], (15 << (arg & 7)) + (arg & 127)); + rc = SPIFFS_write(FS, fd[fdn], buff, (15 << (arg & 7)) + (arg & 127)); + LOGOP(" -> %d\n", rc); + } + break; + + case 'C': + if (fd[fdn] >= 0) { + LOGOP(" close(%d)\n", fd[fdn]); + SPIFFS_close(FS, fd[fdn]); + } + fd[fdn] = -1; + openindex[fdn] = -1; + break; + + case 'b': + add = fgetc(f); + for (i = 0; i < sizeof(buff); i++) { + buff[i] = add + i * arg; + } + break; + + case 'f': + if (fd[fdn] >= 0) { + LOGOP(" fflush(%d)\n", fd[fdn]); + SPIFFS_fflush(FS, fd[fdn]); + } + break; + +#ifdef HAVE_REMOVE_OPEN + case 'D': + if (fd[fdn] >= 0) { + LOGOP(" fremove(%d)\n", fd[fdn]); + SPIFFS_fremove(FS, fd[fdn]); + } + break; +#endif + + case 'd': +#ifndef HAVE_REMOVE_OPEN + { + int index = arg & 7; + for (i = 0; i < sizeof(openindex) / sizeof(openindex[0]); i++) { + if (openindex[i] == index) { + break; + } + } + if (i < sizeof(openindex) / sizeof(openindex[0])) { + break; + } + } +#endif + LOGOP(" remove(\"%s\")", filename[arg & 7]); + rc = SPIFFS_remove(FS, filename[arg & 7]); + LOGOP(" -> %d\n", rc); + break; + + case 'r': +#ifndef HAVE_REMOVE_OPEN + { + int index = arg & 7; + for (i = 0; i < sizeof(openindex) / sizeof(openindex[0]); i++) { + if (openindex[i] == index) { + break; + } + } + if (i < sizeof(openindex) / sizeof(openindex[0])) { + break; + } + } +#endif + LOGOP(" rename(\"%s\", \"%s\")", filename[arg & 7], filename[(arg >> 3) & 7]); + rc = SPIFFS_rename(FS, filename[arg & 7], filename[(arg >> 3) & 7]); + LOGOP(" -> %d\n", rc); + break; + + case 'U': + ungetc(arg, f); + for (i = 0; i < 4; i++) { + fd[i] = -1; + } + { +#ifdef DO_UNMOUNT + LOGOP(" unmount\n"); + SPIFFS_unmount(FS); +#endif + char *tmpfile = strdup("/tmp/fsdump.XXXXXX"); + LOGOP(" cycle and remount\n"); + close(mkstemp(tmpfile)); + fs_store_dump(tmpfile); + fs_mount_dump(tmpfile, 0, 0, blocks * block_size, erase_size, block_size, page_size); + unlink(tmpfile); + free(tmpfile); +#ifndef NO_FORCE_CHECK + LOGOP(" forcecheck()"); + rc = SPIFFS_check(FS); + LOGOP(" -> %d\n", rc); +#endif + } + break; + + case 'c': + { + LOGOP(" check()"); + rc = SPIFFS_check(FS); + LOGOP(" -> %d\n", rc); + ungetc(arg, f); + break; + } + + default: + ungetc(arg, f); + break; + } + } + + for (i = 0; i < 4; i++) { + if (fd[i] >= 0) { + LOGOP(" close(%d)\n", fd[i]); + SPIFFS_close(FS, fd[i]); + } + } + + return TEST_RES_OK; +} + +#define FMEMARGS(x) x, sizeof(x) - 1 + +TEST(fuzzer_found_1) { + return run_fuzz_test(fmemopen(FMEMARGS("\021OlWkd5O4W4W0O5OlWkO5OlW0O5O4W0"), "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_2) { + return run_fuzz_test(fmemopen(FMEMARGS("bO4W6W0d\036O4W6"), "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_3) { + return run_fuzz_test(fmemopen(FMEMARGS("\264O4OqWeWWWWW@O4WWW\027"), "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_4) { + unsigned char smalltest[] = { + 0x62, 0x4f, 0x24, 0x57, 0x3f, 0x57, 0x3f, 0x57, 0x3f, 0x57, 0x3f, 0x57, + 0x3f, 0x4f, 0x34, 0x57, 0x3f, 0x55, 0x4f, 0x61, 0x57, 0x61, 0x4f, 0x61, + 0x57, 0x65, 0x43, 0x61, 0x4f, 0x24, 0x57, 0x30 + }; + unsigned int smalltest_len = 32; + + return run_fuzz_test(fmemopen(smalltest, smalltest_len, "r"), 4, 1); +} TEST_END + +TEST(fuzzer_found_single_1) { + return run_fuzz_test(fmemopen(FMEMARGS("\000O\004Odr4d\356Okr0WWUO;WWWWd\035W4"), "r"), 1, 1); +} TEST_END + +TEST(log_afl_test) { + u32_t old_val = set_abort_on_error(1); + int rc = run_fuzz_test(stdin, 4, 1); + set_abort_on_error(old_val); + return rc; +} TEST_END + +TEST(afl_test) { + u32_t old_val = set_abort_on_error(1); + int rc = run_fuzz_test(stdin, 4, 0); + set_abort_on_error(old_val); + return rc; +} TEST_END + +TEST(afl_single) { + u32_t old_val = set_abort_on_error(1); + int rc = run_fuzz_test(stdin, 1, 0); + set_abort_on_error(old_val); + return rc; +} TEST_END + +TEST(small_free_space) { + fs_reset_specific(0, 0, 400*1024, 4096, 2*4096, 256); + spiffs_file fd; + int res; + (FS)->fd_count = 4; + + int tfd = SPIFFS_open(FS, "testfile", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(tfd > 0); + char *tbuf = "some data"; + res = SPIFFS_write(FS, tfd, tbuf, strlen(tbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + res = SPIFFS_fflush(FS, tfd); + TEST_CHECK(res >= SPIFFS_OK); + + SPIFFS_close(FS, tfd); + + const int runs = 1000; + + int fileCurrNumber = 0; + int fileDelNumber = 1; + + int run = 0; + do { + u8_t buf[1000]; + + sprintf(buf, "%d", fileCurrNumber); + int i; + for (i = 0; i < 100; i++) { + strcat(buf, " azzaaax"); + } + + int maxFileNr = 500; + char *filename = "awyn"; + char *fileext = ".dat"; + + u32_t total; + u32_t used; + + SPIFFS_info(FS, &total, &used); + + if (total - used < 20000) { + maxFileNr = 1; + } + + fileCurrNumber++; + int fileCntr = fileCurrNumber + 1 - fileDelNumber; + + char fileCurrName[64]; + sprintf(fileCurrName, "%s%d%s", filename, fileCurrNumber, fileext); + + fd = SPIFFS_open(FS, fileCurrName, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(fd > 0); + + //printf("About to write to %s\n", fileCurrName); + res = SPIFFS_write(FS, fd, buf, strlen(buf)); + + TEST_CHECK(res == strlen(buf)); + + res = SPIFFS_fflush(FS, fd); + TEST_CHECK_EQ(res, SPIFFS_OK); + + SPIFFS_close(FS, fd); + + if (fileCntr > maxFileNr) { + char fileDelName[64]; + sprintf(fileDelName, "%s%d%s", filename, fileDelNumber, fileext); + //printf("Deleting %s (free space %d)\n", fileDelName, total - used); + + res = SPIFFS_remove(FS, fileDelName); + + TEST_CHECK(res == SPIFFS_OK); + fileDelNumber++; + } + } while (run ++ < runs); + + tfd = SPIFFS_open(FS, "testfile", SPIFFS_RDONLY, 0); + TEST_CHECK(tfd > 0); + char rbuf[32]; + res = SPIFFS_read(FS, tfd, rbuf, sizeof(rbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + SPIFFS_close(FS, tfd); + + TEST_CHECK(memcmp(rbuf, tbuf, strlen(tbuf)) == 0); + + return TEST_RES_OK; +} TEST_END + +TEST(lots_of_overwrite) { + fs_reset_specific(0, 0, 3000*1024, 4096, 2*4096, 256); + spiffs_file fd; + int res; + (FS)->fd_count = 4; + + int i; + + for (i = 0; i < 5; i++) { + + char filename[64]; + sprintf(filename, "%d-tstfile", i); + int tfd = SPIFFS_open(FS, filename, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(tfd > 0); + char tbuf[1024]; + memset(tbuf, 'a', 700); + tbuf[700] = 0; + res = SPIFFS_write(FS, tfd, tbuf, strlen(tbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + res = SPIFFS_fflush(FS, tfd); + TEST_CHECK(res >= SPIFFS_OK); + + SPIFFS_close(FS, tfd); + } + + const int runs = 100000; + + int run = 0; + for (run = 0; run < runs; run++) { + u8_t buf[2000]; + + sprintf(buf, "%d", run); + int i; + for (i = 0; i < 100 + (run % 100); i++) { + strcat(buf, " azzaaax"); + } + + int tfd = SPIFFS_open(FS, "file.dat", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0); + TEST_CHECK(tfd > 0); + res = SPIFFS_write(FS, tfd, buf, strlen(buf)); + + TEST_CHECK(res == strlen(buf)); + + res = SPIFFS_fflush(FS, tfd); + TEST_CHECK(res >= SPIFFS_OK); + + SPIFFS_close(FS, tfd); + + tfd = SPIFFS_open(FS, "file.dat", SPIFFS_RDONLY, 0); + TEST_CHECK(tfd > 0); + char rbuf[2000]; + res = SPIFFS_read(FS, tfd, rbuf, sizeof(rbuf)); + + TEST_CHECK(res == strlen(buf)); + + SPIFFS_close(FS, tfd); + + TEST_CHECK(memcmp(rbuf, buf, strlen(buf)) == 0); + + char filename[64]; + sprintf(filename, "%d-tstfile", run % 5); + tfd = SPIFFS_open(FS, filename, SPIFFS_RDONLY, 0); + TEST_CHECK(tfd > 0); + char tbuf[1024]; + memset(tbuf, 'a', 700); + tbuf[700] = 0; + res = SPIFFS_read(FS, tfd, rbuf, sizeof(rbuf)); + + TEST_CHECK(res == strlen(tbuf)); + + SPIFFS_close(FS, tfd); + TEST_CHECK(memcmp(rbuf, tbuf, strlen(tbuf)) == 0); + } + + return TEST_RES_OK; +} TEST_END + + #if 0 TEST(spiffs_hidden_file_90) { fs_mount_dump("imgs/90.hidden_file.spiffs", 0, 0, 1*1024*1024, 4096, 4096, 128); @@ -659,6 +1116,121 @@ TEST(null_deref_check_93) { } TEST_END #endif +TEST(spiffs_145) { + int res; + fs_reset_specific(0, 0, 1024*1024, 65536, 65536, 1024); + { + spiffs_file fd = SPIFFS_open(FS, "biggie", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + TEST_CHECK(fd >= 0); + char buf[1024*512]; + memset(buf, 0xee, sizeof(buf)); + TEST_CHECK_GT(SPIFFS_write(FS, fd, buf, sizeof(buf)), 0); + TEST_CHECK_EQ(SPIFFS_close(FS, fd), SPIFFS_OK); + } + const int runs = 1000; + int run = 0; + while (run++ < runs) { + spiffs_file fd = SPIFFS_open(FS, "clobber", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_WRONLY, 0); + TEST_CHECK(fd >= 0); + char buf[8192]; + memset(buf, 0xee, sizeof(buf)); + TEST_CHECK_GT(SPIFFS_write(FS, fd, buf, sizeof(buf)), 0); + TEST_CHECK_EQ(SPIFFS_close(FS, fd), SPIFFS_OK); + TEST_CHECK_EQ(SPIFFS_remove(FS, "clobber"), SPIFFS_OK); + } + + // below stolen from SPIFFS_vis + spiffs *fs = FS; + int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); + spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; + spiffs_block_ix bix = 0; + + while (bix < fs->block_count) { + // check each object lookup page + spiffs_obj_id erase_count; + TEST_CHECK_EQ(_spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0, + SPIFFS_ERASE_COUNT_PADDR(fs, bix), + sizeof(spiffs_obj_id), (u8_t *)&erase_count), SPIFFS_OK); + TEST_CHECK_NEQ(erase_count, (spiffs_obj_id)-1); + TEST_CHECK_NEQ(erase_count, 0); + bix++; + } // per block + + return TEST_RES_OK; +} TEST_END + + +TEST(seek_bug_148) { + int res; +#define MAGIC_SIZE_THAT_FAILS 26355 // happens to be SPIFFS_DATA_PAGE_SIZE(FS) * SPIFFS_OBJ_HDR_IX_LEN(FS) + fs_reset_specific(0, 0, 64*1024, 4096, 4096, 256); + u8_t buf[MAGIC_SIZE_THAT_FAILS]; + spiffs_file fd = SPIFFS_open(FS, "EVENT", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0); + TEST_CHECK_GT(fd, 0); + TEST_CHECK_EQ(SPIFFS_write(FS, fd, &buf, sizeof(buf)), sizeof(buf)); + TEST_CHECK_EQ(SPIFFS_close(FS, fd), SPIFFS_OK); + fd = SPIFFS_open(FS, "EVENT", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd, 0); + TEST_CHECK_EQ(SPIFFS_lseek(FS, fd, 0, SEEK_END), MAGIC_SIZE_THAT_FAILS); + return TEST_RES_OK; +} TEST_END + + +TEST(remove_release_fd_152) { + int res; + fs_reset_specific(0, 0, 64*1024, 4096, 4096, 256); + u8_t buf[1024]; + memrand(buf, sizeof(buf)); + TEST_CHECK_EQ(count_taken_fds(FS), 0); + spiffs_file fd1 = SPIFFS_open(FS, "removemeandloseafd", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0); + TEST_CHECK_GT(fd1, 0); + TEST_CHECK_EQ(count_taken_fds(FS), 1); + TEST_CHECK_EQ(SPIFFS_write(FS, fd1, &buf, sizeof(buf)), sizeof(buf)); + TEST_CHECK_EQ(SPIFFS_close(FS, fd1), SPIFFS_OK); + TEST_CHECK_EQ(count_taken_fds(FS), 0); + spiffs_file fd2 = SPIFFS_open(FS, "removemeandloseafd", SPIFFS_O_RDWR, 0); + TEST_CHECK_GT(fd2, 0); + TEST_CHECK_EQ(count_taken_fds(FS), 1); + spiffs_file fd3 = SPIFFS_open(FS, "removemeandloseafd", SPIFFS_O_RDWR, 0); + TEST_CHECK_GT(fd3, 0); + TEST_CHECK_EQ(count_taken_fds(FS), 2); + TEST_CHECK_EQ(SPIFFS_remove(FS, "removemeandloseafd"), SPIFFS_OK); + TEST_CHECK_EQ(count_taken_fds(FS), 0); + return TEST_RES_OK; +} TEST_END + +TEST(certain_file_size_fail_165) { + fs_reset_specific(0, 0, 512*1024, 4*1024, 64*1024, 256); + const int NUM = 134; + const int SIZ = 200; + u8_t buf[SIZ]; + + TEST_CHECK_EQ(SPIFFS_creat(FS, "test", 0), SPIFFS_OK); + spiffs_file fd = SPIFFS_open(FS, "test", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); + TEST_CHECK_GT(fd, 0); + + int i; + for (i = 0; i < NUM; i++) { + TEST_CHECK_EQ(SPIFFS_write(FS, fd, buf, SIZ), SIZ); + } + TEST_CHECK_EQ(SPIFFS_close(FS, fd), SPIFFS_OK); + fd = SPIFFS_open(FS, "test", SPIFFS_O_RDONLY, 0); + TEST_CHECK_GT(fd, 0); + + spiffs_stat s; + TEST_CHECK_EQ(SPIFFS_fstat(FS, fd, &s), SPIFFS_OK); + TEST_CHECK_EQ(s.size, NUM*SIZ); + + int size = 0; + for (i = 0; i < NUM; i++) { + size += SPIFFS_read(FS, fd, buf, SIZ); + } + TEST_CHECK_EQ(size, NUM*SIZ); + + return TEST_RES_OK; +} TEST_END + + SUITE_TESTS(bug_tests) ADD_TEST(nodemcu_full_fs_1) ADD_TEST(nodemcu_full_fs_2) @@ -671,6 +1243,20 @@ SUITE_TESTS(bug_tests) ADD_TEST(eof_tell_72) ADD_TEST(spiffs_dup_file_74) ADD_TEST(temporal_fd_cache) + ADD_TEST(spiffs_145) + ADD_TEST(seek_bug_148) + //ADD_TEST(small_free_space) + ADD_TEST(lots_of_overwrite) + ADD_TEST(fuzzer_found_1) + ADD_TEST(fuzzer_found_2) + ADD_TEST(fuzzer_found_3) + ADD_TEST(fuzzer_found_4) + ADD_TEST(remove_release_fd_152) + ADD_TEST(certain_file_size_fail_165) + ADD_TEST_NON_DEFAULT(fuzzer_found_single_1) + ADD_TEST_NON_DEFAULT(log_afl_test) + ADD_TEST_NON_DEFAULT(afl_test) + ADD_TEST_NON_DEFAULT(afl_single) #if 0 ADD_TEST(spiffs_hidden_file_90) #endif diff --git a/Sming/third-party/spiffs/src/test/test_hydrogen.c b/Sming/third-party/spiffs/src/test/test_hydrogen.c index 8244db4dd3..52126b2a5f 100644 --- a/Sming/third-party/spiffs/src/test/test_hydrogen.c +++ b/Sming/third-party/spiffs/src/test/test_hydrogen.c @@ -30,7 +30,7 @@ TEST(info) int res = SPIFFS_info(FS, &total, &used); TEST_CHECK(res == SPIFFS_OK); TEST_CHECK(used == 0); - TEST_CHECK(total < __fs.cfg.phys_size); + TEST_CHECK(total < SPIFFS_CFG_PHYS_SZ(&__fs)); return TEST_RES_OK; } TEST_END @@ -189,6 +189,12 @@ TEST(bad_fd) res = SPIFFS_write(FS, fd, 0, 0); TEST_CHECK(res < 0); TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); +#if SPIFFS_OBJ_META_LEN + u8_t new_meta[SPIFFS_OBJ_META_LEN] = {0}; + res = SPIFFS_fupdate_meta(FS, fd, new_meta); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_BAD_DESCRIPTOR); +#endif return TEST_RES_OK; } TEST_END @@ -218,6 +224,12 @@ TEST(closed_fd) res = SPIFFS_write(FS, fd, 0, 0); TEST_CHECK(res < 0); TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); +#if SPIFFS_OBJ_META_LEN + u8_t new_meta[SPIFFS_OBJ_META_LEN] = {0}; + res = SPIFFS_fupdate_meta(FS, fd, new_meta); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED); +#endif return TEST_RES_OK; } TEST_END @@ -351,8 +363,6 @@ TEST_END #if SPIFFS_FILEHDL_OFFSET TEST(open_fh_offs) { - int res; - spiffs_stat s; spiffs_file fd1, fd2, fd3; fd1 = SPIFFS_open(FS, "1", SPIFFS_CREAT | SPIFFS_EXCL, 0); fd2 = SPIFFS_open(FS, "2", SPIFFS_CREAT | SPIFFS_EXCL, 0); @@ -417,6 +427,17 @@ TEST(list_dir) break; } } + { + spiffs_stat s; + TEST_CHECK_EQ(SPIFFS_stat(FS, pe->name, &s), 0); + TEST_CHECK_EQ(pe->obj_id, s.obj_id); + TEST_CHECK_EQ(pe->size, s.size); + TEST_CHECK_EQ(pe->type, s.type); + TEST_CHECK_EQ(pe->pix, s.pix); +#if SPIFFS_OBJ_META_LEN + TEST_CHECK_EQ(memcmp(pe->meta, s.meta, SPIFFS_OBJ_META_LEN), 0); +#endif + } } SPIFFS_closedir(&d); @@ -727,6 +748,53 @@ TEST(rename) { return TEST_RES_OK; } TEST_END +#if SPIFFS_OBJ_META_LEN +TEST(update_meta) { + s32_t i, res, fd; + spiffs_stat s; + u8_t new_meta[SPIFFS_OBJ_META_LEN], new_meta2[SPIFFS_OBJ_META_LEN]; + + res = test_create_file("foo"); + TEST_CHECK(res >= 0); + + for (i = 0; i < SPIFFS_OBJ_META_LEN; i++) { + new_meta[i] = 0xaa; + } + res = SPIFFS_update_meta(FS, "foo", new_meta); + TEST_CHECK(res >= 0); + + res = SPIFFS_stat(FS, "foo", &s); + TEST_CHECK(res >= 0); + TEST_CHECK_EQ(memcmp(s.meta, new_meta, SPIFFS_OBJ_META_LEN), 0); + + for (i = 0; i < SPIFFS_OBJ_META_LEN; i++) { + new_meta2[i] = 0xbb; + } + + fd = SPIFFS_open(FS, "foo", SPIFFS_RDONLY, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fupdate_meta(FS, fd, new_meta2); + TEST_CHECK(res < 0); + TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_WRITABLE); + SPIFFS_close(FS, fd); + + res = SPIFFS_stat(FS, "foo", &s); + TEST_CHECK(res >= 0); + TEST_CHECK_EQ(memcmp(s.meta, new_meta, SPIFFS_OBJ_META_LEN), 0); + + fd = SPIFFS_open(FS, "foo", SPIFFS_RDWR, 0); + TEST_CHECK(fd >= 0); + res = SPIFFS_fupdate_meta(FS, fd, new_meta2); + TEST_CHECK_EQ(res, 0); + SPIFFS_close(FS, fd); + + res = SPIFFS_stat(FS, "foo", &s); + TEST_CHECK(res >= 0); + TEST_CHECK_EQ(memcmp(s.meta, new_meta2, SPIFFS_OBJ_META_LEN), 0); + + return TEST_RES_OK; +} TEST_END +#endif TEST(remove_single_by_path) { @@ -801,7 +869,7 @@ TEST_END TEST(write_big_file_chunks_page) { - int size = ((50*(FS)->cfg.phys_size)/100); + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100); printf(" filesize %i\n", size); int res = test_create_and_write_file("bigfile", size, SPIFFS_DATA_PAGE_SIZE(FS)); TEST_CHECK(res >= 0); @@ -819,7 +887,7 @@ TEST(write_big_files_chunks_page) int f; int files = 10; int res; - int size = ((50*(FS)->cfg.phys_size)/100)/files; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; printf(" filesize %i\n", size); for (f = 0; f < files; f++) { sprintf(name, "bigfile%i", f); @@ -839,7 +907,7 @@ TEST_END TEST(write_big_file_chunks_index) { - int size = ((50*(FS)->cfg.phys_size)/100); + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100); printf(" filesize %i\n", size); int res = test_create_and_write_file("bigfile", size, SPIFFS_DATA_PAGE_SIZE(FS) * SPIFFS_OBJ_HDR_IX_LEN(FS)); TEST_CHECK(res >= 0); @@ -857,7 +925,7 @@ TEST(write_big_files_chunks_index) int f; int files = 10; int res; - int size = ((50*(FS)->cfg.phys_size)/100)/files; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; printf(" filesize %i\n", size); for (f = 0; f < files; f++) { sprintf(name, "bigfile%i", f); @@ -895,7 +963,7 @@ TEST(write_big_files_chunks_huge) int f; int files = 10; int res; - int size = ((50*(FS)->cfg.phys_size)/100)/files; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; printf(" filesize %i\n", size); for (f = 0; f < files; f++) { sprintf(name, "bigfile%i", f); @@ -1174,7 +1242,7 @@ TEST_END TEST(read_chunk_huge) { - int sz = (2*(FS)->cfg.phys_size)/3; + int sz = (2*SPIFFS_CFG_PHYS_SZ(FS))/3; TEST_CHECK(create_and_read_back(sz, sz) == 0); return TEST_RES_OK; } @@ -1222,6 +1290,48 @@ TEST(read_beyond) } TEST_END +TEST(read_beyond2) +{ + char *name = "file"; + spiffs_file fd; + s32_t res; + const s32_t size = SPIFFS_DATA_PAGE_SIZE(FS); + + u8_t buf[size*2]; + memrand(buf, size); + + res = test_create_file(name); + CHECK(res >= 0); + fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); + CHECK(fd >= 0); + res = SPIFFS_write(FS, fd, buf, size); + CHECK(res >= 0); + + spiffs_stat stat; + res = SPIFFS_fstat(FS, fd, &stat); + CHECK(res >= 0); + CHECK(stat.size == size); + + SPIFFS_close(FS, fd); + + int i,j; + for (j = 1; j <= size+1; j++) { + fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0); + CHECK(fd >= 0); + SPIFFS_clearerr(FS); + for (i = 0; i < size * 2; i += j) { + u8_t dst; + res = SPIFFS_read(FS, fd, buf, j); + TEST_CHECK_EQ(SPIFFS_errno(FS), i < size ? SPIFFS_OK : SPIFFS_ERR_END_OF_OBJECT); + TEST_CHECK_EQ(res, MIN(j, MAX(0, size - (i + j) + j))); + } + SPIFFS_close(FS, fd); + } + + return TEST_RES_OK; +} +TEST_END + TEST(bad_index_1) { int size = SPIFFS_DATA_PAGE_SIZE(FS)*3; @@ -1301,7 +1411,6 @@ TEST(lseek_simple_modification) { int res; spiffs_file fd; char *fname = "seekfile"; - int i; int len = 4096; fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); TEST_CHECK(fd > 0); @@ -1341,7 +1450,6 @@ TEST(lseek_modification_append) { int res; spiffs_file fd; char *fname = "seekfile"; - int i; int len = 4096; fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); TEST_CHECK(fd > 0); @@ -1481,6 +1589,33 @@ TEST(lseek_read) { TEST_END + +TEST(lseek_oob) { + int res; + spiffs_file fd; + char *fname = "seekfile"; + int len = (FS_PURE_DATA_PAGES(FS) / 2) * SPIFFS_DATA_PAGE_SIZE(FS); + + fd = SPIFFS_open(FS, fname, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0); + TEST_CHECK(fd > 0); + u8_t *refbuf = malloc(len); + memrand(refbuf, len); + res = SPIFFS_write(FS, fd, refbuf, len); + TEST_CHECK(res >= 0); + + int offs = 0; + res = SPIFFS_lseek(FS, fd, -1, SPIFFS_SEEK_SET); + TEST_CHECK_EQ(res, SPIFFS_ERR_SEEK_BOUNDS); + res = SPIFFS_lseek(FS, fd, len+1, SPIFFS_SEEK_SET); + TEST_CHECK_EQ(res, SPIFFS_ERR_END_OF_OBJECT); + free(refbuf); + SPIFFS_close(FS, fd); + + return TEST_RES_OK; +} +TEST_END + + TEST(gc_quick) { char name[32]; @@ -1570,7 +1705,7 @@ TEST(write_small_files_chunks_1) char name[32]; int f; int size = 512; - int files = ((20*(FS)->cfg.phys_size)/100)/size; + int files = ((20*SPIFFS_CFG_PHYS_SZ(FS))/100)/size; int res; for (f = 0; f < files; f++) { sprintf(name, "smallfile%i", f); @@ -1589,7 +1724,7 @@ TEST_END TEST(write_big_file_chunks_1) { - int size = ((50*(FS)->cfg.phys_size)/100); + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100); printf(" filesize %i\n", size); int res = test_create_and_write_file("bigfile", size, 1); TEST_CHECK(res >= 0); @@ -1606,7 +1741,7 @@ TEST(write_big_files_chunks_1) int f; int files = 10; int res; - int size = ((50*(FS)->cfg.phys_size)/100)/files; + int size = ((50*SPIFFS_CFG_PHYS_SZ(FS))/100)/files; printf(" filesize %i\n", size); for (f = 0; f < files; f++) { sprintf(name, "bigfile%i", f); @@ -2022,7 +2157,7 @@ TEST(ix_map_remap) { // create a file, 10 data pages long s32_t res; - spiffs_file fd1, fd2; + spiffs_file fd1; fd1 = SPIFFS_open(FS, "1", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); TEST_CHECK_GT(fd1, 0); @@ -2128,7 +2263,7 @@ TEST(ix_map_partial) { // create a file, 10 data pages long s32_t res; - spiffs_file fd, fd2; + spiffs_file fd; fd = SPIFFS_open(FS, "1", SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); TEST_CHECK_GT(fd, 0); @@ -2160,7 +2295,6 @@ TEST(ix_map_partial) const int entries = SPIFFS_bytes_to_ix_map_entries(FS, size/2); spiffs_ix_map map; spiffs_page_ix ixbuf[entries]; - spiffs_page_ix ixbuf_ref[entries]; printf("map 0-50%%\n"); res = SPIFFS_ix_map(FS, fd, &map, 0, size/2, ixbuf); @@ -2324,6 +2458,9 @@ SUITE_TESTS(hydrogen_tests) ADD_TEST(user_callback_gc) ADD_TEST(name_too_long) ADD_TEST(rename) +#if SPIFFS_OBJ_META_LEN + ADD_TEST(update_meta) +#endif ADD_TEST(remove_single_by_path) ADD_TEST(remove_single_by_fd) ADD_TEST(write_cache) @@ -2342,12 +2479,14 @@ SUITE_TESTS(hydrogen_tests) ADD_TEST(read_chunk_index) ADD_TEST(read_chunk_huge) ADD_TEST(read_beyond) + ADD_TEST(read_beyond2) ADD_TEST(bad_index_1) ADD_TEST(bad_index_2) ADD_TEST(lseek_simple_modification) ADD_TEST(lseek_modification_append) ADD_TEST(lseek_modification_append_multi) ADD_TEST(lseek_read) + ADD_TEST(lseek_oob) ADD_TEST(gc_quick) ADD_TEST(write_small_file_chunks_1) ADD_TEST(write_small_files_chunks_1) diff --git a/Sming/third-party/spiffs/src/test/test_spiffs.c b/Sming/third-party/spiffs/src/test/test_spiffs.c index 2f138a2109..aa60866034 100644 --- a/Sming/third-party/spiffs/src/test/test_spiffs.c +++ b/Sming/third-party/spiffs/src/test/test_spiffs.c @@ -110,7 +110,8 @@ static int mkpath(const char *path, mode_t mode) { } // end take - +// +// char *make_test_fname(const char *name) { sprintf(_path, "%s/%s", TEST_PATH, name); return _path; @@ -139,7 +140,11 @@ void clear_test_path() { } } -static s32_t _read(spiffs *fs, u32_t addr, u32_t size, u8_t *dst) { +static s32_t _read( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + u32_t addr, u32_t size, u8_t *dst) { //printf("rd @ addr %08x => %p\n", addr, &AREA(addr)); if (log_flash_ops) { bytes_rd += size; @@ -151,19 +156,25 @@ static s32_t _read(spiffs *fs, u32_t addr, u32_t size, u8_t *dst) { return SPIFFS_ERR_TEST; } } - if (addr < __fs.cfg.phys_addr) { + if (addr < SPIFFS_CFG_PHYS_ADDR(&__fs)) { printf("FATAL read addr too low %08x < %08x\n", addr, SPIFFS_PHYS_ADDR); - exit(0); + ERREXIT(); + return -1; } - if (addr + size > __fs.cfg.phys_addr + __fs.cfg.phys_size) { + if (addr + size > SPIFFS_CFG_PHYS_ADDR(&__fs) + SPIFFS_CFG_PHYS_SZ(&__fs)) { printf("FATAL read addr too high %08x + %08x > %08x\n", addr, size, SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE); - exit(0); + ERREXIT(); + return -1; } memcpy(dst, &AREA(addr), size); return 0; } -static s32_t _write(spiffs *fs, u32_t addr, u32_t size, u8_t *src) { +static s32_t _write( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + u32_t addr, u32_t size, u8_t *src) { int i; //printf("wr %08x %i\n", addr, size); if (log_flash_ops) { @@ -177,21 +188,24 @@ static s32_t _write(spiffs *fs, u32_t addr, u32_t size, u8_t *src) { } } - if (addr < __fs.cfg.phys_addr) { + if (addr < SPIFFS_CFG_PHYS_ADDR(&__fs)) { printf("FATAL write addr too low %08x < %08x\n", addr, SPIFFS_PHYS_ADDR); - exit(0); + ERREXIT(); + return -1; } - if (addr + size > __fs.cfg.phys_addr + __fs.cfg.phys_size) { + if (addr + size > SPIFFS_CFG_PHYS_ADDR(&__fs) + SPIFFS_CFG_PHYS_SZ(&__fs)) { printf("FATAL write addr too high %08x + %08x > %08x\n", addr, size, SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE); - exit(0); + ERREXIT(); + return -1; } for (i = 0; i < size; i++) { - if (((addr + i) & (__fs.cfg.log_page_size-1)) != offsetof(spiffs_page_header, flags)) { + if (((addr + i) & (SPIFFS_CFG_LOG_PAGE_SZ(&__fs)-1)) != offsetof(spiffs_page_header, flags)) { if (check_valid_flash && ((AREA(addr + i) ^ src[i]) & src[i])) { - printf("trying to write %02x to %02x at addr %08x\n", src[i], AREA(addr + i), addr+i); - spiffs_page_ix pix = (addr + i) / LOG_PAGE; + printf("trying to write %02x to %02x at addr %08x (as part of writing %d bytes to addr %08x)\n", src[i], AREA(addr + i), addr+i, size, addr); + spiffs_page_ix pix = (addr + i) / SPIFFS_CFG_LOG_PAGE_SZ(&__fs); dump_page(&__fs, pix); + ERREXIT(); return -1; } } @@ -199,16 +213,22 @@ static s32_t _write(spiffs *fs, u32_t addr, u32_t size, u8_t *src) { } return 0; } -static s32_t _erase(spiffs *fs, u32_t addr, u32_t size) { - if (addr & (__fs.cfg.phys_erase_block-1)) { +static s32_t _erase( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + u32_t addr, u32_t size) { + if (addr & (SPIFFS_CFG_PHYS_ERASE_SZ(&__fs)-1)) { printf("trying to erase at addr %08x, out of boundary\n", addr); + ERREXIT(); return -1; } - if (size & (__fs.cfg.phys_erase_block-1)) { + if (size & (SPIFFS_CFG_PHYS_ERASE_SZ(&__fs)-1)) { printf("trying to erase at with size %08x, out of boundary\n", size); + ERREXIT(); return -1; } - _erases[(addr-__fs.cfg.phys_addr)/__fs.cfg.phys_erase_block]++; + _erases[(addr-SPIFFS_CFG_PHYS_ADDR(&__fs))/SPIFFS_CFG_PHYS_ERASE_SZ(&__fs)]++; memset(&AREA(addr), 0xff, size); return 0; } @@ -291,7 +311,7 @@ void dump_page(spiffs *fs, spiffs_page_ix p) { } } printf("\n"); - u32_t len = fs->cfg.log_page_size; + u32_t len = SPIFFS_CFG_LOG_PAGE_SZ(fs); hexdump(addr, len); } @@ -318,22 +338,25 @@ void area_read(u32_t addr, u8_t *buf, u32_t size) { void dump_erase_counts(spiffs *fs) { spiffs_block_ix bix; + spiffs_block_ix bix_offs; printf(" BLOCK |\n"); printf(" AGE COUNT|\n"); - for (bix = 0; bix < fs->block_count; bix++) { - printf("----%3i ----|", bix); - } - printf("\n"); - for (bix = 0; bix < fs->block_count; bix++) { - spiffs_obj_id erase_mark; - _spiffs_rd(fs, 0, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (u8_t *)&erase_mark); - if (_erases[bix] == 0) { - printf(" |"); - } else { - printf("%7i %4i|", (fs->max_erase_count - erase_mark), _erases[bix]); + for (bix_offs = 0; bix_offs < fs->block_count; bix_offs+=8) { + for (bix = bix_offs; bix < bix_offs+8 && bix < fs->block_count; bix++) { + printf("----%3i ----|", bix); + } + printf("\n"); + for (bix = bix_offs; bix < bix_offs+8 && bix < fs->block_count; bix++) { + spiffs_obj_id erase_mark; + _spiffs_rd(fs, 0, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (u8_t *)&erase_mark); + if (_erases[bix] == 0) { + printf(" |"); + } else { + printf("%7i %4i|", (fs->max_erase_count - erase_mark), _erases[bix]); + } } + printf("\n"); } - printf("\n"); } void dump_flash_access_stats() { @@ -342,8 +365,13 @@ void dump_flash_access_stats() { } -static u32_t old_perc = 999; -static void spiffs_check_cb_f(spiffs *fs, spiffs_check_type type, spiffs_check_report report, +static int check_cb_count; +// static u32_t old_perc = 999; +static void spiffs_check_cb_f( +#if SPIFFS_HAL_CALLBACK_EXTRA + spiffs *fs, +#endif + spiffs_check_type type, spiffs_check_report report, u32_t arg1, u32_t arg2) { /* if (report == SPIFFS_CHECK_PROGRESS && old_perc != arg1) { old_perc = arg1; @@ -359,6 +387,7 @@ static void spiffs_check_cb_f(spiffs *fs, spiffs_check_type type, spiffs_check_r printf("%i%%\n", arg1 * 100 / 256); }*/ if (report != SPIFFS_CHECK_PROGRESS) { + check_cb_count++; if (report != SPIFFS_CHECK_ERROR) fs_check_fixes++; printf(" check: "); switch (type) { @@ -397,6 +426,7 @@ void fs_set_addr_offset(u32_t offset) { void test_lock(spiffs *fs) { if (_fs_locks != 0) { printf("FATAL: reentrant locks. Abort.\n"); + ERREXIT(); exit(-1); } _fs_locks++; @@ -405,6 +435,7 @@ void test_lock(spiffs *fs) { void test_unlock(spiffs *fs) { if (_fs_locks != 1) { printf("FATAL: unlocking unlocked. Abort.\n"); + ERREXIT(); exit(-1); } _fs_locks--; @@ -417,11 +448,13 @@ s32_t fs_mount_specific(u32_t phys_addr, u32_t phys_size, c.hal_erase_f = _erase; c.hal_read_f = _read; c.hal_write_f = _write; +#if SPIFFS_SINGLETON == 0 c.log_block_size = log_block_size; c.log_page_size = log_page_size; c.phys_addr = phys_addr; c.phys_erase_block = phys_sector_size; c.phys_size = phys_size; +#endif #if SPIFFS_FILEHDL_OFFSET c.fh_ix_offset = TEST_SPIFFS_FILEHDL_OFFSET; #endif @@ -446,10 +479,12 @@ static void fs_create(u32_t spiflash_size, ASSERT(_fds != NULL, "testbench fd buffer could not be malloced"); memset(_fds, 0, _fds_sz); +#if SPIFFS_CACHE _cache_sz = sizeof(spiffs_cache) + cache_pages * (sizeof(spiffs_cache_page) + log_page_size); _cache = malloc(_cache_sz); ASSERT(_cache != NULL, "testbench cache could not be malloced"); memset(_cache, 0, _cache_sz); +#endif const u32_t work_sz = log_page_size * 2; _work = malloc(work_sz); @@ -593,7 +628,6 @@ void real_assert(int c, const char *n, const char *file, int l) { } int read_and_verify(char *name) { - s32_t res; int fd = SPIFFS_open(&__fs, name, SPIFFS_RDONLY, 0); if (fd < 0) { printf(" read_and_verify: could not open file %s\n", name); @@ -611,6 +645,14 @@ int read_and_verify_fd(spiffs_file fd, char *name) { printf(" read_and_verify: could not stat file %s\n", name); return res; } + + off_t fsize = lseek(pfd, 0, SEEK_END); + if (s.size != fsize) { + printf(" read_and_verify: size differs, %s spiffs:%d!=fs:%ld\n", name, s.size, fsize); + return -1; + } + lseek(pfd, 0, SEEK_SET); + if (s.size == 0) { SPIFFS_close(&__fs, fd); close(pfd); @@ -693,6 +735,14 @@ int test_create_file(char *name) { CHECK_RES(res); CHECK(strcmp((char*)s.name, name) == 0); CHECK(s.size == 0); +#if SPIFFS_OBJ_META_LEN + { + int i; + for (i = 0; i < SPIFFS_OBJ_META_LEN; i++) { + CHECK(s.meta[i] == 0xff); + } + } +#endif SPIFFS_close(FS, fd); return 0; } @@ -707,7 +757,7 @@ int test_create_and_write_file(char *name, int size, int chunk_size) { } CHECK(res >= 0); fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0); - if (res < 0) { + if (fd < 0) { printf(" failed open, %i\n",res); } CHECK(fd >= 0); @@ -816,10 +866,10 @@ u32_t get_spiffs_file_crc_by_fd(spiffs_file fd) { ASSERT(SPIFFS_lseek(FS, fd, 0, SPIFFS_SEEK_SET) >= 0, "could not seek to start of file"); - while ((res = SPIFFS_read(FS, fd, buf, sizeof(buf))) >= SPIFFS_OK) { + while ((res = SPIFFS_read(FS, fd, buf, sizeof(buf))) > SPIFFS_OK) { crc = crc32(crc, buf, res); } - ASSERT(res == SPIFFS_ERR_END_OF_OBJECT || res == SPIFFS_OK, "failed reading file"); + ASSERT(SPIFFS_errno(FS) == SPIFFS_ERR_END_OF_OBJECT || SPIFFS_errno(FS) == SPIFFS_OK, "failed reading file"); return crc; } @@ -880,14 +930,19 @@ void _teardown() { #endif dump_erase_counts(FS); printf(" fs consistency check output begin\n"); + check_cb_count = 0; SPIFFS_check(FS); printf(" fs consistency check output end\n"); + if (check_cb_count) { + ERREXIT(); + } } clear_test_path(); fs_free(); printf(" locks : %i\n", _fs_locks); if (_fs_locks != 0) { printf("FATAL: lock asymmetry. Abort.\n"); + ERREXIT(); exit(-1); } } @@ -1044,5 +1099,13 @@ int run_file_config(int cfg_count, tfile_conf* cfgs, int max_runs, int max_concu return 0; } - - +int count_taken_fds(spiffs *fs) { + int i; + spiffs_fd *fds = (spiffs_fd *)fs->fd_space; + int taken = 0; + for (i = 0; i < fs->fd_count; i++) { + spiffs_fd *cur_fd = &fds[i]; + if (cur_fd->file_nbr) taken++; + } + return taken; +} diff --git a/Sming/third-party/spiffs/src/test/test_spiffs.h b/Sming/third-party/spiffs/src/test/test_spiffs.h index b0a735338d..4c39bdba9c 100644 --- a/Sming/third-party/spiffs/src/test/test_spiffs.h +++ b/Sming/third-party/spiffs/src/test/test_spiffs.h @@ -18,7 +18,7 @@ extern spiffs __fs; #define CHECK(r) if (!(r)) return -1; #define CHECK_RES(r) if (r < 0) return -1; #define FS_PURE_DATA_PAGES(fs) \ - ((fs)->cfg.phys_size / (fs)->cfg.log_page_size - (fs)->block_count * SPIFFS_OBJ_LOOKUP_PAGES(fs)) + (SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_PAGE_SZ(fs)- (fs)->block_count * SPIFFS_OBJ_LOOKUP_PAGES(fs)) #define FS_PURE_DATA_SIZE(fs) \ FS_PURE_DATA_PAGES(fs) * SPIFFS_DATA_PAGE_SIZE(fs) @@ -89,6 +89,8 @@ u32_t get_flash_ops_log_write_bytes(); void invoke_error_after_read_bytes(u32_t b, char once_only); void invoke_error_after_write_bytes(u32_t b, char once_only); void fs_set_validate_flashing(int i); +int get_error_count(); +int count_taken_fds(spiffs *fs); void memrand(u8_t *b, int len); int test_create_file(char *name); diff --git a/Sming/third-party/spiffs/src/test/testrunner.c b/Sming/third-party/spiffs/src/test/testrunner.c index 96fa1a3ccd..27419d32be 100644 --- a/Sming/third-party/spiffs/src/test/testrunner.c +++ b/Sming/third-party/spiffs/src/test/testrunner.c @@ -36,6 +36,9 @@ void test_init(void (*on_stop)(test *t)) { test_main.on_stop = on_stop; } +static int abort_on_error = 0; +static int error_count = 0; + static char check_spec(char *name) { if (test_main.spec) { fseek(test_main.spec, 0, SEEK_SET); @@ -57,7 +60,7 @@ static char check_spec(char *name) { static char check_incl_filter(char *name) { if (strlen(test_main.incl_filter)== 0) return 1; - return strstr(name, test_main.incl_filter) == 0 ? 0 : 1; + return strstr(name, test_main.incl_filter) == 0 ? 0 : 2; } static char check_excl_filter(char *name) { @@ -65,10 +68,10 @@ static char check_excl_filter(char *name) { return strstr(name, test_main.excl_filter) == 0 ? 1 : 0; } -void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)) { +void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t), int non_default) { if (f == 0) return; if (!check_spec(name)) return; - if (!check_incl_filter(name)) return; + if (check_incl_filter(name) <= non_default) return; if (!check_excl_filter(name)) return; DBGT("adding test %s\n", name); test *t = malloc(sizeof(test)); @@ -108,6 +111,25 @@ static void dump_res(test_res **head) { } } +int get_error_count(void) { + return error_count; +} + +void inc_error_count(void) { + error_count++; +} + +int set_abort_on_error(int val) { + int old_val = abort_on_error; + abort_on_error = val; + + return old_val; +} + +int get_abort_on_error(void) { + return abort_on_error; +} + int run_tests(int argc, char **args) { memset(&test_main, 0, sizeof(test_main)); int arg; @@ -166,7 +188,11 @@ int run_tests(int argc, char **args) { test *next_test = cur_t->_next; DBGT("TEST %i/%i : running test %s\n", i, test_main.test_count, cur_t->name); i++; + int start_error_count = get_error_count(); int res = cur_t->f(cur_t); + if (res == TEST_RES_OK && get_error_count() != start_error_count) { + res = TEST_RES_FAIL; + } cur_t->test_result = res; int fd = res == TEST_RES_OK ? fd_success : fd_bad; write(fd, cur_t->name, strlen(cur_t->name)); diff --git a/Sming/third-party/spiffs/src/test/testrunner.h b/Sming/third-party/spiffs/src/test/testrunner.h index c64c920142..697fb09590 100644 --- a/Sming/third-party/spiffs/src/test/testrunner.h +++ b/Sming/third-party/spiffs/src/test/testrunner.h @@ -65,6 +65,8 @@ void add_suites() { #define TEST_RES_FAIL -1 #define TEST_RES_ASSERT -2 +#define ERREXIT() if (get_abort_on_error()) abort(); else inc_error_count() + struct test_s; typedef int (*test_f)(struct test_s *t); @@ -85,35 +87,35 @@ typedef struct test_res_s { } test_res; #define TEST_CHECK(x) if (!(x)) { \ - printf(" TEST FAIL %s:%i\n", __FILE__, __LINE__); \ + printf(" TEST FAIL %s:%d\n", __FILE__, __LINE__); \ goto __fail_stop; \ } #define TEST_CHECK_EQ(x, y) if ((x) != (y)) { \ - printf(" TEST FAIL %s:%i, %i != %i\n", __FILE__, __LINE__, (x), (y)); \ + printf(" TEST FAIL %s:%d, %d != %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ goto __fail_stop; \ } #define TEST_CHECK_NEQ(x, y) if ((x) == (y)) { \ - printf(" TEST FAIL %s:%i, %i == %i\n", __FILE__, __LINE__, (x), (y)); \ + printf(" TEST FAIL %s:%d, %d == %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ goto __fail_stop; \ } #define TEST_CHECK_GT(x, y) if ((x) <= (y)) { \ - printf(" TEST FAIL %s:%i, %i <= %i\n", __FILE__, __LINE__, (x), (y)); \ + printf(" TEST FAIL %s:%d, %d <= %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ goto __fail_stop; \ } #define TEST_CHECK_LT(x, y) if ((x) >= (y)) { \ - printf(" TEST FAIL %s:%i, %i >= %i\n", __FILE__, __LINE__, (x), (y)); \ + printf(" TEST FAIL %s:%d, %d >= %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ goto __fail_stop; \ } #define TEST_CHECK_GE(x, y) if ((x) < (y)) { \ - printf(" TEST FAIL %s:%i, %i < %i\n", __FILE__, __LINE__, (x), (y)); \ + printf(" TEST FAIL %s:%d, %d < %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ goto __fail_stop; \ } #define TEST_CHECK_LE(x, y) if ((x) > (y)) { \ - printf(" TEST FAIL %s:%i, %i > %i\n", __FILE__, __LINE__, (x), (y)); \ + printf(" TEST FAIL %s:%d, %d > %d\n", __FILE__, __LINE__, (int)(x), (int)(y)); \ goto __fail_stop; \ } #define TEST_ASSERT(x) if (!(x)) { \ - printf(" TEST ASSERT %s:%i\n", __FILE__, __LINE__); \ + printf(" TEST ASSERT %s:%d\n", __FILE__, __LINE__); \ goto __fail_assert; \ } @@ -130,7 +132,10 @@ typedef struct test_res_s { } #define ADD_TEST(tf) \ - _add_test(__test_##tf, str(tf), setup, teardown); + _add_test(__test_##tf, str(tf), setup, teardown, 0); + +#define ADD_TEST_NON_DEFAULT(tf) \ + _add_test(__test_##tf, str(tf), setup, teardown, 1); #define ADD_SUITE(sui) \ extern void _add_suite_tests_##sui(void); \ @@ -145,11 +150,16 @@ typedef struct test_res_s { __fail_assert: return TEST_RES_ASSERT; \ } -void add_suites(); +int set_abort_on_error(int val); +int get_abort_on_error(void); +int get_error_count(void); +void inc_error_count(void); + +void add_suites(void); void test_init(void (*on_stop)(test *t)); // returns 0 if all tests ok, -1 if any test failed, -2 on badness int run_tests(int argc, char **args); void _add_suite(const char *suite_name); -void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)); +void _add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t), int non_default); #endif /* TESTRUNNER_H_ */ diff --git a/Sming/third-party/spiffs/src/test/testsuites.c b/Sming/third-party/spiffs/src/test/testsuites.c index f5722874fa..cce5cd9d5b 100644 --- a/Sming/third-party/spiffs/src/test/testsuites.c +++ b/Sming/third-party/spiffs/src/test/testsuites.c @@ -7,7 +7,7 @@ #include "testrunner.h" -void add_suites() { +void add_suites(void) { //ADD_SUITE(dev_tests); ADD_SUITE(check_tests); ADD_SUITE(hydrogen_tests); 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 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 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..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 * */ @@ -75,7 +76,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 @@ -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_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/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 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. 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")) { 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/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 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 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()