From 37180024f48c80371d271384103ce4267746070a Mon Sep 17 00:00:00 2001 From: iosen Date: Tue, 21 Jun 2016 23:16:10 +1000 Subject: [PATCH 01/26] sntp: free the pbuf after sending the request Fixes a memory leak. --- extras/sntp/sntp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extras/sntp/sntp.c b/extras/sntp/sntp.c index 5654075..48b2f14 100644 --- a/extras/sntp/sntp.c +++ b/extras/sntp/sntp.c @@ -608,6 +608,8 @@ sntp_send_request(ip_addr_t *server_addr) sntp_initialize_request(sntpmsg); /* send request */ udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT); + pbuf_free(p); + /* set up receive timeout: try next server or retry on timeout */ sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); #if SNTP_CHECK_RESPONSE >= 1 From 587c867d4bac6e49155b918f3c8c46f9a62e594b Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 28 Jun 2016 10:09:08 +1000 Subject: [PATCH 02/26] queue.h: Re-add the BSD Copyright notice to queue.h from Espressif's SDK. Thanks @pfalcon for the heads-up on this: https://groups.google.com/forum/#!topic/esp8266-re/I4iO3fM0mmA --- include/espressif/queue.h | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/include/espressif/queue.h b/include/espressif/queue.h index a760c8d..7725a3b 100644 --- a/include/espressif/queue.h +++ b/include/espressif/queue.h @@ -1,6 +1,61 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ +/* + * Note: This header file comes to us from the Espressif + * SDK. Espressif adapted it from BSD's queue.h. The BSD copyright + * notice and the following extract from the explanatory statement + * were re-added by esp-open-rtos. + * + * FreeBSD version of this header: + * https://svnweb.freebsd.org/base/head/sys/sys/queue.h?view=markup + * + * **** + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * For details on the use of these macros, see the queue(3) manual page. + * + */ + #define QMD_SAVELINK(name, link) #define TRASHIT(x) From 04b119a61ee614d6475edfb3a1e84ce5989f0d55 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 30 Jun 2016 08:18:10 +1000 Subject: [PATCH 03/26] Seed libc PRNG from hardware RNG on reset --- core/app_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/app_main.c b/core/app_main.c index a38fb5f..ebf9e9a 100644 --- a/core/app_main.c +++ b/core/app_main.c @@ -21,6 +21,7 @@ #include "esp/spi_regs.h" #include "esp/dport_regs.h" #include "esp/wdev_regs.h" +#include "esp/hwrand.h" #include "os_version.h" #include "espressif/esp_common.h" @@ -378,6 +379,8 @@ static __attribute__((noinline)) void user_start_phase2(void) { init_networking(&phy_info, sdk_info.sta_mac_addr); + srand(hwrand()); /* seed libc rng */ + // Call gcc constructor functions void (**ctor)(void); for ( ctor = &__init_array_start; ctor != &__init_array_end; ++ctor) { From b71a7ad23758fd3bf23628ed687e5e0aabee7a26 Mon Sep 17 00:00:00 2001 From: sheinz Date: Thu, 30 Jun 2016 17:38:05 +0300 Subject: [PATCH 04/26] Use SPIFFS for POSIX file access. Draft. Not tested. --- .gitmodules | 3 ++ core/newlib_syscalls.c | 20 ++++++++--- examples/posix_fs/Makefile | 11 ++++++ examples/posix_fs/fs-test | 1 + examples/posix_fs/posix_fs_example.c | 41 ++++++++++++++++++++++ extras/spiffs/esp_spiffs.c | 51 ++++++++++++++++++++++++++++ 6 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 examples/posix_fs/Makefile create mode 160000 examples/posix_fs/fs-test create mode 100644 examples/posix_fs/posix_fs_example.c diff --git a/.gitmodules b/.gitmodules index 00dadd8..d3fc285 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,3 +14,6 @@ [submodule "extras/spiffs/spiffs"] path = extras/spiffs/spiffs url = https://github.com/pellepl/spiffs.git +[submodule "examples/posix_fs/fs-test"] + path = examples/posix_fs/fs-test + url = https://github.com/sheinz/fs-test diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c index 023872c..c8104a9 100644 --- a/core/newlib_syscalls.c +++ b/core/newlib_syscalls.c @@ -41,7 +41,7 @@ IRAM caddr_t _sbrk_r (struct _reent *r, int incr) } /* syscall implementation for stdio write to UART */ -long _write_r(struct _reent *r, int fd, const char *ptr, int len ) +__attribute__((weak)) long _write_r(struct _reent *r, int fd, const char *ptr, int len ) { if(fd != r->_stdout->_file) { r->_errno = EBADF; @@ -79,10 +79,20 @@ __attribute__((weak)) long _read_r( struct _reent *r, int fd, char *ptr, int len /* Stub syscall implementations follow, to allow compiling newlib functions that pull these in via various codepaths */ -__attribute__((alias("syscall_returns_enosys"))) int _open_r(struct _reent *r, const char *pathname, int flags, int mode); -__attribute__((alias("syscall_returns_enosys"))) int _fstat_r(struct _reent *r, int fd, void *buf); -__attribute__((alias("syscall_returns_enosys"))) int _close_r(struct _reent *r, int fd); -__attribute__((alias("syscall_returns_enosys"))) off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence); +__attribute__((weak, alias("syscall_returns_enosys"))) +int _open_r(struct _reent *r, const char *pathname, int flags, int mode); + +__attribute__((weak, alias("syscall_returns_enosys"))) +int _close_r(struct _reent *r, int fd); + +__attribute__((weak, alias("syscall_returns_enosys"))) +int _unlink_r(struct _reent *r, const char *path); + +__attribute__((alias("syscall_returns_enosys"))) +int _fstat_r(struct _reent *r, int fd, void *buf); + +__attribute__((alias("syscall_returns_enosys"))) +off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence); /* Generic stub for any newlib syscall that fails with errno ENOSYS ("Function not implemented") and a return value equivalent to diff --git a/examples/posix_fs/Makefile b/examples/posix_fs/Makefile new file mode 100644 index 0000000..bf45ed7 --- /dev/null +++ b/examples/posix_fs/Makefile @@ -0,0 +1,11 @@ +PROGRAM=posix_fs_example +PROGRAM_EXTRA_SRC_FILES=./fs-test/fs_test.c + +EXTRA_COMPONENTS = extras/spiffs +FLASH_SIZE = 32 + +# spiffs configuration +SPIFFS_BASE_ADDR = 0x200000 +SPIFFS_SIZE = 0x100000 + +include ../../common.mk diff --git a/examples/posix_fs/fs-test b/examples/posix_fs/fs-test new file mode 160000 index 0000000..983ed83 --- /dev/null +++ b/examples/posix_fs/fs-test @@ -0,0 +1 @@ +Subproject commit 983ed830a8d2bd1a3eaa586ed608530f9d29201e diff --git a/examples/posix_fs/posix_fs_example.c b/examples/posix_fs/posix_fs_example.c new file mode 100644 index 0000000..7e3ad8f --- /dev/null +++ b/examples/posix_fs/posix_fs_example.c @@ -0,0 +1,41 @@ +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include "esp8266.h" +#include + +#include "esp_spiffs.h" +#include "spiffs.h" + +#include "fs-test/fs_test.h" + + +void test_task(void *pvParameters) +{ + esp_spiffs_mount(); + esp_spiffs_unmount(); // FS must be unmounted before formating + if (SPIFFS_format(&fs) == SPIFFS_OK) { + printf("Format complete\n"); + } else { + printf("Format failed\n"); + } + esp_spiffs_mount(); + + while (1) { + vTaskDelay(5000 / portTICK_RATE_MS); + + if (fs_test_run(10000)) { + printf("PASS\n"); + } else { + printf("FAIL\n"); + } + } +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + + xTaskCreate(test_task, (signed char *)"test_task", 1024, NULL, 2, NULL); +} diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index d6ec7d6..194d697 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -9,6 +9,7 @@ #include "spiffs.h" #include #include +#include spiffs fs; @@ -185,3 +186,53 @@ void esp_spiffs_unmount() fds_buf = 0; cache_buf = 0; } + +/* syscall implementation for stdio write to UART */ +long _write_r(struct _reent *r, int fd, const char *ptr, int len ) +{ + if(fd != r->_stdout->_file) { + return SPIFFS_write(&fs, (spiffs_file)fd, (char*)ptr, len); + } + for(int i = 0; i < len; i++) { + /* Auto convert CR to CRLF, ignore other LFs (compatible with Espressif SDK behaviour) */ + if(ptr[i] == '\r') + continue; + if(ptr[i] == '\n') + uart_putc(0, '\r'); + uart_putc(0, ptr[i]); + } + return len; +} + +/* syscall implementation for stdio read from UART */ +long _read_r( struct _reent *r, int fd, char *ptr, int len ) +{ + int ch, i; + + if(fd != r->_stdin->_file) { + return SPIFFS_read(&fs, (spiffs_file)fd, ptr, len); + } + uart_rxfifo_wait(0, 1); + for(i = 0; i < len; i++) { + ch = uart_getc_nowait(0); + if (ch < 0) break; + ptr[i] = ch; + } + return i; +} + +/* syscall implementation for stdio write to UART */ +int _open_r(struct _reent *r, const char *pathname, int flags, int mode) +{ + return SPIFFS_open(&fs, pathname, flags, mode); +} + +int _close_r(struct _reent *r, int fd) +{ + return SPIFFS_close(&fs, (spiffs_file)fd); +} + +int _unlink_r(struct _reent *r, const char *path) +{ + return SPIFFS_remove(&fs, path); +} From 0f9d991ba7fe84655de9f2a57c98bb89492533c5 Mon Sep 17 00:00:00 2001 From: sheinz Date: Thu, 30 Jun 2016 22:18:07 +0300 Subject: [PATCH 05/26] Fixed libc and SPIFFS integration. Test passes on ESP-12E module. --- examples/posix_fs/fs-test | 2 +- examples/posix_fs/posix_fs_example.c | 2 +- extras/spiffs/esp_spiffs.c | 31 +++++++++++++++++++++------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/examples/posix_fs/fs-test b/examples/posix_fs/fs-test index 983ed83..218c523 160000 --- a/examples/posix_fs/fs-test +++ b/examples/posix_fs/fs-test @@ -1 +1 @@ -Subproject commit 983ed830a8d2bd1a3eaa586ed608530f9d29201e +Subproject commit 218c5235584429f407d619e5e35f90732ad505f3 diff --git a/examples/posix_fs/posix_fs_example.c b/examples/posix_fs/posix_fs_example.c index 7e3ad8f..d84be5e 100644 --- a/examples/posix_fs/posix_fs_example.c +++ b/examples/posix_fs/posix_fs_example.c @@ -25,7 +25,7 @@ void test_task(void *pvParameters) while (1) { vTaskDelay(5000 / portTICK_RATE_MS); - if (fs_test_run(10000)) { + if (fs_test_run(1000)) { printf("PASS\n"); } else { printf("FAIL\n"); diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index 194d697..4b5ef77 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -10,6 +10,7 @@ #include #include #include +#include spiffs fs; @@ -187,11 +188,15 @@ void esp_spiffs_unmount() cache_buf = 0; } -/* syscall implementation for stdio write to UART */ +#define FD_OFFSET 3 + +// This implementation replaces implementation in core/newlib_syscals.c long _write_r(struct _reent *r, int fd, const char *ptr, int len ) { if(fd != r->_stdout->_file) { - return SPIFFS_write(&fs, (spiffs_file)fd, (char*)ptr, len); + long ret = SPIFFS_write(&fs, (spiffs_file)(fd - FD_OFFSET), + (char*)ptr, len); + return ret; } for(int i = 0; i < len; i++) { /* Auto convert CR to CRLF, ignore other LFs (compatible with Espressif SDK behaviour) */ @@ -204,13 +209,14 @@ long _write_r(struct _reent *r, int fd, const char *ptr, int len ) return len; } -/* syscall implementation for stdio read from UART */ +// This implementation replaces implementation in core/newlib_syscals.c long _read_r( struct _reent *r, int fd, char *ptr, int len ) { int ch, i; if(fd != r->_stdin->_file) { - return SPIFFS_read(&fs, (spiffs_file)fd, ptr, len); + long ret = SPIFFS_read(&fs, (spiffs_file)(fd - FD_OFFSET), ptr, len); + return ret; } uart_rxfifo_wait(0, 1); for(i = 0; i < len; i++) { @@ -221,15 +227,26 @@ long _read_r( struct _reent *r, int fd, char *ptr, int len ) return i; } -/* syscall implementation for stdio write to UART */ int _open_r(struct _reent *r, const char *pathname, int flags, int mode) { - return SPIFFS_open(&fs, pathname, flags, mode); + uint32_t spiffs_flags = SPIFFS_RDONLY; + + if (flags & O_CREAT) spiffs_flags |= SPIFFS_CREAT; + if (flags & O_APPEND) spiffs_flags |= SPIFFS_APPEND; + if (flags & O_TRUNC) spiffs_flags |= SPIFFS_TRUNC; + if (flags & O_RDONLY) spiffs_flags |= SPIFFS_RDONLY; + if (flags & O_WRONLY) spiffs_flags |= SPIFFS_WRONLY; + + int ret = SPIFFS_open(&fs, pathname, spiffs_flags, mode); + if (ret > 0) { + return ret + FD_OFFSET; + } + return ret; } int _close_r(struct _reent *r, int fd) { - return SPIFFS_close(&fs, (spiffs_file)fd); + return SPIFFS_close(&fs, (spiffs_file)(fd - FD_OFFSET)); } int _unlink_r(struct _reent *r, const char *path) From 09a5ec062ac1432860bf4fe339b0a25e55049c85 Mon Sep 17 00:00:00 2001 From: baoshi Date: Tue, 5 Jul 2016 21:37:47 +0800 Subject: [PATCH 06/26] Handling MQTT read failure and send buffer length --- extras/paho_mqtt_c/MQTTClient.c | 32 ++++++++++++++++++++------------ extras/paho_mqtt_c/MQTTClient.h | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/extras/paho_mqtt_c/MQTTClient.c b/extras/paho_mqtt_c/MQTTClient.c index b964250..4df3d8e 100644 --- a/extras/paho_mqtt_c/MQTTClient.c +++ b/extras/paho_mqtt_c/MQTTClient.c @@ -35,7 +35,7 @@ int sendPacket(MQTTClient* c, int length, Timer* timer) while (sent < length && !expired(timer)) { - rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, left_ms(timer)); + rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length - sent, left_ms(timer)); if (rc < 0) // there was an error writing the data break; sent += rc; @@ -70,7 +70,9 @@ int decodePacket(MQTTClient* c, int* value, int timeout) } rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout); if (rc != 1) - goto exit; + { + goto exit; + } *value += (i & 127) * multiplier; multiplier *= 128; } while ((i & 128) != 0); @@ -79,6 +81,7 @@ exit: } +// Return packet type. If no packet avilable, return FAILURE, or READ_ERROR if timeout int readPacket(MQTTClient* c, Timer* timer) { int rc = FAILURE; @@ -89,20 +92,19 @@ int readPacket(MQTTClient* c, Timer* timer) /* 1. read the header byte. This has the packet type in it */ if (c->ipstack->mqttread(c->ipstack, c->readbuf, 1, left_ms(timer)) != 1) goto exit; - len = 1; /* 2. read the remaining length. This is variable in itself */ decodePacket(c, &rem_len, left_ms(timer)); len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */ - /* 3. read the rest of the buffer using a callback to supply the rest of the data */ if (rem_len > 0 && (c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, left_ms(timer)) != rem_len)) + { + rc = READ_ERROR; goto exit; - + } header.byte = c->readbuf[0]; rc = header.bits.type; exit: - //dmsg_printf("readPacket=%d\r\n", rc); return rc; } @@ -212,10 +214,10 @@ exit: } -int cycle(MQTTClient* c, Timer* timer) +int cycle(MQTTClient* c, Timer* timer) { // read the socket, see what work is due - unsigned short packet_type = readPacket(c, timer); + int packet_type = readPacket(c, timer); int len = 0, rc = SUCCESS; @@ -266,11 +268,17 @@ int cycle(MQTTClient* c, Timer* timer) case PUBCOMP: break; case PINGRESP: - { - c->ping_outstanding = 0; - c->fail_count = 0; - } + { + c->ping_outstanding = 0; + c->fail_count = 0; break; + } + case READ_ERROR: + { + c->isconnected = 0; // we simulate a disconnect if reading error + rc = DISCONNECTED; // so that the outer layer will reconnect and recover + break; + } } if (c->isconnected) rc = keepalive(c); diff --git a/extras/paho_mqtt_c/MQTTClient.h b/extras/paho_mqtt_c/MQTTClient.h index f7ea424..876197c 100644 --- a/extras/paho_mqtt_c/MQTTClient.h +++ b/extras/paho_mqtt_c/MQTTClient.h @@ -27,7 +27,7 @@ enum QoS { QOS0, QOS1, QOS2 }; // all failure return codes must be negative -enum returnCode {DISCONNECTED = -3, BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 }; +enum returnCode {READ_ERROR = -4, DISCONNECTED = -3, BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 }; void NewTimer(Timer*); From 2ecbf1d584a89370b9bcc2fa8a53414bed3522d2 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Sat, 10 Oct 2015 21:56:11 -0700 Subject: [PATCH 07/26] First batch of opensdk additions Replacements for: libmain/misc.o libmain/os_cpu_a.o libmain/spi_flash.o libmain/timers.o libmain/uart.o libmain/xtensa_context.o --- core/include/esp/rom.h | 17 ++- core/include/esp/spi_regs.h | 30 +++-- core/include/flashchip.h | 39 +++++++ core/include/xtensa_ops.h | 13 ++- include/espressif/spi_flash.h | 23 +--- include/etstimer.h | 39 +++++++ opensdk/component.mk | 11 ++ opensdk/libmain/misc.c | 59 ++++++++++ opensdk/libmain/os_cpu_a.c | 121 ++++++++++++++++++++ opensdk/libmain/spi_flash.c | 183 +++++++++++++++++++++++++++++++ opensdk/libmain/timers.c | 89 +++++++++++++++ opensdk/libmain/uart.c | 17 +++ opensdk/libmain/xtensa_context.S | 41 +++++++ parameters.mk | 4 +- 14 files changed, 642 insertions(+), 44 deletions(-) create mode 100644 core/include/flashchip.h create mode 100644 include/etstimer.h create mode 100644 opensdk/component.mk create mode 100644 opensdk/libmain/misc.c create mode 100644 opensdk/libmain/os_cpu_a.c create mode 100644 opensdk/libmain/spi_flash.c create mode 100644 opensdk/libmain/timers.c create mode 100644 opensdk/libmain/uart.c create mode 100644 opensdk/libmain/xtensa_context.S diff --git a/core/include/esp/rom.h b/core/include/esp/rom.h index c2f8759..5c41e46 100644 --- a/core/include/esp/rom.h +++ b/core/include/esp/rom.h @@ -5,7 +5,9 @@ */ #ifndef _ESP_ROM_H #define _ESP_ROM_H -#include + +#include "esp/types.h" +#include "flashchip.h" #ifdef __cplusplus extern "C" { @@ -21,8 +23,19 @@ void Cache_Read_Disable(void); */ void Cache_Read_Enable(uint32_t odd_even, uint32_t mb_count, uint32_t no_idea); +/* Low-level SPI flash read/write routines */ +int Enable_QMode(sdk_flashchip_t *chip); +int Disable_QMode(sdk_flashchip_t *chip); +int SPI_page_program(sdk_flashchip_t *chip, uint32_t dest_addr, uint32_t *src_addr, uint32_t size); +int SPI_read_data(sdk_flashchip_t *chip, uint32_t src_addr, uint32_t *dest_addr, uint32_t size); +int SPI_write_enable(sdk_flashchip_t *chip); +int SPI_sector_erase(sdk_flashchip_t *chip, uint32_t addr); +int SPI_read_status(sdk_flashchip_t *chip, uint32_t *status); +int SPI_write_status(sdk_flashchip_t *chip, uint32_t status); +int Wait_SPI_Idle(sdk_flashchip_t *chip); + #ifdef __cplusplus } #endif -#endif +#endif /* _ESP_ROM_H */ diff --git a/core/include/esp/spi_regs.h b/core/include/esp/spi_regs.h index 37eb113..83b61af 100644 --- a/core/include/esp/spi_regs.h +++ b/core/include/esp/spi_regs.h @@ -46,22 +46,7 @@ struct SPI_REGS { uint32_t volatile SLAVE1; // 0x34 uint32_t volatile SLAVE2; // 0x38 uint32_t volatile SLAVE3; // 0x3c - uint32_t volatile W0; // 0x40 - uint32_t volatile W1; // 0x44 - uint32_t volatile W2; // 0x48 - uint32_t volatile W3; // 0x4c - uint32_t volatile W4; // 0x50 - uint32_t volatile W5; // 0x54 - uint32_t volatile W6; // 0x58 - uint32_t volatile W7; // 0x5c - uint32_t volatile W8; // 0x60 - uint32_t volatile W9; // 0x64 - uint32_t volatile W10; // 0x68 - uint32_t volatile W11; // 0x6c - uint32_t volatile W12; // 0x70 - uint32_t volatile W13; // 0x74 - uint32_t volatile W14; // 0x78 - uint32_t volatile W15; // 0x7c + uint32_t volatile W[16]; // 0x40 - 0x7c uint32_t volatile _unused[28]; // 0x80 - 0xec uint32_t volatile EXT0; // 0xf0 uint32_t volatile EXT1; // 0xf4 @@ -73,6 +58,19 @@ _Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size"); /* Details for CMD register */ +#define SPI_CMD_READ BIT(31) +#define SPI_CMD_WRITE_ENABLE BIT(30) +#define SPI_CMD_WRITE_DISABLE BIT(29) +#define SPI_CMD_READ_ID BIT(28) +#define SPI_CMD_READ_SR BIT(27) +#define SPI_CMD_WRITE_SR BIT(26) +#define SPI_CMD_PP BIT(25) +#define SPI_CMD_SE BIT(24) +#define SPI_CMD_BE BIT(23) +#define SPI_CMD_CE BIT(22) +#define SPI_CMD_DP BIT(21) +#define SPI_CMD_RES BIT(20) +#define SPI_CMD_HPM BIT(19) #define SPI_CMD_USR BIT(18) /* Details for CTRL0 register */ diff --git a/core/include/flashchip.h b/core/include/flashchip.h new file mode 100644 index 0000000..c14d4a3 --- /dev/null +++ b/core/include/flashchip.h @@ -0,0 +1,39 @@ +/* flashchip.h + * + * sdk_flashchip_t structure used by the SDK and some bootrom routines + * + * This is in a separate include file because it's referenced by several other + * headers which are otherwise independent of each other. + * + * Part of esp-open-rtos + * Copyright (C) 2015 Alex Stewart and Angus Gratton + * BSD Licensed as described in the file LICENSE + */ + +#ifndef _FLASHCHIP_H +#define _FLASHCHIP_H + +/* SDK/bootrom uses this structure internally to account for flash size. + + chip_size field is initialised during startup from the flash size + saved in the image header (on the first 8 bytes of SPI flash). + + Other field are initialised to hardcoded values by the SDK. + + ** NOTE: This structure is passed to some bootrom routines and is therefore + fixed. Be very careful if you want to change it that you do not break + things. ** + + Based on RE work by @foogod at + http://esp8266-re.foogod.com/wiki/Flashchip_%28IoT_RTOS_SDK_0.9.9%29 +*/ +typedef struct { + uint32_t device_id; + uint32_t chip_size; /* in bytes */ + uint32_t block_size; /* in bytes */ + uint32_t sector_size; /* in bytes */ + uint32_t page_size; /* in bytes */ + uint32_t status_mask; +} sdk_flashchip_t; + +#endif /* _FLASHCHIP_H */ diff --git a/core/include/xtensa_ops.h b/core/include/xtensa_ops.h index 52eba2a..6951869 100644 --- a/core/include/xtensa_ops.h +++ b/core/include/xtensa_ops.h @@ -11,9 +11,6 @@ #ifndef _XTENSA_OPS_H #define _XTENSA_OPS_H -// GCC macros for reading, writing, and exchanging Xtensa processor special -// registers: - /* Read stack pointer to variable. * * Note that the compiler will push a stack frame (minimum 16 bytes) @@ -28,8 +25,18 @@ */ #define RETADDR(var) asm volatile ("mov %0, a0" : "=r" (var)) +// GCC macros for reading, writing, and exchanging Xtensa processor special +// registers: + #define RSR(var, reg) asm volatile ("rsr %0, " #reg : "=r" (var)); #define WSR(var, reg) asm volatile ("wsr %0, " #reg : : "r" (var)); #define XSR(var, reg) asm volatile ("xsr %0, " #reg : "+r" (var)); +// GCC macros for performing associated "*sync" opcodes + +#define ISYNC() asm volatile ( "isync" ) +#define RSYNC() asm volatile ( "rsync" ) +#define ESYNC() asm volatile ( "esync" ) +#define DSYNC() asm volatile ( "dsync" ) + #endif /* _XTENSA_OPS_H */ diff --git a/include/espressif/spi_flash.h b/include/espressif/spi_flash.h index 44c8677..f08cda9 100644 --- a/include/espressif/spi_flash.h +++ b/include/espressif/spi_flash.h @@ -6,6 +6,8 @@ #ifndef __SPI_FLASH_H__ #define __SPI_FLASH_H__ +#include "flashchip.h" + #ifdef __cplusplus extern "C" { #endif @@ -44,29 +46,8 @@ sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, const void *src, uin */ sdk_SpiFlashOpResult sdk_spi_flash_read(uint32_t src_addr, void *des, uint32_t size); - -/* SDK uses this structure internally to account for flash size. - - chip_size field is initialised during startup from the flash size - saved in the image header (on the first 8 bytes of SPI flash). - - Other field are initialised to hardcoded values by the SDK. - - Based on RE work by @foogod at - http://esp8266-re.foogod.com/wiki/Flashchip_%28IoT_RTOS_SDK_0.9.9%29 -*/ -typedef struct { - uint32_t device_id; - uint32_t chip_size; /* in bytes */ - uint32_t block_size; /* in bytes */ - uint32_t sector_size; /* in bytes */ - uint32_t page_size; /* in bytes */ - uint32_t status_mask; -} sdk_flashchip_t; - extern sdk_flashchip_t sdk_flashchip; - #ifdef __cplusplus } #endif diff --git a/include/etstimer.h b/include/etstimer.h new file mode 100644 index 0000000..bcc914a --- /dev/null +++ b/include/etstimer.h @@ -0,0 +1,39 @@ +/* Structures and constants used by some SDK routines + * + * Part of esp-open-rtos + * Copyright (C) 2015 Superhouse Automation Pty Ltd + * BSD Licensed as described in the file LICENSE + */ + +/* Note: The following definitions are normally found (in the non-RTOS SDK) in + * the ets_sys.h distributed by Espressif. Unfortunately, they are not found + * anywhere in the RTOS SDK headers, and differ substantially from the non-RTOS + * versions, so the structures defined here had to be obtained by careful + * examination of the code found in the Espressif RTOS SDK. + */ + +/* Note also: These cannot be included in esp8266/ets_sys.h, because it is + * included from FreeRTOS.h, creating an (unnecessary) circular dependency. + * They have therefore been put into their own header file instead. + */ + +#ifndef _ETSTIMER_H +#define _ETSTIMER_H + +#include "FreeRTOS.h" +#include "timers.h" +#include "esp/types.h" + +typedef void ETSTimerFunc(void *); + +typedef struct ETSTimer_st { + struct ETSTimer_st *timer_next; + xTimerHandle timer_handle; + uint32_t _unknown; + uint32_t timer_ms; + ETSTimerFunc *timer_func; + bool timer_repeat; + void *timer_arg; +} ETSTimer; + +#endif /* _ETSTIMER_H */ diff --git a/opensdk/component.mk b/opensdk/component.mk new file mode 100644 index 0000000..26fa5ad --- /dev/null +++ b/opensdk/component.mk @@ -0,0 +1,11 @@ +# Component makefile for "open sdk libs" + +# args for passing into compile rule generation +opensdk_libmain_ROOT = $(opensdk_libmain_DEFAULT_ROOT)libmain +opensdk_libmain_INC_DIR = +opensdk_libmain_SRC_DIR = $(opensdk_libmain_ROOT) +opensdk_libmain_EXTRA_SRC_FILES = + +opensdk_libmain_CFLAGS = $(CFLAGS) + +$(eval $(call component_compile_rules,opensdk_libmain)) diff --git a/opensdk/libmain/misc.c b/opensdk/libmain/misc.c new file mode 100644 index 0000000..25a059d --- /dev/null +++ b/opensdk/libmain/misc.c @@ -0,0 +1,59 @@ +#include "espressif/esp_misc.h" +#include "esp/gpio_regs.h" +#include "esp/rtc_regs.h" +#include "sdk_internal.h" +#include "xtensa/hal.h" + +static int cpu_freq = 80; + +void (*sdk__putc1)(char); + +int IRAM sdk_os_get_cpu_frequency(void) { + return cpu_freq; +} + +void sdk_os_update_cpu_frequency(int freq) { + cpu_freq = freq; +} + +void sdk_ets_update_cpu_frequency(int freq) __attribute__ (( alias ("sdk_os_update_cpu_frequency") )); + +void sdk_os_delay_us(uint16_t us) { + uint32_t start_ccount = xthal_get_ccount(); + uint32_t delay_ccount = cpu_freq * us; + while (xthal_get_ccount() - start_ccount < delay_ccount) {} +} + +void sdk_ets_delay_us(uint16_t us) __attribute__ (( alias ("sdk_os_delay_us") )); + +void sdk_os_install_putc1(void (*p)(char)) { + sdk__putc1 = p; +} + +void sdk_os_putc(char c) { + sdk__putc1(c); +} + +void sdk_gpio_output_set(uint32_t set_mask, uint32_t clear_mask, uint32_t enable_mask, uint32_t disable_mask) { + GPIO.OUT_SET = set_mask; + GPIO.OUT_CLEAR = clear_mask; + GPIO.ENABLE_OUT_SET = enable_mask; + GPIO.ENABLE_OUT_CLEAR = disable_mask; +} + +uint8_t sdk_rtc_get_reset_reason(void) { + uint8_t reason; + + reason = FIELD2VAL(RTC_RESET_REASON1_CODE, RTC.RESET_REASON1); + if (reason == 5) { + if (FIELD2VAL(RTC_RESET_REASON2_CODE, RTC.RESET_REASON2) == 1) { + reason = 6; + } else { + if (FIELD2VAL(RTC_RESET_REASON2_CODE, RTC.RESET_REASON2) != 8) { + reason = 0; + } + } + } + RTC.RESET_REASON0 &= ~RTC_RESET_REASON0_SOMETHING; + return reason; +} diff --git a/opensdk/libmain/os_cpu_a.c b/opensdk/libmain/os_cpu_a.c new file mode 100644 index 0000000..4841ebe --- /dev/null +++ b/opensdk/libmain/os_cpu_a.c @@ -0,0 +1,121 @@ +#include "esp/types.h" +#include "FreeRTOS.h" +#include "task.h" +#include "xtensa_ops.h" +#include "common_macros.h" + +// xPortSysTickHandle is defined in FreeRTOS/Source/portable/esp8266/port.c but +// does not exist in any header files. +void xPortSysTickHandle(void); + +/* The following "functions" manipulate the stack at a low level and thus cannot be coded directly in C */ + +void IRAM vPortYield(void) { + asm(" wsr a0, excsave1 \n\ + addi sp, sp, -80 \n\ + s32i a0, sp, 4 \n\ + addi a0, sp, 80 \n\ + s32i a0, sp, 16 \n\ + rsr a0, ps \n\ + s32i a0, sp, 8 \n\ + rsr a0, excsave1 \n\ + s32i a0, sp, 12 \n\ + movi a0, _xt_user_exit \n\ + s32i a0, sp, 0 \n\ + call0 sdk__xt_int_enter \n\ + call0 vPortEnterCritical \n\ + call0 vTaskSwitchContext \n\ + call0 vPortExitCritical \n\ + call0 sdk__xt_int_exit \n\ + "); +} + +void IRAM sdk__xt_int_enter(void) { + asm(" s32i a12, sp, 60 \n\ + s32i a13, sp, 64 \n\ + mov a12, a0 \n\ + call0 sdk__xt_context_save \n\ + movi a0, pxCurrentTCB \n\ + l32i a0, a0, 0 \n\ + s32i sp, a0, 0 \n\ + mov a0, a12 \n\ + "); +} + +void IRAM sdk__xt_int_exit(void) { + asm(" s32i a14, sp, 68 \n\ + s32i a15, sp, 72 \n\ + movi sp, pxCurrentTCB \n\ + l32i sp, sp, 0 \n\ + l32i sp, sp, 0 \n\ + movi a14, pxCurrentTCB \n\ + l32i a14, a14, 0 \n\ + addi a15, sp, 80 \n\ + s32i a15, a14, 0 \n\ + call0 sdk__xt_context_restore \n\ + l32i a14, sp, 68 \n\ + l32i a15, sp, 72 \n\ + l32i a0, sp, 0 \n\ + "); +} + +void IRAM sdk__xt_timer_int(void) { + uint32_t trigger_ccount; + uint32_t current_ccount; + uint32_t ccount_interval = portTICK_RATE_MS * 80000; //FIXME + + do { + RSR(trigger_ccount, ccompare0); + WSR(trigger_ccount + ccount_interval, ccompare0); + ESYNC(); + xPortSysTickHandle(); + ESYNC(); + RSR(current_ccount, ccount); + } while (current_ccount - trigger_ccount > ccount_interval); +} + +void IRAM sdk__xt_timer_int1(void) { + vTaskSwitchContext(); +} + +#define INTENABLE_CCOMPARE BIT(6) + +void IRAM sdk__xt_tick_timer_init(void) { + uint32_t ints_enabled; + uint32_t current_ccount; + uint32_t ccount_interval = portTICK_RATE_MS * 80000; //FIXME + + RSR(current_ccount, ccount); + WSR(current_ccount + ccount_interval, ccompare0); + ints_enabled = 0; + XSR(ints_enabled, intenable); + WSR(ints_enabled | INTENABLE_CCOMPARE, intenable); +} + +void IRAM sdk__xt_isr_unmask(uint32_t mask) { + uint32_t ints_enabled; + + ints_enabled = 0; + XSR(ints_enabled, intenable); + WSR(ints_enabled | mask, intenable); +} + +void IRAM sdk__xt_isr_mask(uint32_t mask) { + uint32_t ints_enabled; + + ints_enabled = 0; + XSR(ints_enabled, intenable); + WSR(ints_enabled & mask, intenable); +} + +uint32_t IRAM sdk__xt_read_ints(void) { + uint32_t ints_enabled; + + RSR(ints_enabled, intenable); + return ints_enabled; +} + +void IRAM sdk__xt_clear_ints(uint32_t mask) { + WSR(mask, intclear); +} + diff --git a/opensdk/libmain/spi_flash.c b/opensdk/libmain/spi_flash.c new file mode 100644 index 0000000..2915c79 --- /dev/null +++ b/opensdk/libmain/spi_flash.c @@ -0,0 +1,183 @@ +#include "FreeRTOS.h" +#include "common_macros.h" +#include "esp/spi_regs.h" +#include "esp/rom.h" +#include "sdk_internal.h" +#include "espressif/spi_flash.h" + +sdk_flashchip_t sdk_flashchip = { + 0x001640ef, // device_id + 4 * 1024 * 1024, // chip_size + 65536, // block_size + 4096, // sector_size + 256, // page_size + 0x0000ffff, // status_mask +}; + +// NOTE: This routine appears to be completely unused in the SDK + +int IRAM sdk_SPIReadModeCnfig(uint32_t mode) { + uint32_t ctrl_bits; + + SPI(0).CTRL0 &= ~(SPI_CTRL0_FASTRD_MODE | SPI_CTRL0_DOUT_MODE | SPI_CTRL0_QOUT_MODE | SPI_CTRL0_DIO_MODE | SPI_CTRL0_QIO_MODE); + if (mode == 0) { + ctrl_bits = SPI_CTRL0_FASTRD_MODE | SPI_CTRL0_QIO_MODE; + } else if (mode == 1) { + ctrl_bits = SPI_CTRL0_FASTRD_MODE | SPI_CTRL0_QOUT_MODE; + } else if (mode == 2) { + ctrl_bits = SPI_CTRL0_FASTRD_MODE | SPI_CTRL0_DIO_MODE; + } else if (mode == 3) { + ctrl_bits = SPI_CTRL0_FASTRD_MODE | SPI_CTRL0_DOUT_MODE; + } else if (mode == 4) { + ctrl_bits = SPI_CTRL0_FASTRD_MODE; + } else { + ctrl_bits = 0; + } + if (mode == 0 || mode == 1) { + Enable_QMode(&sdk_flashchip); + } else { + Disable_QMode(&sdk_flashchip); + } + SPI(0).CTRL0 |= ctrl_bits; + return 0; +} + +sdk_SpiFlashOpResult IRAM sdk_SPIWrite(uint32_t des_addr, uint32_t *src_addr, uint32_t size) { + uint32_t first_page_portion; + uint32_t pos; + uint32_t full_pages; + uint32_t bytes_remaining; + + if (des_addr + size <= sdk_flashchip.chip_size) { + first_page_portion = sdk_flashchip.page_size - (des_addr % sdk_flashchip.page_size); + if (size < first_page_portion) { + if (SPI_page_program(&sdk_flashchip, des_addr, src_addr, size)) { + return SPI_FLASH_RESULT_ERR; + } else { + return SPI_FLASH_RESULT_OK; + } + } + } else { + return SPI_FLASH_RESULT_ERR; + } + if (SPI_page_program(&sdk_flashchip, des_addr, src_addr, first_page_portion)) { + return SPI_FLASH_RESULT_ERR; + } + pos = first_page_portion; + bytes_remaining = size - first_page_portion; + full_pages = bytes_remaining / sdk_flashchip.page_size; + if (full_pages) { + for (int i = 0; i != full_pages; i++) { + if (SPI_page_program(&sdk_flashchip, des_addr + pos, src_addr + (pos / 4), sdk_flashchip.page_size)) { + return SPI_FLASH_RESULT_ERR; + } + pos += sdk_flashchip.page_size; + } + bytes_remaining = size - pos; + } + if (SPI_page_program(&sdk_flashchip, des_addr + pos, src_addr + (pos / 4), bytes_remaining)) { + return SPI_FLASH_RESULT_ERR; + } + return SPI_FLASH_RESULT_OK; +} + +sdk_SpiFlashOpResult IRAM sdk_SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size) { + if (SPI_read_data(&sdk_flashchip, src_addr, des_addr, size)) { + return SPI_FLASH_RESULT_ERR; + } else { + return SPI_FLASH_RESULT_OK; + } +} + +sdk_SpiFlashOpResult IRAM sdk_SPIEraseSector(uint16_t sec) { + if (sec >= sdk_flashchip.chip_size / sdk_flashchip.sector_size) { + return SPI_FLASH_RESULT_ERR; + } + if (SPI_write_enable(&sdk_flashchip)) { + return SPI_FLASH_RESULT_ERR; + } + if (SPI_sector_erase(&sdk_flashchip, sdk_flashchip.sector_size * sec)) { + return SPI_FLASH_RESULT_ERR; + } + return SPI_FLASH_RESULT_OK; +} + +uint32_t IRAM sdk_spi_flash_get_id(void) { + uint32_t result; + + portENTER_CRITICAL(); + Cache_Read_Disable(); + Wait_SPI_Idle(&sdk_flashchip); + SPI(0).W[0] = 0; + SPI(0).CMD = SPI_CMD_READ_ID; + while (SPI(0).CMD != 0) {} + result = SPI(0).W[0] & 0x00ffffff; + Cache_Read_Enable(0, 0, 1); + portEXIT_CRITICAL(); + return result; +} + +sdk_SpiFlashOpResult IRAM sdk_spi_flash_read_status(uint32_t *status) { + sdk_SpiFlashOpResult result; + + portENTER_CRITICAL(); + Cache_Read_Disable(); + result = SPI_read_status(&sdk_flashchip, status); + Cache_Read_Enable(0, 0, 1); + portEXIT_CRITICAL(); + return result; +} + +sdk_SpiFlashOpResult IRAM sdk_spi_flash_write_status(uint32_t status) { + sdk_SpiFlashOpResult result; + + portENTER_CRITICAL(); + Cache_Read_Disable(); + result = SPI_write_status(&sdk_flashchip, status); + Cache_Read_Enable(0, 0, 1); + portEXIT_CRITICAL(); + return result; +} + +sdk_SpiFlashOpResult IRAM sdk_spi_flash_erase_sector(uint16_t sec) { + sdk_SpiFlashOpResult result; + + portENTER_CRITICAL(); + Cache_Read_Disable(); + result = sdk_SPIEraseSector(sec); + Cache_Read_Enable(0, 0, 1); + portEXIT_CRITICAL(); + return result; +} + +sdk_SpiFlashOpResult IRAM sdk_spi_flash_write(uint32_t des_addr, uint32_t *src_addr, uint32_t size) { + sdk_SpiFlashOpResult result; + + if (!src_addr) { + return SPI_FLASH_RESULT_ERR; + } + if (size & 3) { + size = (size & ~3) + 4; + } + portENTER_CRITICAL(); + Cache_Read_Disable(); + result = sdk_SPIWrite(des_addr, src_addr, size); + Cache_Read_Enable(0, 0, 1); + portEXIT_CRITICAL(); + return result; +} + +sdk_SpiFlashOpResult IRAM sdk_spi_flash_read(uint32_t src_addr, uint32_t *des_addr, uint32_t size) { + sdk_SpiFlashOpResult result; + + if (!des_addr) { + return SPI_FLASH_RESULT_ERR; + } + portENTER_CRITICAL(); + Cache_Read_Disable(); + result = sdk_SPIRead(src_addr, des_addr, size); + Cache_Read_Enable(0, 0, 1); + portEXIT_CRITICAL(); + return result; +} + diff --git a/opensdk/libmain/timers.c b/opensdk/libmain/timers.c new file mode 100644 index 0000000..1359fc1 --- /dev/null +++ b/opensdk/libmain/timers.c @@ -0,0 +1,89 @@ +#include "etstimer.h" + +struct timer_list_st { + struct timer_list_st *next; + ETSTimer *timer; +}; + +static struct timer_list_st *timer_list; +static uint8_t armed_timer_count; + +void sdk_os_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *parg) { + struct timer_list_st *entry = 0; + struct timer_list_st *new_entry; + struct timer_list_st **tailptr; + + if (timer_list) { + for (entry = timer_list; ; entry = entry->next) { + if (entry->timer == ptimer) { + if (ptimer->timer_arg == parg && ptimer->timer_func == pfunction) { + return; + } + if (ptimer->timer_handle) { + if (!xTimerDelete(ptimer->timer_handle, 50)) { + printf("Timer Delete Failed\n"); + } + armed_timer_count--; + } + ptimer->timer_func = pfunction; + ptimer->timer_arg = parg; + ptimer->timer_handle = 0; + ptimer->timer_ms = 0; + return; + } + if (!entry->next) { + break; + } + } + } + ptimer->timer_func = pfunction; + ptimer->timer_arg = parg; + ptimer->timer_handle = 0; + ptimer->timer_ms = 0; + new_entry = (struct timer_list_st *)pvPortMalloc(8); + new_entry->timer = ptimer; + new_entry->next = 0; + tailptr = &entry->next; + if (!timer_list) { + tailptr = &timer_list; + } + *tailptr = new_entry; +} + +void sdk_os_timer_arm(ETSTimer *ptimer, uint32_t milliseconds, bool repeat_flag) { + if (!ptimer->timer_handle) { + ptimer->timer_repeat = repeat_flag; + ptimer->timer_ms = milliseconds; + ptimer->timer_handle = xTimerCreate(0, milliseconds/10, repeat_flag, ptimer->timer_arg, ptimer->timer_func); + armed_timer_count++; + if (!ptimer->timer_handle) { + //FIXME: should print an error? (original code doesn't) + return; + } + } + if (ptimer->timer_repeat != repeat_flag) { + ptimer->timer_repeat = repeat_flag; + // FIXME: This is wrong. The original code is directly modifying + // internal FreeRTOS structures to try to change the uxAutoReload of an + // existing timer. The correct way to do this is probably to use + // xTimerDelete and then xTimerCreate to recreate the timer with a + // different uxAutoReload setting. + ((uint32_t *)ptimer->timer_handle)[7] = repeat_flag; + } + if (ptimer->timer_ms != milliseconds) { + ptimer->timer_ms = milliseconds; + xTimerChangePeriod(ptimer->timer_handle, milliseconds/10, 10); + } + if (!xTimerStart(ptimer->timer_handle, 50)) { + printf("Timer Start Failed\n"); + } +} + +void sdk_os_timer_disarm(ETSTimer *ptimer) { + if (ptimer->timer_handle) { + if (!xTimerStop(ptimer->timer_handle, 50)) { + printf("Timer Stop Failed\n"); + } + } +} + diff --git a/opensdk/libmain/uart.c b/opensdk/libmain/uart.c new file mode 100644 index 0000000..25ae961 --- /dev/null +++ b/opensdk/libmain/uart.c @@ -0,0 +1,17 @@ +#include "espressif/sdk_private.h" +#include "esp/uart_regs.h" + +void sdk_uart_buff_switch(void) { + /* No-Op */ +} + +void sdk_uart_div_modify(uint32_t uart_no, uint32_t new_divisor) { + UART(uart_no).CLOCK_DIVIDER = new_divisor; + UART(uart_no).CONF0 |= (UART_CONF0_TXFIFO_RESET | UART_CONF0_RXFIFO_RESET); + UART(uart_no).CONF0 &= ~(UART_CONF0_TXFIFO_RESET | UART_CONF0_RXFIFO_RESET); +} + +void sdk_Uart_Init(void) { + /* No-Op */ +} + diff --git a/opensdk/libmain/xtensa_context.S b/opensdk/libmain/xtensa_context.S new file mode 100644 index 0000000..511877e --- /dev/null +++ b/opensdk/libmain/xtensa_context.S @@ -0,0 +1,41 @@ + .section .iram1.text, "ax", @progbits + + .balign 4 + .global sdk__xt_context_save + .type sdk__xt_context_save, @function +sdk__xt_context_save: + + s32i a2, sp, 20 + s32i a3, sp, 24 + s32i a4, sp, 28 + s32i a5, sp, 32 + s32i a6, sp, 36 + s32i a7, sp, 40 + s32i a8, sp, 44 + s32i a9, sp, 48 + s32i a10, sp, 52 + s32i a11, sp, 56 + rsr a3, sar + s32i a3, sp, 76 + ret + + .balign 4 + .global sdk__xt_context_restore + .type sdk__xt_context_restore, @function +sdk__xt_context_restore: + l32i a3, sp, 76 + l32i a2, sp, 20 + wsr a3, sar + l32i a3, sp, 24 + l32i a4, sp, 28 + l32i a5, sp, 32 + l32i a6, sp, 36 + l32i a7, sp, 40 + l32i a8, sp, 44 + l32i a9, sp, 48 + l32i a10, sp, 52 + l32i a11, sp, 56 + l32i a12, sp, 60 + l32i a13, sp, 64 + ret + diff --git a/parameters.mk b/parameters.mk index e750e83..f14a26b 100644 --- a/parameters.mk +++ b/parameters.mk @@ -60,7 +60,7 @@ OBJDUMP = $(CROSS)objdump # Source components to compile and link. Each of these are subdirectories # of the root, with a 'component.mk' file. -COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core +COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core opensdk # binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking. SDK_LIBS ?= main net80211 phy pp wpa @@ -114,7 +114,7 @@ else ifeq ($(FLAVOR),sdklike) # the output of the compiler used to build the SDK libs (for comparison of # disassemblies when coding replacement routines). It is not normally # intended to be used otherwise. - CFLAGS += -O2 -Os -fno-inline -fno-ipa-cp -fno-toplevel-reorder + CFLAGS += -O2 -Os -fno-inline -fno-ipa-cp -fno-toplevel-reorder -fno-caller-saves -fconserve-stack LDFLAGS += -O2 else C_CXX_FLAGS += -g -O2 From eee4a3660cd7f52776b02685294dd88ce7712160 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Tue, 22 Mar 2016 16:26:53 -0700 Subject: [PATCH 08/26] Rename opensdk dir to open_esplibs --- {opensdk => open_esplibs}/component.mk | 0 {opensdk => open_esplibs}/libmain/misc.c | 0 {opensdk => open_esplibs}/libmain/os_cpu_a.c | 0 {opensdk => open_esplibs}/libmain/spi_flash.c | 0 {opensdk => open_esplibs}/libmain/timers.c | 0 {opensdk => open_esplibs}/libmain/uart.c | 0 {opensdk => open_esplibs}/libmain/xtensa_context.S | 0 parameters.mk | 2 +- 8 files changed, 1 insertion(+), 1 deletion(-) rename {opensdk => open_esplibs}/component.mk (100%) rename {opensdk => open_esplibs}/libmain/misc.c (100%) rename {opensdk => open_esplibs}/libmain/os_cpu_a.c (100%) rename {opensdk => open_esplibs}/libmain/spi_flash.c (100%) rename {opensdk => open_esplibs}/libmain/timers.c (100%) rename {opensdk => open_esplibs}/libmain/uart.c (100%) rename {opensdk => open_esplibs}/libmain/xtensa_context.S (100%) diff --git a/opensdk/component.mk b/open_esplibs/component.mk similarity index 100% rename from opensdk/component.mk rename to open_esplibs/component.mk diff --git a/opensdk/libmain/misc.c b/open_esplibs/libmain/misc.c similarity index 100% rename from opensdk/libmain/misc.c rename to open_esplibs/libmain/misc.c diff --git a/opensdk/libmain/os_cpu_a.c b/open_esplibs/libmain/os_cpu_a.c similarity index 100% rename from opensdk/libmain/os_cpu_a.c rename to open_esplibs/libmain/os_cpu_a.c diff --git a/opensdk/libmain/spi_flash.c b/open_esplibs/libmain/spi_flash.c similarity index 100% rename from opensdk/libmain/spi_flash.c rename to open_esplibs/libmain/spi_flash.c diff --git a/opensdk/libmain/timers.c b/open_esplibs/libmain/timers.c similarity index 100% rename from opensdk/libmain/timers.c rename to open_esplibs/libmain/timers.c diff --git a/opensdk/libmain/uart.c b/open_esplibs/libmain/uart.c similarity index 100% rename from opensdk/libmain/uart.c rename to open_esplibs/libmain/uart.c diff --git a/opensdk/libmain/xtensa_context.S b/open_esplibs/libmain/xtensa_context.S similarity index 100% rename from opensdk/libmain/xtensa_context.S rename to open_esplibs/libmain/xtensa_context.S diff --git a/parameters.mk b/parameters.mk index f14a26b..8c6a8a3 100644 --- a/parameters.mk +++ b/parameters.mk @@ -60,7 +60,7 @@ OBJDUMP = $(CROSS)objdump # Source components to compile and link. Each of these are subdirectories # of the root, with a 'component.mk' file. -COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core opensdk +COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core open_esplibs # binary esp-iot-rtos SDK libraries to link. These are pre-processed prior to linking. SDK_LIBS ?= main net80211 phy pp wpa From 4d6fa0ccfa593ff9fbe0c789771a2309066b4e85 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Tue, 22 Mar 2016 17:11:18 -0700 Subject: [PATCH 09/26] Misc post-merge fixups --- core/esp_spi.c | 6 +++--- include/espressif/spi_flash.h | 8 ++++++-- open_esplibs/libmain/timers.c | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/core/esp_spi.c b/core/esp_spi.c index c6c0546..7a8704c 100644 --- a/core/esp_spi.c +++ b/core/esp_spi.c @@ -178,7 +178,7 @@ static void _spi_buf_prepare(uint8_t bus, size_t len, spi_endianness_t e, spi_wo if (e == SPI_LITTLE_ENDIAN || word_size == SPI_32BIT) return; size_t count = word_size == SPI_16BIT ? (len + 1) / 2 : (len + 3) / 4; - uint32_t *data = (uint32_t *)&SPI(bus).W0; + uint32_t *data = (uint32_t *)SPI(bus).W; for (size_t i = 0; i < count; i ++) { data[i] = word_size == SPI_16BIT @@ -193,14 +193,14 @@ static void _spi_buf_transfer(uint8_t bus, const void *out_data, void *in_data, _wait(bus); size_t bytes = len * (uint8_t)word_size; _set_size(bus, bytes); - memcpy((void *)&SPI(bus).W0, out_data, bytes); + memcpy((void *)SPI(bus).W, out_data, bytes); _spi_buf_prepare(bus, len, e, word_size); _start(bus); _wait(bus); if (in_data) { _spi_buf_prepare(bus, len, e, word_size); - memcpy(in_data, (void *)&SPI(bus).W0, bytes); + memcpy(in_data, (void *)SPI(bus).W, bytes); } } diff --git a/include/espressif/spi_flash.h b/include/espressif/spi_flash.h index f08cda9..61f8ae9 100644 --- a/include/espressif/spi_flash.h +++ b/include/espressif/spi_flash.h @@ -36,7 +36,7 @@ sdk_SpiFlashOpResult sdk_spi_flash_erase_sector(uint16_t sec); src is pointer to a buffer to read bytes from. Should be 4-byte aligned. size is length of buffer in bytes. Should be a multiple of 4. */ -sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, const void *src, uint32_t size); +sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, uint32_t *src, uint32_t size); /* Read data from flash. @@ -44,8 +44,12 @@ sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, const void *src, uin des is pointer to a buffer to read bytes into. Should be 4-byte aligned. size is number of bytes to read. Should be a multiple of 4. */ -sdk_SpiFlashOpResult sdk_spi_flash_read(uint32_t src_addr, void *des, uint32_t size); +sdk_SpiFlashOpResult sdk_spi_flash_read(uint32_t src_addr, uint32_t *des, uint32_t size); +/* SDK uses this structure internally to account for flash size. + + See flashchip.h for more info. +*/ extern sdk_flashchip_t sdk_flashchip; #ifdef __cplusplus diff --git a/open_esplibs/libmain/timers.c b/open_esplibs/libmain/timers.c index 1359fc1..1e2a920 100644 --- a/open_esplibs/libmain/timers.c +++ b/open_esplibs/libmain/timers.c @@ -1,4 +1,5 @@ #include "etstimer.h" +#include "stdio.h" struct timer_list_st { struct timer_list_st *next; From 3e5af479bc1f02027db340d57870313d02425987 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Tue, 22 Mar 2016 17:43:07 -0700 Subject: [PATCH 10/26] Add conditional compilation for open_esplib code --- open_esplibs/component.mk | 18 ++++++++------ open_esplibs/include/open_esplibs.h | 36 +++++++++++++++++++++++++++ open_esplibs/libmain/misc.c | 6 +++++ open_esplibs/libmain/os_cpu_a.c | 5 ++++ open_esplibs/libmain/spi_flash.c | 5 ++++ open_esplibs/libmain/timers.c | 5 ++++ open_esplibs/libmain/uart.c | 5 ++++ open_esplibs/libmain/xtensa_context.S | 5 ++++ 8 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 open_esplibs/include/open_esplibs.h diff --git a/open_esplibs/component.mk b/open_esplibs/component.mk index 26fa5ad..23c8b6a 100644 --- a/open_esplibs/component.mk +++ b/open_esplibs/component.mk @@ -1,11 +1,15 @@ -# Component makefile for "open sdk libs" +# Component makefile for "open Espressif libs" + +INC_DIRS += $(open_esplibs_ROOT)include + +$(eval $(call component_compile_rules,open_esplibs)) # args for passing into compile rule generation -opensdk_libmain_ROOT = $(opensdk_libmain_DEFAULT_ROOT)libmain -opensdk_libmain_INC_DIR = -opensdk_libmain_SRC_DIR = $(opensdk_libmain_ROOT) -opensdk_libmain_EXTRA_SRC_FILES = +open_esplibs_libmain_ROOT = $(open_esplibs_libmain_DEFAULT_ROOT)libmain +open_esplibs_libmain_INC_DIR = +open_esplibs_libmain_SRC_DIR = $(open_esplibs_libmain_ROOT) +open_esplibs_libmain_EXTRA_SRC_FILES = -opensdk_libmain_CFLAGS = $(CFLAGS) +open_esplibs_libmain_CFLAGS = $(CFLAGS) -$(eval $(call component_compile_rules,opensdk_libmain)) +$(eval $(call component_compile_rules,open_esplibs_libmain)) diff --git a/open_esplibs/include/open_esplibs.h b/open_esplibs/include/open_esplibs.h new file mode 100644 index 0000000..5443fef --- /dev/null +++ b/open_esplibs/include/open_esplibs.h @@ -0,0 +1,36 @@ +#ifndef _OPEN_ESPLIBS_H +#define _OPEN_ESPLIBS_H + +// This header includes conditional defines to control which bits of the +// Open-Source libraries get built when building esp-open-rtos. This can be +// useful for quickly troubleshooting whether a bug is due to the +// reimplementation of Espressif libraries, or something else. + +#ifndef OPEN_ESPLIBS +#define OPEN_ESPLIBS 1 +#endif + +#ifndef OPEN_LIBMAIN +#define OPEN_LIBMAIN (OPEN_ESPLIBS) +#endif + +#ifndef OPEN_LIBMAIN_MISC +#define OPEN_LIBMAIN_MISC (OPEN_LIBMAIN) +#endif +#ifndef OPEN_LIBMAIN_OS_CPU_A +#define OPEN_LIBMAIN_OS_CPU_A (OPEN_LIBMAIN) +#endif +#ifndef OPEN_LIBMAIN_SPI_FLASH +#define OPEN_LIBMAIN_SPI_FLASH (OPEN_LIBMAIN) +#endif +#ifndef OPEN_LIBMAIN_TIMERS +#define OPEN_LIBMAIN_TIMERS (OPEN_LIBMAIN) +#endif +#ifndef OPEN_LIBMAIN_UART +#define OPEN_LIBMAIN_UART (OPEN_LIBMAIN) +#endif +#ifndef OPEN_LIBMAIN_XTENSA_CONTEXT +#define OPEN_LIBMAIN_XTENSA_CONTEXT (OPEN_LIBMAIN) +#endif + +#endif /* _OPEN_ESPLIBS_H */ diff --git a/open_esplibs/libmain/misc.c b/open_esplibs/libmain/misc.c index 25a059d..8029a38 100644 --- a/open_esplibs/libmain/misc.c +++ b/open_esplibs/libmain/misc.c @@ -1,3 +1,7 @@ +#include "open_esplibs.h" +#if OPEN_LIBMAIN_MISC +// The contents of this file are only built if OPEN_LIBMAIN_MISC is set to true + #include "espressif/esp_misc.h" #include "esp/gpio_regs.h" #include "esp/rtc_regs.h" @@ -57,3 +61,5 @@ uint8_t sdk_rtc_get_reset_reason(void) { RTC.RESET_REASON0 &= ~RTC_RESET_REASON0_SOMETHING; return reason; } + +#endif /* OPEN_LIBMAIN_MISC */ diff --git a/open_esplibs/libmain/os_cpu_a.c b/open_esplibs/libmain/os_cpu_a.c index 4841ebe..7908b6f 100644 --- a/open_esplibs/libmain/os_cpu_a.c +++ b/open_esplibs/libmain/os_cpu_a.c @@ -1,3 +1,7 @@ +#include "open_esplibs.h" +#if OPEN_LIBMAIN_OS_CPU_A +// The contents of this file are only built if OPEN_LIBMAIN_OS_CPU_A is set to true + #include "esp/types.h" #include "FreeRTOS.h" #include "task.h" @@ -119,3 +123,4 @@ void IRAM sdk__xt_clear_ints(uint32_t mask) { WSR(mask, intclear); } +#endif /* OPEN_LIBMAIN_OS_CPU_A */ diff --git a/open_esplibs/libmain/spi_flash.c b/open_esplibs/libmain/spi_flash.c index 2915c79..ee2d2f4 100644 --- a/open_esplibs/libmain/spi_flash.c +++ b/open_esplibs/libmain/spi_flash.c @@ -1,3 +1,7 @@ +#include "open_esplibs.h" +#if OPEN_LIBMAIN_SPI_FLASH +// The contents of this file are only built if OPEN_LIBMAIN_SPI_FLASH is set to true + #include "FreeRTOS.h" #include "common_macros.h" #include "esp/spi_regs.h" @@ -181,3 +185,4 @@ sdk_SpiFlashOpResult IRAM sdk_spi_flash_read(uint32_t src_addr, uint32_t *des_ad return result; } +#endif /* OPEN_LIBMAIN_SPI_FLASH */ diff --git a/open_esplibs/libmain/timers.c b/open_esplibs/libmain/timers.c index 1e2a920..d460088 100644 --- a/open_esplibs/libmain/timers.c +++ b/open_esplibs/libmain/timers.c @@ -1,3 +1,7 @@ +#include "open_esplibs.h" +#if OPEN_LIBMAIN_TIMERS +// The contents of this file are only built if OPEN_LIBMAIN_TIMERS is set to true + #include "etstimer.h" #include "stdio.h" @@ -88,3 +92,4 @@ void sdk_os_timer_disarm(ETSTimer *ptimer) { } } +#endif /* OPEN_LIBMAIN_TIMERS */ diff --git a/open_esplibs/libmain/uart.c b/open_esplibs/libmain/uart.c index 25ae961..5ee2699 100644 --- a/open_esplibs/libmain/uart.c +++ b/open_esplibs/libmain/uart.c @@ -1,3 +1,7 @@ +#include "open_esplibs.h" +#if OPEN_LIBMAIN_UART +// The contents of this file are only built if OPEN_LIBMAIN_UART is set to true + #include "espressif/sdk_private.h" #include "esp/uart_regs.h" @@ -15,3 +19,4 @@ void sdk_Uart_Init(void) { /* No-Op */ } +#endif /* OPEN_LIBMAIN_UART */ diff --git a/open_esplibs/libmain/xtensa_context.S b/open_esplibs/libmain/xtensa_context.S index 511877e..139d5db 100644 --- a/open_esplibs/libmain/xtensa_context.S +++ b/open_esplibs/libmain/xtensa_context.S @@ -1,3 +1,7 @@ +#include "open_esplibs.h" +#if OPEN_LIBMAIN_XTENSA_CONTEXT +// The contents of this file are only built if OPEN_LIBMAIN_XTENSA_CONTEXT is set to true + .section .iram1.text, "ax", @progbits .balign 4 @@ -39,3 +43,4 @@ sdk__xt_context_restore: l32i a13, sp, 64 ret +#endif /* OPEN_LIBMAIN_XTENSA_CONTEXT */ From 8c9a77efe877e3da39cd6b504c3de3fc5e9a421c Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Tue, 5 Apr 2016 09:23:28 -0700 Subject: [PATCH 11/26] Added first half of RE'd user_interface.c --- core/app_main.c | 9 +- core/debug_dumps.c | 2 +- core/include/esp/dport_regs.h | 4 + core/include/esp/rtc_regs.h | 8 +- core/include/esp/sar_regs.h | 39 ++ core/include/sdk_internal.h | 40 +- examples/http_get_mbedtls/Makefile | 2 +- examples/pwm_test/Makefile | 2 +- examples/tls_server/Makefile | 2 +- include/espressif/esp_misc.h | 2 + include/espressif/esp_system.h | 4 +- include/espressif/osapi.h | 8 + include/espressif/user_interface.h | 27 + open_esplibs/include/esplibs/libmain.h | 19 + open_esplibs/include/esplibs/libnet80211.h | 14 + open_esplibs/include/esplibs/libphy.h | 8 + open_esplibs/include/esplibs/libpp.h | 32 ++ open_esplibs/include/open_esplibs.h | 3 + open_esplibs/libmain/misc.c | 2 +- open_esplibs/libmain/user_interface.c | 548 +++++++++++++++++++++ 20 files changed, 745 insertions(+), 30 deletions(-) create mode 100644 core/include/esp/sar_regs.h create mode 100644 include/espressif/osapi.h create mode 100644 include/espressif/user_interface.h create mode 100644 open_esplibs/include/esplibs/libmain.h create mode 100644 open_esplibs/include/esplibs/libnet80211.h create mode 100644 open_esplibs/include/esplibs/libphy.h create mode 100644 open_esplibs/include/esplibs/libpp.h create mode 100644 open_esplibs/libmain/user_interface.c diff --git a/core/app_main.c b/core/app_main.c index ebf9e9a..ac74426 100644 --- a/core/app_main.c +++ b/core/app_main.c @@ -27,6 +27,7 @@ #include "espressif/esp_common.h" #include "espressif/phy_info.h" #include "sdk_internal.h" +#include "esplibs/libmain.h" /* This is not declared in any header file (but arguably should be) */ @@ -345,8 +346,8 @@ static __attribute__((noinline)) void user_start_phase2(void) { sdk_phy_info_t phy_info, default_phy_info; sdk_system_rtc_mem_read(0, &sdk_rst_if, sizeof(sdk_rst_if)); - if (sdk_rst_if.version > 3) { - // Bad version number. Probably garbage. + if (sdk_rst_if.reason > 3) { + // Bad reason. Probably garbage. bzero(&sdk_rst_if, sizeof(sdk_rst_if)); } buf = malloc(sizeof(sdk_rst_if)); @@ -357,8 +358,8 @@ static __attribute__((noinline)) void user_start_phase2(void) { get_otp_mac_address(sdk_info.sta_mac_addr); sdk_wifi_softap_cacl_mac(sdk_info.softap_mac_addr, sdk_info.sta_mac_addr); sdk_info._unknown0 = 0x0104a8c0; - sdk_info._unknown1 = 0x00ffffff; - sdk_info._unknown2 = 0x0104a8c0; + sdk_info._unknown4 = 0x00ffffff; + sdk_info._unknown8 = 0x0104a8c0; init_g_ic(); read_saved_phy_info(&phy_info); diff --git a/core/debug_dumps.c b/core/debug_dumps.c index 7f1a1ca..c5af763 100644 --- a/core/debug_dumps.c +++ b/core/debug_dumps.c @@ -20,7 +20,7 @@ #include "esp/rom.h" #include "esp/uart.h" #include "espressif/esp_common.h" -#include "sdk_internal.h" +#include "esplibs/libmain.h" /* Forward declarations */ static void IRAM fatal_handler_prelude(void); diff --git a/core/include/esp/dport_regs.h b/core/include/esp/dport_regs.h index 87efca1..d04de2f 100644 --- a/core/include/esp/dport_regs.h +++ b/core/include/esp/dport_regs.h @@ -90,6 +90,10 @@ _Static_assert(sizeof(struct DPORT_REGS) == 0x60, "DPORT_REGS is the wrong size" /* Details for CLOCKGATE_WATCHDOG register */ +// Set and then cleared during sdk_system_restart_in_nmi(). +// Not sure what this does. May be related to ESPSAR.UNKNOWN_48 +#define DPORT_CLOCKGATE_WATCHDOG_UNKNOWN_8 BIT(8) + /* Comment found in pvvx/mp3_decode headers: "use clockgate_watchdog(flg) { if(flg) 0x3FF00018 &= 0x77; else 0x3FF00018 |= 8; }". Not sure what this means or does. */ #define DPORT_CLOCKGATE_WATCHDOG_DISABLE BIT(3) diff --git a/core/include/esp/rtc_regs.h b/core/include/esp/rtc_regs.h index 4acb2a3..1798498 100644 --- a/core/include/esp/rtc_regs.h +++ b/core/include/esp/rtc_regs.h @@ -31,7 +31,8 @@ struct RTC_REGS { uint32_t volatile CTRL0; // 0x00 uint32_t volatile COUNTER_ALARM; // 0x04 uint32_t volatile RESET_REASON0; // 0x08 //FIXME: need better name - uint32_t volatile _unknownc[2]; // 0x0c - 0x10 + uint32_t volatile _unknownc; // 0x0c + uint32_t volatile _unknown10; // 0x10 uint32_t volatile RESET_REASON1; // 0x14 //FIXME: need better name uint32_t volatile RESET_REASON2; // 0x18 //FIXME: need better name uint32_t volatile COUNTER; // 0x1c @@ -40,7 +41,10 @@ struct RTC_REGS { uint32_t volatile INT_ENABLE; // 0x28 uint32_t volatile _unknown2c; // 0x2c uint32_t volatile SCRATCH[4]; // 0x30 - 3c - uint32_t volatile _unknown40[10]; // 0x40 - 0x64 + uint32_t volatile _unknown40; // 0x40 + uint32_t volatile _unknown44; // 0x44 + uint32_t volatile _unknown48; // 0x48 + uint32_t volatile _unknown4c[7]; // 0x4c - 0x64 uint32_t volatile GPIO_OUT; // 0x68 uint32_t volatile _unknown6c[2]; // 0x6c - 0x70 uint32_t volatile GPIO_ENABLE; // 0x74 diff --git a/core/include/esp/sar_regs.h b/core/include/esp/sar_regs.h new file mode 100644 index 0000000..b0266b7 --- /dev/null +++ b/core/include/esp/sar_regs.h @@ -0,0 +1,39 @@ +/* esp/sar_regs.h + * + * ESP8266 register definitions for the "sar" region (0x3FF2xxx) + * + * The 0x60000D00 register region is referred to as "sar" by some old header + * files. Apparently referenced both by ROM I2C functions as well as ADC + * config/read functions. + * + * Not compatible with ESP SDK register access code. + */ + +#ifndef _ESP_SAR_REGS_H +#define _ESP_SAR_REGS_H + +#include "esp/types.h" +#include "common_macros.h" + +#define SAR_BASE 0x60000d00 +// Unfortunately, +// esp-open-sdk/xtensa-lx106-elf/xtensa-lx106-elf/sysroot/usr/include/xtensa/config/specreg.h +// already has a "SAR" macro definition which would conflict with this, so +// we'll use "ESPSAR" instead.. +#define ESPSAR (*(struct SAR_REGS *)(SAR_BASE)) + +/* Note: This memory region is not currently well understood. Pretty much all + * of the definitions here are from reverse-engineering the Espressif SDK code, + * many are just educated guesses, and almost certainly some are misleading or + * wrong. If you can improve on any of this, please contribute! + */ + +struct SAR_REGS { + uint32_t volatile _unknown0[18]; // 0x00 - 0x44 + uint32_t volatile UNKNOWN_48; // 0x48 : used by sdk_system_restart_in_nmi() +} __attribute__ (( packed )); + +_Static_assert(sizeof(struct SAR_REGS) == 0x4c, "SAR_REGS is the wrong size"); + +#endif /* _ESP_SAR_REGS_H */ + diff --git a/core/include/sdk_internal.h b/core/include/sdk_internal.h index b8233fd..4e3faa5 100644 --- a/core/include/sdk_internal.h +++ b/core/include/sdk_internal.h @@ -4,6 +4,7 @@ #include "espressif/esp_wifi.h" #include "espressif/spi_flash.h" #include "espressif/phy_info.h" +#include "etstimer.h" #include "lwip/netif.h" /////////////////////////////////////////////////////////////////////////////// @@ -13,31 +14,38 @@ // 'info' is declared in app_main.o at .bss+0x4 struct sdk_info_st { - uint32_t _unknown0; - uint32_t _unknown1; - uint32_t _unknown2; - uint8_t _unknown3[12]; - uint8_t softap_mac_addr[6]; - uint8_t sta_mac_addr[6]; + uint32_t _unknown0; // 0x00 + uint32_t _unknown4; // 0x04 + uint32_t _unknown8; // 0x08 + ip_addr_t ipaddr; // 0x0c + ip_addr_t netmask; // 0x10 + ip_addr_t gw; // 0x14 + uint8_t softap_mac_addr[6]; // 0x18 + uint8_t sta_mac_addr[6]; // 0x1e }; extern struct sdk_info_st sdk_info; // 'rst_if' is declared in user_interface.o at .bss+0xfc - -struct sdk_rst_if_st { - uint32_t version; - uint8_t _unknown[28]; -}; - -extern struct sdk_rst_if_st sdk_rst_if; +extern struct sdk_rst_info sdk_rst_if; // 'g_ic' is declared in libnet80211/ieee80211.o at .bss+0x0 // See also: http://esp8266-re.foogod.com/wiki/G_ic_(IoT_RTOS_SDK_0.9.9) struct sdk_g_ic_netif_info { - struct netif *netif; - //TODO: rest of this structure is unknown. + struct netif *netif; // 0x00 + ETSTimer timer; // 0x04 - 0x20 + uint8_t _unknown20[28]; // 0x20 - 0x3c + uint32_t _unknown3c; // 0x3c (referenced by sdk_wifi_station_disconnect) + uint8_t _unknown40[6]; // 0x40 - 0x46 + uint8_t _unknown46[66]; // 0x46 - 0x88 + struct sdk_netif_conninfo *_unknown88; // 0x88 + uint32_t _unknown8c; // 0x8c + struct sdk_netif_conninfo *conninfo[6]; // 0x90 - 0xa8 + uint8_t _unknowna8[16]; // 0xa8 - 0xb8 + uint8_t _unknownb8; // 0xb8 (referenced by sdk_wifi_station_connect / sdk_wifi_station_disconnect) + uint8_t _unknownb9; // 0xb9 (referenced by sdk_wifi_station_connect / sdk_wifi_station_disconnect) + uint8_t connect_status; // 0xba (referenced by sdk_system_station_got_ip_set / sdk_wifi_station_disconnect) }; // This is the portion of g_ic which is not loaded/saved to the flash ROM, and @@ -197,7 +205,6 @@ extern struct sdk_g_ic_st sdk_g_ic; /////////////////////////////////////////////////////////////////////////////// _Static_assert(sizeof(struct sdk_info_st) == 0x24, "info_st is the wrong size!"); -_Static_assert(sizeof(struct sdk_rst_if_st) == 0x20, "sdk_rst_if_st is the wrong size!"); _Static_assert(sizeof(struct sdk_g_ic_volatile_st) == 0x1d8, "sdk_g_ic_volatile_st is the wrong size!"); _Static_assert(sizeof(struct sdk_g_ic_saved_st) == 0x370, "sdk_g_ic_saved_st is the wrong size!"); _Static_assert(sizeof(struct sdk_g_ic_st) == 0x548, "sdk_g_ic_st is the wrong size!"); @@ -221,7 +228,6 @@ void sdk_pp_soft_wdt_init(void); int sdk_register_chipv6_phy(sdk_phy_info_t *); void sdk_sleep_reset_analog_rtcreg_8266(void); uint32_t sdk_system_get_checksum(uint8_t *, uint32_t); -void sdk_system_restart_in_nmi(void); void sdk_wDevEnableRx(void); void sdk_wDev_Initialize(void); void sdk_wifi_mode_set(uint8_t); diff --git a/examples/http_get_mbedtls/Makefile b/examples/http_get_mbedtls/Makefile index fc9a4fa..7e7a432 100644 --- a/examples/http_get_mbedtls/Makefile +++ b/examples/http_get_mbedtls/Makefile @@ -1,4 +1,4 @@ PROGRAM=http_get_mbedtls -COMPONENTS = FreeRTOS lwip core extras/mbedtls +EXTRA_COMPONENTS = extras/mbedtls include ../../common.mk diff --git a/examples/pwm_test/Makefile b/examples/pwm_test/Makefile index 36ee7d0..574420d 100644 --- a/examples/pwm_test/Makefile +++ b/examples/pwm_test/Makefile @@ -1,4 +1,4 @@ # Simple makefile for simple example PROGRAM=pwm_test -COMPONENTS = FreeRTOS lwip core extras/pwm +EXTRA_COMPONENTS = extras/pwm include ../../common.mk diff --git a/examples/tls_server/Makefile b/examples/tls_server/Makefile index 2c5ef2c..1070e91 100644 --- a/examples/tls_server/Makefile +++ b/examples/tls_server/Makefile @@ -1,4 +1,4 @@ PROGRAM=tls_server -COMPONENTS = FreeRTOS lwip core extras/mbedtls +EXTRA_COMPONENTS = extras/mbedtls include ../../common.mk diff --git a/include/espressif/esp_misc.h b/include/espressif/esp_misc.h index 6490fa5..8427d60 100644 --- a/include/espressif/esp_misc.h +++ b/include/espressif/esp_misc.h @@ -27,6 +27,8 @@ void sdk_os_delay_us(uint16_t us); void sdk_os_install_putc1(void (*p)(char c)); void sdk_os_putc(char c); +void sdk_gpio_output_set(uint32_t set_mask, uint32_t clear_mask, uint32_t enable_mask, uint32_t disable_mask); + #ifdef __cplusplus } #endif diff --git a/include/espressif/esp_system.h b/include/espressif/esp_system.h index 04af582..abeb26a 100644 --- a/include/espressif/esp_system.h +++ b/include/espressif/esp_system.h @@ -54,8 +54,8 @@ uint32_t sdk_system_get_chip_id(void); uint32_t sdk_system_rtc_clock_cali_proc(void); uint32_t sdk_system_get_rtc_time(void); -bool sdk_system_rtc_mem_read(uint8_t src, void *dst, uint16_t n); -bool sdk_system_rtc_mem_write(uint8_t dst, const void *src, uint16_t n); +bool sdk_system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint16_t save_size); +bool sdk_system_rtc_mem_write(uint32_t des_addr, void *src_addr, uint16_t save_size); void sdk_system_uart_swap(void); void sdk_system_uart_de_swap(void); diff --git a/include/espressif/osapi.h b/include/espressif/osapi.h new file mode 100644 index 0000000..1c1808f --- /dev/null +++ b/include/espressif/osapi.h @@ -0,0 +1,8 @@ +#ifndef _OSAPI_H_ +#define _OSAPI_H_ + +void sdk_os_timer_setfn(ETSTimer *ptimer, ETSTimerFunc *pfunction, void *parg); +void sdk_os_timer_arm(ETSTimer *ptimer, uint32_t milliseconds, bool repeat_flag); +void sdk_os_timer_disarm(ETSTimer *ptimer); + +#endif diff --git a/include/espressif/user_interface.h b/include/espressif/user_interface.h new file mode 100644 index 0000000..223efba --- /dev/null +++ b/include/espressif/user_interface.h @@ -0,0 +1,27 @@ +#ifndef __USER_INTERFACE_H__ +#define __USER_INTERFACE_H__ + +#include +#include +#include +#include "espressif/esp_wifi.h" + +enum sdk_dhcp_status { + DHCP_STOPPED, + DHCP_STARTED +}; + +uint8_t sdk_system_get_boot_version(void); +uint32_t sdk_system_get_userbin_addr(void); +uint8_t sdk_system_get_boot_mode(void); +bool sdk_system_restart_enhance(uint8_t bin_type, uint32_t bin_addr); +bool sdk_system_upgrade_userbin_set(uint8_t userbin); +uint8_t sdk_system_upgrade_userbin_check(void); +bool sdk_system_upgrade_flag_set(uint8_t flag); +uint8_t sdk_system_upgrade_flag_check(void); +bool sdk_system_upgrade_reboot(void); +bool sdk_wifi_station_dhcpc_start(void); +bool sdk_wifi_station_dhcpc_stop(void); +enum sdk_dhcp_status sdk_wifi_station_dhcpc_status(void); + +#endif diff --git a/open_esplibs/include/esplibs/libmain.h b/open_esplibs/include/esplibs/libmain.h new file mode 100644 index 0000000..dc36117 --- /dev/null +++ b/open_esplibs/include/esplibs/libmain.h @@ -0,0 +1,19 @@ +#ifndef _ESPLIBS_LIBMAIN_H +#define _ESPLIBS_LIBMAIN_H + +#include "sdk_internal.h" + +// misc.c +int sdk_os_get_cpu_frequency(void); +void sdk_os_update_cpu_frequency(int freq); + +// user_interface.c +void sdk_system_restart_in_nmi(void); +int sdk_system_get_test_result(void); +void sdk_wifi_param_save_protect(struct sdk_g_ic_saved_st *data); +bool sdk_system_overclock(void); +bool sdk_system_restoreclock(void); +uint32_t sdk_system_relative_time(uint32_t reltime); + +#endif /* _ESPLIBS_LIBMAIN_H */ + diff --git a/open_esplibs/include/esplibs/libnet80211.h b/open_esplibs/include/esplibs/libnet80211.h new file mode 100644 index 0000000..12f5980 --- /dev/null +++ b/open_esplibs/include/esplibs/libnet80211.h @@ -0,0 +1,14 @@ +#ifndef _ESPLIBS_LIBNET80211_H +#define _ESPLIBS_LIBNET80211_H + +// Defined in wl_cnx.o +extern ETSTimer sdk_sta_con_timer; + +// Defined in ieee80211_sta.o: .irom0.text+0xcc4 +bool sdk_wifi_station_stop(void); + +// Defined in ieee80211_hostap.o: .irom0.text+0x1184 +bool sdk_wifi_softap_stop(void); + +#endif /* _ESPLIBS_LIBNET80211_H */ + diff --git a/open_esplibs/include/esplibs/libphy.h b/open_esplibs/include/esplibs/libphy.h new file mode 100644 index 0000000..92ec355 --- /dev/null +++ b/open_esplibs/include/esplibs/libphy.h @@ -0,0 +1,8 @@ +#ifndef _ESPLIBS_LIBPHY_H +#define _ESPLIBS_LIBPHY_H + +// Defined in phy_chip_v6_ana.o: .irom0.text+0x12d8 +uint32_t sdk_test_tout(bool); + +#endif /* _ESPLIBS_LIBPHY_H */ + diff --git a/open_esplibs/include/esplibs/libpp.h b/open_esplibs/include/esplibs/libpp.h new file mode 100644 index 0000000..c2ed458 --- /dev/null +++ b/open_esplibs/include/esplibs/libpp.h @@ -0,0 +1,32 @@ +#ifndef _ESPLIBS_LIBPP_H +#define _ESPLIBS_LIBPP_H + +// Located in wdev.o +extern uint32_t sdk_WdevTimOffSet; + +// Defined in pp.o: .irom0.text+0xa08 +void sdk_ppRecycleRxPkt(void *); + +// Defined in pm.o: .irom0.text+0x74 +uint32_t sdk_pm_rtc_clock_cali_proc(void); + +// Defined in pm.o: .irom0.text+0xb8 +void sdk_pm_set_sleep_time(uint32_t); + +// Defined in pm.o: .irom0.text+0x1758 +uint8_t sdk_pm_is_waked(void); + +// Defined in pm.o: .irom0.text+0x1774 +bool sdk_pm_is_open(void); + +// Defined in pm.o: .irom0.text+0x19ac +bool sdk_pm_post(int); + +// Defined in wdev.o: .irom0.text+0x450 +void sdk_wDev_MacTim1SetFunc(void (*func)(void)); + +// Defined in wdev.o: .text+0x4a8 +void sdk_wDev_MacTim1Arm(uint32_t); + +#endif /* _ESPLIBS_LIBPP_H */ + diff --git a/open_esplibs/include/open_esplibs.h b/open_esplibs/include/open_esplibs.h index 5443fef..8db3127 100644 --- a/open_esplibs/include/open_esplibs.h +++ b/open_esplibs/include/open_esplibs.h @@ -32,5 +32,8 @@ #ifndef OPEN_LIBMAIN_XTENSA_CONTEXT #define OPEN_LIBMAIN_XTENSA_CONTEXT (OPEN_LIBMAIN) #endif +#ifndef OPEN_LIBMAIN_USER_INTERFACE +#define OPEN_LIBMAIN_USER_INTERFACE (OPEN_LIBMAIN) +#endif #endif /* _OPEN_ESPLIBS_H */ diff --git a/open_esplibs/libmain/misc.c b/open_esplibs/libmain/misc.c index 8029a38..3c1cd02 100644 --- a/open_esplibs/libmain/misc.c +++ b/open_esplibs/libmain/misc.c @@ -58,7 +58,7 @@ uint8_t sdk_rtc_get_reset_reason(void) { } } } - RTC.RESET_REASON0 &= ~RTC_RESET_REASON0_SOMETHING; + RTC.RESET_REASON0 &= ~RTC_RESET_REASON0_BIT21; return reason; } diff --git a/open_esplibs/libmain/user_interface.c b/open_esplibs/libmain/user_interface.c new file mode 100644 index 0000000..1533594 --- /dev/null +++ b/open_esplibs/libmain/user_interface.c @@ -0,0 +1,548 @@ +#include "open_esplibs.h" +#if OPEN_LIBMAIN_USER_INTERFACE +// The contents of this file are only built if OPEN_LIBMAIN_USER_INTERFACE is set to true + +#include "FreeRTOS.h" +#include "task.h" +#include "string.h" + +#include "lwip/dhcp.h" + +#include "esp/types.h" +#include "esp/rom.h" +#include "esp/dport_regs.h" +#include "esp/rtcmem_regs.h" +#include "esp/iomux_regs.h" +#include "esp/sar_regs.h" +#include "esp/wdev_regs.h" + +#include "etstimer.h" +#include "espressif/sdk_private.h" +#include "espressif/esp_system.h" +#include "espressif/esp_wifi.h" +#include "espressif/esp_sta.h" +#include "espressif/esp_softap.h" +#include "espressif/esp_misc.h" +#include "espressif/osapi.h" +#include "espressif/user_interface.h" + +#include "sdk_internal.h" +#include "esplibs/libmain.h" +#include "esplibs/libpp.h" +#include "esplibs/libphy.h" +#include "esplibs/libnet80211.h" + +// Structure for the data contained in the last sector of Flash which contains +// meta-info about the saved wifi param sectors. +struct param_dir_st { + uint8_t current_sector; // 0x00 + uint32_t cksum_magic; // 0x04 + uint32_t save_count; // 0x08 + uint32_t cksum_len[2]; // 0x0c + uint32_t cksum_value[2]; // 0x14 +}; +_Static_assert(sizeof(struct param_dir_st) == 28, "param_dir_st is the wrong size"); + +enum sdk_dhcp_status sdk_dhcpc_flag = DHCP_STARTED; +bool sdk_cpu_overclock; +struct sdk_rst_info sdk_rst_if; +sdk_wifi_promiscuous_cb_t sdk_promiscuous_cb; + +static uint8_t _system_upgrade_flag; // Ldata009 + +// Prototypes for static functions +static bool _check_boot_version(void); +static void _deep_sleep_phase2(void *timer_arg); +static struct netif *_get_netif(uint32_t mode); + +// Linker-created values used by sdk_system_print_meminfo +extern uint32_t _data_start, _data_end; +extern uint32_t _rodata_start, _rodata_end; +extern uint32_t _bss_start, _bss_end; +extern uint32_t _heap_start; + +#define _rom_reset_vector ((void (*)(void))0x40000080) + +void IRAM sdk_system_restart_in_nmi(void) { + uint32_t buf[8]; + + sdk_system_rtc_mem_read(0, buf, 32); + if (buf[0] != 2) { + memset(buf, 0, 32); + buf[0] = 3; + sdk_system_rtc_mem_write(0, buf, 32); + } + if (!sdk_NMIIrqIsOn) { + portENTER_CRITICAL(); + do { + DPORT.DPORT0 = SET_FIELD(DPORT.DPORT0, DPORT_DPORT0_FIELD0, 0); + } while (DPORT.DPORT0 & 1); + } + ESPSAR.UNKNOWN_48 |= 3; + DPORT.CLOCKGATE_WATCHDOG |= DPORT_CLOCKGATE_WATCHDOG_UNKNOWN_8; + ESPSAR.UNKNOWN_48 &= ~3; + DPORT.CLOCKGATE_WATCHDOG &= ~DPORT_CLOCKGATE_WATCHDOG_UNKNOWN_8; + Cache_Read_Disable(); + DPORT.SPI_CACHE_RAM &= ~(DPORT_SPI_CACHE_RAM_BANK0 | DPORT_SPI_CACHE_RAM_BANK1); + // This calls directly to 0x40000080, the "reset" exception vector address. + _rom_reset_vector(); +} + +bool IRAM sdk_system_rtc_mem_write(uint32_t des_addr, void *src_addr, uint16_t save_size) { + uint32_t volatile *src_buf = (uint32_t *)src_addr; + + if (des_addr > 191) { + return false; + } + if ((intptr_t)src_addr & 3) { + return false; + } + if ((768 - (des_addr * 4)) < save_size) { + return false; + } + if ((save_size & 3) != 0) { + save_size = (save_size & ~3) + 4; + } + for (uint8_t i = 0; i < (save_size >> 2); i++) { + RTCMEM_SYSTEM[i] = src_buf[i]; + } + return true; +} + +bool IRAM sdk_system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint16_t save_size) { + uint32_t volatile *src_buf = (uint32_t *)src_addr; + + if (src_addr > 191) { + return false; + } + if ((intptr_t)des_addr & 3) { + return false; + } + if ((768 - (src_addr * 4)) < save_size) { + return false; + } + if ((save_size & 3) != 0) { + save_size = (save_size & ~3) + 4; + } + for (uint8_t i = 0; i < (save_size >> 2); i++) { + src_buf[i] = RTCMEM_SYSTEM[i]; + } + return true; +} + +void sdk_system_pp_recycle_rx_pkt(void *eb) { + sdk_ppRecycleRxPkt(eb); +} + +uint16_t sdk_system_adc_read(void) { + return sdk_test_tout(false); +} + +void sdk_system_restart(void) { + if (sdk_wifi_get_opmode() != 2) { + sdk_wifi_station_stop(); + } + if (sdk_wifi_get_opmode() != 1) { + sdk_wifi_softap_stop(); + } + vTaskDelay(6); + IOMUX_GPIO12 |= IOMUX_PIN_PULLUP; + sdk_wDev_MacTim1SetFunc(sdk_system_restart_in_nmi); + sdk_wDev_MacTim1Arm(3); +} + +void sdk_system_restore(void) { + struct sdk_g_ic_saved_st *buf; + + buf = malloc(sizeof(struct sdk_g_ic_saved_st)); + memset(buf, 0xff, sizeof(struct sdk_g_ic_saved_st)); + memcpy(buf, &sdk_g_ic.s, 8); + sdk_wifi_param_save_protect(buf); + free(buf); +} + +uint8_t sdk_system_get_boot_version(void) { + return sdk_g_ic.s.boot_info & 0x1f; +} + +static bool _check_boot_version(void) { + uint8_t ver = sdk_system_get_boot_version(); + if (ver < 3 || ver == 31) { + printf("failed: need boot >= 1.3\n"); + return false; + } + return true; +} + +int sdk_system_get_test_result(void) { + if (_check_boot_version()) { + return (sdk_g_ic.s.boot_info >> 5) & 1; + } else { + return -1; + } +} + +uint32_t sdk_system_get_userbin_addr(void) { + uint8_t buf[8]; + uint16_t unknown_var = 0; //FIXME: read but never written? + uint32_t addr; + uint32_t flash_size_code; + + if (!(sdk_g_ic.s.boot_info >> 7)) { + if (sdk_g_ic.s._unknown1d8 & 0x4) { + addr = sdk_g_ic.s.user1_addr[0] | (sdk_g_ic.s.user1_addr[1] << 8) | +(sdk_g_ic.s.user1_addr[2] << 16); + } else { + addr = sdk_g_ic.s.user0_addr[0] | (sdk_g_ic.s.user0_addr[1] << 8) | (sdk_g_ic.s.user0_addr[2] << 16); + } + } else { + if (!sdk_system_upgrade_userbin_check()) { + addr = 0x00001000; + } else { + sdk_spi_flash_read(0, (uint32_t *)buf, 8); + flash_size_code = buf[3] >> 4; + if (flash_size_code >= 2 && flash_size_code < 5) { + flash_size_code = 0x81; + } else if (flash_size_code == 1) { + flash_size_code = 0x41; + } else { + // FIXME: In the original code, this loads from a local stack + // variable, which is never actually assigned to anywhere. + // It's unclear what this value is actually supposed to be. + flash_size_code = unknown_var; + } + addr = flash_size_code << 12; + } + } + return addr; +} + +uint8_t sdk_system_get_boot_mode(void) { + int boot_version = sdk_g_ic.s.boot_info & 0x1f; + if (boot_version < 3 || boot_version == 0x1f) { + return 1; + } + return sdk_g_ic.s.boot_info >> 7; +} + +bool sdk_system_restart_enhance(uint8_t bin_type, uint32_t bin_addr) { + uint32_t current_addr; + + if (!_check_boot_version()) { + return false; + } + if (bin_type == 0) { + current_addr = sdk_system_get_userbin_addr(); + printf("restart to use user bin @ %x\n", bin_addr); + sdk_g_ic.s.user1_addr[0] = bin_addr; + sdk_g_ic.s.user1_addr[1] = bin_addr >> 8; + sdk_g_ic.s.user1_addr[2] = bin_addr >> 16; + sdk_g_ic.s.user0_addr[0] = current_addr; + sdk_g_ic.s.user0_addr[1] = current_addr >> 8; + sdk_g_ic.s.user0_addr[2] = current_addr >> 16; + sdk_g_ic.s._unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xfb) | 0x04; + sdk_g_ic.s.boot_info &= 0x7f; + sdk_wifi_param_save_protect(&sdk_g_ic.s); + sdk_system_restart(); + return true; + } else { + if (bin_type != 1) { + printf("don't supported type.\n"); + return false; + } + if (!sdk_system_get_test_result()) { + printf("test already passed.\n"); + return false; + } + + printf("reboot to use test bin @ %x\n", bin_addr); + sdk_g_ic.s.user0_addr[0] = bin_addr; + sdk_g_ic.s.user0_addr[1] = bin_addr >> 8; + sdk_g_ic.s.user0_addr[2] = bin_addr >> 16; + sdk_g_ic.s.boot_info &= 0xbf; + sdk_wifi_param_save_protect(&sdk_g_ic.s); + sdk_system_restart(); + + return true; + } +} + +bool sdk_system_upgrade_userbin_set(uint8_t userbin) { + uint8_t userbin_val, userbin_mask; + uint8_t boot_ver = sdk_system_get_boot_version(); + + if (userbin >= 2) { + return false; + } else { + if (boot_ver == 2 || boot_ver == 0x1f) { + userbin_val = userbin & 0x0f; + userbin_mask = 0xf0; + } else { + userbin_val = userbin & 0x03; + userbin_mask = 0xfc; + } + sdk_g_ic.s._unknown1d8 = (sdk_g_ic.s._unknown1d8 & userbin_mask) | userbin_val; + return true; + } +} + +uint8_t sdk_system_upgrade_userbin_check(void) { + uint8_t boot_ver = sdk_system_get_boot_version(); + if (boot_ver != 0x1f && boot_ver != 2) { + if ((sdk_g_ic.s._unknown1d8 & 0x03) == 1) { + if (sdk_g_ic.s._unknown1d8 & 0x4) { + return 1; + } else { + return 0; + } + } else { + if (sdk_g_ic.s._unknown1d8 & 0x4) { + return 0; + } else { + return 1; + } + } + } else { + if ((sdk_g_ic.s._unknown1d8 & 0x0f) == 1) { + return 1; + } else { + return 0; + } + } +} + +bool sdk_system_upgrade_flag_set(uint8_t flag) { + if (flag < 3) { + _system_upgrade_flag = flag; + return true; + } + return false; +} + +uint8_t sdk_system_upgrade_flag_check(void) { + return _system_upgrade_flag; +} + +bool sdk_system_upgrade_reboot(void) { + uint8_t boot_ver = sdk_system_get_boot_version(); + uint8_t new__unknown1d8; + + if (_system_upgrade_flag != 2) { + return false; + } + printf("reboot to use"); + if (boot_ver != 2 && boot_ver != 0x1f) { + sdk_g_ic.s.boot_info = (sdk_g_ic.s.boot_info & 0x7f) | 0x80; + sdk_g_ic.s._unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xfb) | 0x04; + if ((sdk_g_ic.s._unknown1d8 & 0x03) == 1) { + printf("1\n"); + new__unknown1d8 = sdk_g_ic.s._unknown1d8 & 0xfc; + } else { + printf("2\n"); + new__unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xfc) | 0x01; + } + } else { + if ((sdk_g_ic.s._unknown1d8 & 0x0f) == 1) { + printf("1\n"); + new__unknown1d8 = sdk_g_ic.s._unknown1d8 & 0xf0; + } else { + printf("2\n"); + new__unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xf0) | 0x01; + } + } + sdk_g_ic.s._unknown1d8 = new__unknown1d8; + sdk_wifi_param_save_protect(&sdk_g_ic.s); + sdk_system_restart(); + return true; +} + +static void _deep_sleep_phase2(void *timer_arg) { + uint32_t time_in_us = (uint32_t)timer_arg; + + printf("deep sleep %ds\n\n", time_in_us / 1000000); + while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(0).STATUS)) {} + while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(1).STATUS)) {} + RTC.CTRL0 = 0; + RTC.CTRL0 &= 0xffffbfff; + RTC.CTRL0 |= 0x00000030; + RTC._unknown44 = 0x00000004; + RTC._unknownc = 0x00010010; + RTC._unknown48 = (RTC._unknown48 & 0xffff01ff) | 0x0000fc00; + RTC._unknown48 = (RTC._unknown48 & 0xfffffe00) | 0x00000080; + RTC.COUNTER_ALARM = RTC.COUNTER + 136; + RTC.RESET_REASON2 = 0x00000008; + RTC.RESET_REASON0 = 0x00100000; + sdk_os_delay_us(200); + RTC.GPIO_CFG[2] = 0x00000011; + RTC.GPIO_CFG[3] = 0x00000003; + RTC._unknownc = 0x000640c8; + RTC.CTRL0 &= 0xffffffcf; + sdk_pm_rtc_clock_cali_proc(); + sdk_pm_set_sleep_time(time_in_us); + RTC.GPIO_CFG[2] = 0x00000011; + RTC.GPIO_CFG[3] = 0x00000003; + DPORT.INT_ENABLE &= ~(DPORT_INT_ENABLE_WDT); + _xt_isr_mask(1 << ETS_WDT_INUM); + RTC._unknown40 = 0xffffffff; + RTC._unknown44 = 0x00000020; + RTC._unknown10 = 0x00000000; + if (time_in_us == 0) { + RTC.RESET_REASON2 = 0x00000000; + } else { + RTC.RESET_REASON2 = 0x00000008; + } + RTC.RESET_REASON0 = 0x00100000; +} + +void sdk_system_deep_sleep(uint32_t time_in_us) { + if (sdk_wifi_get_opmode() != 2) { + sdk_wifi_station_stop(); + } + if (sdk_wifi_get_opmode() != 1) { + sdk_wifi_softap_stop(); + } + sdk_os_timer_disarm(&sdk_sta_con_timer); + sdk_os_timer_setfn(&sdk_sta_con_timer, _deep_sleep_phase2, (void *)time_in_us); + sdk_os_timer_arm(&sdk_sta_con_timer, 100, 0); +} + +bool sdk_system_update_cpu_freq(uint8_t freq) { + if (freq == 80) { + DPORT.CPU_CLOCK &= ~(DPORT_CPU_CLOCK_X2); + sdk_os_update_cpu_frequency(80); + } else if (freq == 160) { + DPORT.CPU_CLOCK |= DPORT_CPU_CLOCK_X2; + sdk_os_update_cpu_frequency(160); + } else { + return false; + } + return true; +} + +uint8_t sdk_system_get_cpu_freq(void) { + return sdk_os_get_cpu_frequency(); +} + +bool sdk_system_overclock(void) { + if (sdk_system_get_cpu_freq() == 80) { + sdk_cpu_overclock = true; + sdk_system_update_cpu_freq(160); + return true; + } + return false; +} + +bool sdk_system_restoreclock(void) { + if (sdk_system_get_cpu_freq() == 160 && sdk_cpu_overclock) { + sdk_cpu_overclock = false; + sdk_system_update_cpu_freq(80); + return true; + } + return false; +} + +uint32_t sdk_system_get_time(void) { + return WDEV.SYS_TIME + sdk_WdevTimOffSet; +} + +uint32_t sdk_system_relative_time(uint32_t reltime) { + return WDEV.SYS_TIME - reltime; +} + +void sdk_system_station_got_ip_set(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw) { + uint8_t *ip_bytes = (uint8_t *)&ip->addr; + uint8_t *mask_bytes = (uint8_t *)&mask->addr; + uint8_t *gw_bytes = (uint8_t *)&gw->addr; + uint32_t gpio_mask; + + sdk_g_ic.v.station_netif_info->connect_status = STATION_GOT_IP; + printf("ip:%d.%d.%d.%d,mask:%d.%d.%d.%d,gw:%d.%d.%d.%d", ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3], mask_bytes[0], mask_bytes[1], mask_bytes[2], mask_bytes[3], gw_bytes[0], gw_bytes[1], gw_bytes[2], gw_bytes[3]); + printf("\n"); + if ((sdk_g_ic.s.wifi_led_enable == 1) && (sdk_g_ic.s.wifi_mode == 1)) { + sdk_os_timer_disarm(&sdk_sta_con_timer); + gpio_mask = 1 << sdk_g_ic.s.wifi_led_gpio; + sdk_gpio_output_set(0, gpio_mask, gpio_mask, 0); + } +} + +void sdk_system_print_meminfo(void) { + printf("%s: 0x%x ~ 0x%x, len: %d\n", "data ", _data_start, _data_end, _data_end - _data_start); + printf("%s: 0x%x ~ 0x%x, len: %d\n", "rodata", _rodata_start, _rodata_end, _rodata_end - _rodata_start); + printf("%s: 0x%x ~ 0x%x, len: %d\n", "bss ", _bss_start, _bss_end, _bss_end - _bss_start); + printf("%s: 0x%x ~ 0x%x, len: %d\n", "heap ", _heap_start, 0x3fffc000, 0x3fffc000 - _heap_start); +} + +uint32_t sdk_system_get_free_heap_size(void) { + return xPortGetFreeHeapSize(); +} + +uint32_t sdk_system_get_chip_id(void) { + uint32_t mac0 = DPORT.OTP_MAC0 & 0xff000000; + uint32_t mac1 = DPORT.OTP_MAC1 & 0x00ffffff; + return (mac1 << 8) | (mac0 >> 24); +} + +uint32_t sdk_system_rtc_clock_cali_proc(void) { + return sdk_pm_rtc_clock_cali_proc(); +} + +uint32_t sdk_system_get_rtc_time(void) { + return RTC.COUNTER; +} + +struct sdk_rst_info *sdk_system_get_rst_info(void) { + return &sdk_rst_if; +} + +static struct netif *_get_netif(uint32_t mode) { + struct sdk_g_ic_netif_info *info; + + if (mode >= 2) { + return NULL; + } + if (mode == 0) { + info = sdk_g_ic.v.station_netif_info; + } else { + info = sdk_g_ic.v.softap_netif_info; + } + if (info) { + return info->netif; + } + return NULL; +} + +bool sdk_wifi_station_dhcpc_start(void) { + struct netif *netif = _get_netif(0); + if (sdk_wifi_get_opmode() == 2) { + return false; + } + if (netif && sdk_dhcpc_flag == DHCP_STOPPED) { + sdk_info.ipaddr.addr = 0; + sdk_info.netmask.addr = 0; + sdk_info.gw.addr = 0; + netif_set_addr(netif, &sdk_info.ipaddr, &sdk_info.netmask, &sdk_info.gw); + if (dhcp_start(netif)) { + return false; + } + } + sdk_dhcpc_flag = DHCP_STARTED; + return true; +} + +bool sdk_wifi_station_dhcpc_stop(void) { + struct netif *netif = _get_netif(0); + if (sdk_wifi_get_opmode() == 2) { + return false; + } + if (netif && sdk_dhcpc_flag == DHCP_STARTED) { + dhcp_stop(netif); + } + sdk_dhcpc_flag = DHCP_STOPPED; + return true; +} + +enum sdk_dhcp_status sdk_wifi_station_dhcpc_status(void) { + return sdk_dhcpc_flag; +} + +#endif /* OPEN_LIBMAIN_USER_INTERFACE */ From e3827b2f1ca5a0c1d0512b18da7e9520fdc3c7a1 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 30 Jun 2016 09:51:02 +1000 Subject: [PATCH 12/26] Fix rboot-api sdk_spi_flash_read pointer types --- extras/rboot-ota/rboot-api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/rboot-ota/rboot-api.c b/extras/rboot-ota/rboot-api.c index b9a5e57..85b459d 100644 --- a/extras/rboot-ota/rboot-api.c +++ b/extras/rboot-ota/rboot-api.c @@ -249,7 +249,7 @@ bool rboot_verify_image(uint32_t initial_offset, uint32_t *image_length, const c /* sanity limit on how far we can read */ uint32_t end_limit = offset + 0x100000; image_header_t image_header __attribute__((aligned(4))); - if(sdk_spi_flash_read(offset, &image_header, sizeof(image_header_t))) { + if(sdk_spi_flash_read(offset, (uint32_t *)&image_header, sizeof(image_header_t))) { error = "Flash fail"; goto fail; } @@ -271,7 +271,7 @@ bool rboot_verify_image(uint32_t initial_offset, uint32_t *image_length, const c { /* read section header */ section_header_t header __attribute__((aligned(4))); - if(sdk_spi_flash_read(offset, &header, sizeof(section_header_t))) { + if(sdk_spi_flash_read(offset, (uint32_t *)&header, sizeof(section_header_t))) { error = "Flash fail"; goto fail; } @@ -359,7 +359,7 @@ bool rboot_digest_image(uint32_t offset, uint32_t image_length, rboot_digest_upd { uint8_t buf[32] __attribute__((aligned(4))); for(int i = 0; i < image_length; i += sizeof(buf)) { - if(sdk_spi_flash_read(offset+i, buf, sizeof(buf))) + if(sdk_spi_flash_read(offset+i, (uint32_t *)buf, sizeof(buf))) return false; uint32_t digest_len = sizeof(buf); if(i + digest_len > image_length) From 701a4c42846c8ac8ffd0b10c4baf1eb3dabfb4a9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 30 Jun 2016 09:30:21 +1000 Subject: [PATCH 13/26] sdk_system_rtc_mem_read: Fix destination buffer pointer --- open_esplibs/libmain/user_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/open_esplibs/libmain/user_interface.c b/open_esplibs/libmain/user_interface.c index 1533594..9d6865b 100644 --- a/open_esplibs/libmain/user_interface.c +++ b/open_esplibs/libmain/user_interface.c @@ -110,7 +110,7 @@ bool IRAM sdk_system_rtc_mem_write(uint32_t des_addr, void *src_addr, uint16_t s } bool IRAM sdk_system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint16_t save_size) { - uint32_t volatile *src_buf = (uint32_t *)src_addr; + uint32_t *dest_buf = (uint32_t *)des_addr; if (src_addr > 191) { return false; @@ -125,7 +125,7 @@ bool IRAM sdk_system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint16_t sa save_size = (save_size & ~3) + 4; } for (uint8_t i = 0; i < (save_size >> 2); i++) { - src_buf[i] = RTCMEM_SYSTEM[i]; + dest_buf[i] = RTCMEM_SYSTEM[i]; } return true; } From 678b59babfdc30b473d43c0b054ad06938e23601 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 30 Jun 2016 09:22:17 +1000 Subject: [PATCH 14/26] Honour values of configCPU_CLOCK_HZ & configTICK_RATE_HZ for tick rate Fixes #147 * Can vary tick rate from 100Hz via configTICK_RATE_HZ. Note that the SDK binary libraries are hard-coded to assume the tick rate is 100Hz, so changing the tick rate may have unexpected consequences for lower layer WiFi behaviour (such as certain kinds of timeouts happening faster/slower.) * Setting configCPU_CLOCK_HZ to 160MHz means ESP will set 160MHz during initialisation. Only 80MHz and 160MHz are supported. * Timing of tasks is no longer affected by current CPU freq (whether set via configCPU_CLOCK_HZ or via sdk_system_update_cpu_freq().) Previously doubling the CPU frequency would double the tick rate. --- FreeRTOS/Source/include/FreeRTOSConfig.h | 7 +++++++ core/app_main.c | 4 ++++ examples/blink/blink.c | 1 + open_esplibs/include/esplibs/libmain.h | 4 ++++ open_esplibs/libmain/os_cpu_a.c | 5 +++-- 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/FreeRTOS/Source/include/FreeRTOSConfig.h b/FreeRTOS/Source/include/FreeRTOSConfig.h index 6604df3..d886828 100644 --- a/FreeRTOS/Source/include/FreeRTOSConfig.h +++ b/FreeRTOS/Source/include/FreeRTOSConfig.h @@ -34,6 +34,13 @@ #define configUSE_TICK_HOOK 0 #endif #ifndef configCPU_CLOCK_HZ +/* This is the _default_ clock speed for the CPU. Can be either 80MHz + * or 160MHz, and the system will set the clock speed to match at startup. + +Note that it's possible to change the clock speed at runtime, so you +can/should use sdk_system_get_cpu_frequency() in order to determine the +current CPU frequency, in preference to this macro. +*/ #define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 ) #endif #ifndef configTICK_RATE_HZ diff --git a/core/app_main.c b/core/app_main.c index ac74426..43fed17 100644 --- a/core/app_main.c +++ b/core/app_main.c @@ -382,6 +382,10 @@ static __attribute__((noinline)) void user_start_phase2(void) { srand(hwrand()); /* seed libc rng */ + // Set intial CPU clock speed to 160MHz if necessary + _Static_assert(configCPU_CLOCK_HZ == 80000000 || configCPU_CLOCK_HZ == 160000000, "FreeRTOSConfig must define initial clock speed as either 80MHz or 160MHz"); + sdk_system_update_cpu_freq(configCPU_CLOCK_HZ / 1000000); + // Call gcc constructor functions void (**ctor)(void); for ( ctor = &__init_array_start; ctor != &__init_array_end; ++ctor) { diff --git a/examples/blink/blink.c b/examples/blink/blink.c index 9d2ae3c..1539b67 100644 --- a/examples/blink/blink.c +++ b/examples/blink/blink.c @@ -2,6 +2,7 @@ * * This sample code is in the public domain. */ +#include #include "espressif/esp_common.h" #include "esp/uart.h" #include "FreeRTOS.h" diff --git a/open_esplibs/include/esplibs/libmain.h b/open_esplibs/include/esplibs/libmain.h index dc36117..98ccb54 100644 --- a/open_esplibs/include/esplibs/libmain.h +++ b/open_esplibs/include/esplibs/libmain.h @@ -1,3 +1,4 @@ +#include "sdk_internal.h" #ifndef _ESPLIBS_LIBMAIN_H #define _ESPLIBS_LIBMAIN_H @@ -5,6 +6,9 @@ // misc.c int sdk_os_get_cpu_frequency(void); + +/* Don't call this function from user code, it doesn't change the CPU + * speed. Call sdk_system_update_cpu_freq() instead. */ void sdk_os_update_cpu_frequency(int freq); // user_interface.c diff --git a/open_esplibs/libmain/os_cpu_a.c b/open_esplibs/libmain/os_cpu_a.c index 7908b6f..dac5247 100644 --- a/open_esplibs/libmain/os_cpu_a.c +++ b/open_esplibs/libmain/os_cpu_a.c @@ -7,6 +7,7 @@ #include "task.h" #include "xtensa_ops.h" #include "common_macros.h" +#include "esplibs/libmain.h" // xPortSysTickHandle is defined in FreeRTOS/Source/portable/esp8266/port.c but // does not exist in any header files. @@ -66,7 +67,7 @@ void IRAM sdk__xt_int_exit(void) { void IRAM sdk__xt_timer_int(void) { uint32_t trigger_ccount; uint32_t current_ccount; - uint32_t ccount_interval = portTICK_RATE_MS * 80000; //FIXME + uint32_t ccount_interval = portTICK_RATE_MS * sdk_os_get_cpu_frequency() * 1000; do { RSR(trigger_ccount, ccompare0); @@ -87,7 +88,7 @@ void IRAM sdk__xt_timer_int1(void) { void IRAM sdk__xt_tick_timer_init(void) { uint32_t ints_enabled; uint32_t current_ccount; - uint32_t ccount_interval = portTICK_RATE_MS * 80000; //FIXME + uint32_t ccount_interval = portTICK_RATE_MS * sdk_os_get_cpu_frequency() * 1000; RSR(current_ccount, ccount); WSR(current_ccount + ccount_interval, ccompare0); From 6c9d478336e9976d6844cb32241183546465ed9b Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 30 Jun 2016 16:08:59 +1000 Subject: [PATCH 15/26] open_esplibs: Add README and Copyright headers --- open_esplibs/README.md | 15 +++++++++++++++ open_esplibs/include/esplibs/libmain.h | 8 ++++++++ open_esplibs/include/esplibs/libnet80211.h | 8 ++++++++ open_esplibs/include/esplibs/libphy.h | 8 ++++++++ open_esplibs/include/esplibs/libpp.h | 8 ++++++++ open_esplibs/libmain/misc.c | 5 +++++ open_esplibs/libmain/os_cpu_a.c | 5 +++++ open_esplibs/libmain/spi_flash.c | 5 +++++ open_esplibs/libmain/timers.c | 5 +++++ open_esplibs/libmain/uart.c | 5 +++++ open_esplibs/libmain/user_interface.c | 5 +++++ open_esplibs/libmain/xtensa_context.S | 5 +++++ 12 files changed, 82 insertions(+) create mode 100644 open_esplibs/README.md diff --git a/open_esplibs/README.md b/open_esplibs/README.md new file mode 100644 index 0000000..ba11452 --- /dev/null +++ b/open_esplibs/README.md @@ -0,0 +1,15 @@ +# Open Espressif Libs + +These are functional recreations of the MIT licensed binary Espressif SDK libraries found in `lib`. They keep the same functionality as the SDK libraries (possibly with bugfixes or other minor tweaks), but are compiled from source. + +Most of the reverse engineering work so far has been by Alex Stewart (@foogod). + +See http://esp8266-re.foogod.com/wiki/ for more technical details of SDK library internals. + +# Disabling + +The open ESP libs are compiled in by default, and they automatically replace any binary SDK symbols (functions, etc.) with the same names. + +To compile using the binary SDK libraries only, override the COMPONENTS list in parameters.mk to remove the open_esplibs component, or add -DOPEN_ESPLIBS=0 to CPPFLAGS. + +To selectively replace some functionality with binary SDK functionality for debugging, edit the header file open_esplibs/include/open_esplibs.h diff --git a/open_esplibs/include/esplibs/libmain.h b/open_esplibs/include/esplibs/libmain.h index 98ccb54..9bbfe6f 100644 --- a/open_esplibs/include/esplibs/libmain.h +++ b/open_esplibs/include/esplibs/libmain.h @@ -1,3 +1,11 @@ +/* Internal function declarations for Espressif SDK libmain functions. + + These are internal-facing declarations, it is not recommended to include these headers in your program. + (look at the headers in include/espressif/ instead and use these whenever possible.) + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE. +*/ #include "sdk_internal.h" #ifndef _ESPLIBS_LIBMAIN_H #define _ESPLIBS_LIBMAIN_H diff --git a/open_esplibs/include/esplibs/libnet80211.h b/open_esplibs/include/esplibs/libnet80211.h index 12f5980..1c0ac9a 100644 --- a/open_esplibs/include/esplibs/libnet80211.h +++ b/open_esplibs/include/esplibs/libnet80211.h @@ -1,3 +1,11 @@ +/* Internal function declarations for Espressif SDK libnet80211 functions. + + These are internal-facing declarations, it is not recommended to include these headers in your program. + (look at the headers in include/espressif/ instead and use these whenever possible.) + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE. +*/ #ifndef _ESPLIBS_LIBNET80211_H #define _ESPLIBS_LIBNET80211_H diff --git a/open_esplibs/include/esplibs/libphy.h b/open_esplibs/include/esplibs/libphy.h index 92ec355..2c7639c 100644 --- a/open_esplibs/include/esplibs/libphy.h +++ b/open_esplibs/include/esplibs/libphy.h @@ -1,3 +1,11 @@ +/* Internal function declarations for Espressif SDK libphy functions. + + These are internal-facing declarations, it is not recommended to include these headers in your program. + (look at the headers in include/espressif/ instead and use these whenever possible.) + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE. +*/ #ifndef _ESPLIBS_LIBPHY_H #define _ESPLIBS_LIBPHY_H diff --git a/open_esplibs/include/esplibs/libpp.h b/open_esplibs/include/esplibs/libpp.h index c2ed458..238ad02 100644 --- a/open_esplibs/include/esplibs/libpp.h +++ b/open_esplibs/include/esplibs/libpp.h @@ -1,3 +1,11 @@ +/* Internal function declarations for Espressif SDK libpp functions. + + These are internal-facing declarations, it is not recommended to include these headers in your program. + (look at the headers in include/espressif/ instead and use these whenever possible.) + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE. +*/ #ifndef _ESPLIBS_LIBPP_H #define _ESPLIBS_LIBPP_H diff --git a/open_esplibs/libmain/misc.c b/open_esplibs/libmain/misc.c index 3c1cd02..f11d4fd 100644 --- a/open_esplibs/libmain/misc.c +++ b/open_esplibs/libmain/misc.c @@ -1,3 +1,8 @@ +/* Recreated Espressif libmain misc.o contents. + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE +*/ #include "open_esplibs.h" #if OPEN_LIBMAIN_MISC // The contents of this file are only built if OPEN_LIBMAIN_MISC is set to true diff --git a/open_esplibs/libmain/os_cpu_a.c b/open_esplibs/libmain/os_cpu_a.c index dac5247..9ace3a8 100644 --- a/open_esplibs/libmain/os_cpu_a.c +++ b/open_esplibs/libmain/os_cpu_a.c @@ -1,3 +1,8 @@ +/* Recreated Espressif libmain os_cpu_o contents. + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE +*/ #include "open_esplibs.h" #if OPEN_LIBMAIN_OS_CPU_A // The contents of this file are only built if OPEN_LIBMAIN_OS_CPU_A is set to true diff --git a/open_esplibs/libmain/spi_flash.c b/open_esplibs/libmain/spi_flash.c index ee2d2f4..91ee829 100644 --- a/open_esplibs/libmain/spi_flash.c +++ b/open_esplibs/libmain/spi_flash.c @@ -1,3 +1,8 @@ +/* Recreated Espressif libmain os_cpu_o contents. + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE +*/ #include "open_esplibs.h" #if OPEN_LIBMAIN_SPI_FLASH // The contents of this file are only built if OPEN_LIBMAIN_SPI_FLASH is set to true diff --git a/open_esplibs/libmain/timers.c b/open_esplibs/libmain/timers.c index d460088..4c1edb9 100644 --- a/open_esplibs/libmain/timers.c +++ b/open_esplibs/libmain/timers.c @@ -1,3 +1,8 @@ +/* Recreated Espressif libmain timers.o contents. + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE +*/ #include "open_esplibs.h" #if OPEN_LIBMAIN_TIMERS // The contents of this file are only built if OPEN_LIBMAIN_TIMERS is set to true diff --git a/open_esplibs/libmain/uart.c b/open_esplibs/libmain/uart.c index 5ee2699..b93d681 100644 --- a/open_esplibs/libmain/uart.c +++ b/open_esplibs/libmain/uart.c @@ -1,3 +1,8 @@ +/* Recreated Espressif libmain uart.o contents. + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE +*/ #include "open_esplibs.h" #if OPEN_LIBMAIN_UART // The contents of this file are only built if OPEN_LIBMAIN_UART is set to true diff --git a/open_esplibs/libmain/user_interface.c b/open_esplibs/libmain/user_interface.c index 9d6865b..5e89424 100644 --- a/open_esplibs/libmain/user_interface.c +++ b/open_esplibs/libmain/user_interface.c @@ -1,3 +1,8 @@ +/* Recreated Espressif libmain user_interface.o contents. + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE +*/ #include "open_esplibs.h" #if OPEN_LIBMAIN_USER_INTERFACE // The contents of this file are only built if OPEN_LIBMAIN_USER_INTERFACE is set to true diff --git a/open_esplibs/libmain/xtensa_context.S b/open_esplibs/libmain/xtensa_context.S index 139d5db..9e94cfd 100644 --- a/open_esplibs/libmain/xtensa_context.S +++ b/open_esplibs/libmain/xtensa_context.S @@ -1,3 +1,8 @@ +/* Recreated Espressif libmain xtensa_context.o contents. + + Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + BSD Licensed as described in the file LICENSE +*/ #include "open_esplibs.h" #if OPEN_LIBMAIN_XTENSA_CONTEXT // The contents of this file are only built if OPEN_LIBMAIN_XTENSA_CONTEXT is set to true From a41407e3d1422f7e339db2165f612d20b73f4a45 Mon Sep 17 00:00:00 2001 From: sheinz Date: Wed, 6 Jul 2016 15:57:00 +0300 Subject: [PATCH 16/26] DHT11/22 library fix Support DHT11/DHT22 modules. Data representation fix. Library refactoring. --- examples/dht_sensor/dht_sensor.c | 35 ++--- extras/dht/dht.c | 221 +++++++++++++++++++------------ extras/dht/dht.h | 31 ++++- 3 files changed, 181 insertions(+), 106 deletions(-) diff --git a/examples/dht_sensor/dht_sensor.c b/examples/dht_sensor/dht_sensor.c index 11f2c43..46292da 100644 --- a/examples/dht_sensor/dht_sensor.c +++ b/examples/dht_sensor/dht_sensor.c @@ -2,6 +2,8 @@ * * This sample code is in the public domain. */ +#include +#include #include "espressif/esp_common.h" #include "esp/uart.h" #include "FreeRTOS.h" @@ -13,29 +15,30 @@ * to read and print a new temperature and humidity measurement * from a sensor attached to GPIO pin 4. */ -int const dht_gpio = 4; +uint8_t const dht_gpio = 12; void dhtMeasurementTask(void *pvParameters) { - int8_t temperature = 0; - int8_t humidity = 0; + int16_t temperature = 0; + int16_t humidity = 0; - // DHT sensors that come mounted on a PCB generally have - // pull-up resistors on the data pin. It is recommended - // to provide an external pull-up resistor otherwise... - gpio_set_pullup(dht_gpio, false, false); + // DHT sensors that come mounted on a PCB generally have + // pull-up resistors on the data pin. It is recommended + // to provide an external pull-up resistor otherwise... + gpio_set_pullup(dht_gpio, false, false); - while(1) { + while(1) { + if (dht_read_data(dht_gpio, &humidity, &temperature)) { + printf("Humidity: %d.%d%% Temp: %d.%dC\n", + humidity / 10, humidity % 10, + temperature / 10, abs(temperature) % 10); + } else { + printf("Could not read data from sensor\n"); + } - if (dht_fetch_data(dht_gpio, &humidity, &temperature)) { - printf("Humidity: %i%% Temp: %iC\n", humidity, temperature); - } else { - printf("Could not read data from sensor..."); + // Three second delay... + vTaskDelay(3000 / portTICK_RATE_MS); } - - // Three second delay... - vTaskDelay(3000 / portTICK_RATE_MS); - } } void user_init(void) diff --git a/extras/dht/dht.c b/extras/dht/dht.c index 100763a..cd84eba 100644 --- a/extras/dht/dht.c +++ b/extras/dht/dht.c @@ -6,23 +6,26 @@ */ #include "dht.h" +#include "FreeRTOS.h" #include "string.h" #include "task.h" #include "esp/gpio.h" #include // sdk_os_delay_us -#ifndef DEBUG_DHT -#define DEBUG_DHT 0 -#endif +// DHT timer precision in microseconds +#define DHT_TIMER_INTERVAL 2 +#define DHT_DATA_BITS 40 -#if DEBUG_DHT +// #define DEBUG_DHT + +#ifdef DEBUG_DHT #define debug(fmt, ...) printf("%s" fmt "\n", "dht: ", ## __VA_ARGS__); #else #define debug(fmt, ...) /* (do nothing) */ #endif -/* +/* * Note: * A suitable pull-up resistor should be connected to the selected GPIO line * @@ -32,17 +35,17 @@ * * * Initializing communications with the DHT requires four 'phases' as follows: - * + * * Phase A - MCU pulls signal low for at least 18000 us * Phase B - MCU allows signal to float back up and waits 20-40us for DHT to pull it low * Phase C - DHT pulls signal low for ~80us * Phase D - DHT lets signal float back up for ~80us - * + * * After this, the DHT transmits its first bit by holding the signal low for 50us * and then letting it float back high for a period of time that depends on the data bit. * duration_data_high is shorter than 50us for a logic '0' and longer than 50us for logic '1'. * - * There are a total of 40 data bits trasnmitted sequentially. These bits are read into a byte array + * There are a total of 40 data bits transmitted sequentially. These bits are read into a byte array * of length 5. The first and third bytes are humidity (%) and temperature (C), respectively. Bytes 2 and 4 * are zero-filled and the fifth is a checksum such that: * @@ -50,95 +53,143 @@ * */ -/* - * @pin the selected GPIO pin - * @interval how frequently the pin state is checked in microseconds - * @timeout maximum length of time to wait for the expected pin state - * @expected_pin_state high (true) or low (false) pin state - * @counter pointer to external uint8_t for tallying the duration waited for the pin state -*/ -bool dht_await_pin_state(uint8_t pin, uint8_t interval, uint8_t timeout, bool expected_pin_state, uint8_t * counter) { - - for (*counter = 0; *counter < timeout; *counter+=interval) { - if (gpio_read(pin) == expected_pin_state) return true; - sdk_os_delay_us(interval); +/** + * Wait specified time for pin to go to a specified state. + * If timeout is reached and pin doesn't go to a requested state + * false is returned. + * The elapsed time is returned in pointer 'duration' if it is not NULL. + */ +static bool dht_await_pin_state(uint8_t pin, uint32_t timeout, + bool expected_pin_state, uint32_t *duration) +{ + for (uint32_t i = 0; i < timeout; i += DHT_TIMER_INTERVAL) { + if (gpio_read(pin) == expected_pin_state) { + if (duration) { + *duration = i; + } + return true; + } + sdk_os_delay_us(DHT_TIMER_INTERVAL); } return false; } -/* - * - * - * @pin the selected GPIO pin - * @humidity pointer to external int8_t to store resulting humidity value - * @temperature pointer to external int8_t to store resulting temperature value -*/ - -bool dht_fetch_data(int8_t pin, int8_t * humidity, int8_t * temperature) { - int8_t data[40] = {0}; - int8_t result[5] = {0}; - uint8_t i = 0; - - uint8_t init_phase_duration = 0; - uint8_t duration_data_low = 0; - uint8_t duration_data_high = 0; - - gpio_enable(pin, GPIO_OUT_OPEN_DRAIN); - - taskENTER_CRITICAL(); +/** + * Request data from DHT and read raw bit stream. + * The function call should be protected from task switching. + * Return false if error occurred. + */ +static inline bool dht_fetch_data(uint8_t pin, bool bits[DHT_DATA_BITS]) +{ + uint32_t low_duration; + uint32_t high_duration; // Phase 'A' pulling signal low to initiate read sequence gpio_write(pin, 0); sdk_os_delay_us(20000); gpio_write(pin, 1); - // Step through Phase 'B' at 2us intervals, 40us max - if (dht_await_pin_state(pin, 2, 40, false, &init_phase_duration)) { - // Step through Phase 'C ' at 2us intervals, 88us max - if (dht_await_pin_state(pin, 2, 88, true, &init_phase_duration)) { - // Step through Phase 'D' at 2us intervals, 88us max - if (dht_await_pin_state(pin, 2, 88, false, &init_phase_duration)) { - - // Read in each of the 40 bits of data... - for (i = 0; i < 40; i++) { - if (dht_await_pin_state(pin, 2, 60, true, &duration_data_low)) { - if (dht_await_pin_state(pin, 2, 75, false, &duration_data_high)) { - data[i] = duration_data_high > duration_data_low; - } - } - } - - taskEXIT_CRITICAL(); - - for (i = 0; i < 40; i++) { - // Read each bit into 'result' byte array... - result[i/8] <<= 1; - result[i/8] |= data[i]; - } - - if (result[4] == ((result[0] + result[1] + result[2] + result[3]) & 0xFF)) { - // Data valid, checksum succeeded... - *humidity = result[0]; - *temperature = result[2]; - debug("Successfully retrieved sensor data..."); - return true; - } else { - debug("Checksum failed, invalid data received from sensor..."); - } - - } else { - debug("Initialization error, problem in phase 'D'..."); - } - } else { - debug("Initialization error, problem in phase 'C'..."); - } - } else { - debug("Initialization error, problem in phase 'B'..."); + // Step through Phase 'B', 40us + if (!dht_await_pin_state(pin, 40, false, NULL)) { + debug("Initialization error, problem in phase 'B'\n"); + return false; } - - taskEXIT_CRITICAL(); - return false; + + // Step through Phase 'C', 88us + if (!dht_await_pin_state(pin, 88, true, NULL)) { + debug("Initialization error, problem in phase 'C'\n"); + return false; + } + + // Step through Phase 'D', 88us + if (!dht_await_pin_state(pin, 88, false, NULL)) { + debug("Initialization error, problem in phase 'D'\n"); + return false; + } + + // Read in each of the 40 bits of data... + for (int i = 0; i < DHT_DATA_BITS; i++) { + if (!dht_await_pin_state(pin, 65, true, &low_duration)) { + debug("LOW bit timeout\n"); + return false; + } + if (!dht_await_pin_state(pin, 75, false, &high_duration)){ + debug("HIGHT bit timeout\n"); + return false; + } + bits[i] = high_duration > low_duration; + } + return true; } +/** + * Pack two data bytes into single value and take into account sign bit. + */ +static inline int16_t dht_convert_data(uint8_t msb, uint8_t lsb) +{ + int16_t data; + +#if DHT_TYPE == DHT22 + data = msb & 0x7F; + data <<= 8; + data |= lsb; + if (msb & BIT(15)) { + data = 0 - data; // convert it to negative + } +#elif DHT_TYPE == DHT11 + data = msb * 10; +#else +#error "Unsupported DHT type" +#endif + + return data; +} + +bool dht_read_data(uint8_t pin, int16_t *humidity, int16_t *temperature) +{ + bool bits[DHT_DATA_BITS]; + uint8_t data[DHT_DATA_BITS/8] = {0}; + bool result; + + gpio_enable(pin, GPIO_OUT_OPEN_DRAIN); + + taskENTER_CRITICAL(); + result = dht_fetch_data(pin, bits); + taskEXIT_CRITICAL(); + + if (!result) { + return false; + } + + for (uint8_t i = 0; i < DHT_DATA_BITS; i++) { + // Read each bit into 'result' byte array... + data[i/8] <<= 1; + data[i/8] |= bits[i]; + } + + if (data[4] != (data[0] + data[1] + data[2] + data[3])) { + debug("Checksum failed, invalid data received from sensor\n"); + return false; + } + + *humidity = dht_convert_data(data[0], data[1]); + *temperature = dht_convert_data(data[2], data[3]); + + debug("Sensor data: humidity=%d, temp=%d\n", *humidity, *temperature); + + return true; +} + +bool dht_read_float_data(uint8_t pin, float *humidity, float *temperature) +{ + int16_t i_humidity, i_temp; + + if (dht_read_data(pin, &i_humidity, &i_temp)) { + *humidity = (float)i_humidity / 10; + *temperature = (float)i_temp / 10; + return true; + } + return false; +} diff --git a/extras/dht/dht.h b/extras/dht/dht.h index c8a5ed9..3f69a29 100644 --- a/extras/dht/dht.h +++ b/extras/dht/dht.h @@ -5,13 +5,34 @@ * */ -#ifndef __DTH_H__ +#ifndef __DHT_H__ #define __DHT_H__ -#include "FreeRTOS.h" +#include +#include -bool dht_wait_for_pin_state(uint8_t pin, uint8_t interval, uint8_t timeout, bool expected_pin_sate, uint8_t * counter); -bool dht_fetch_data(int8_t pin, int8_t * humidity, int8_t * temperature); +#define DHT11 11 +#define DHT22 22 -#endif +// Type of sensor to use +#define DHT_TYPE DHT22 +/** + * Read data from sensor on specified pin. + * + * Humidity and temperature is returned as integers. + * For example: humidity=625 is 62.5 % + * temperature=24.4 is 24.4 degrees Celsius + * + */ +bool dht_read_data(uint8_t pin, int16_t *humidity, int16_t *temperature); + + +/** + * Float version of dht_read_data. + * + * Return values as floating point values. + */ +bool dht_read_float_data(uint8_t pin, float *humidity, float *temperature); + +#endif // __DHT_H__ From 6ff78f802d3c8b14c225786625770887c0011c81 Mon Sep 17 00:00:00 2001 From: sheinz Date: Wed, 6 Jul 2016 21:01:44 +0300 Subject: [PATCH 17/26] DHT11/DHT22 library fixes. Fixed temperature below zero. Fixed checksum overflow verification. Fixed inconsistent reading of DHT11. --- examples/dht_sensor/dht_sensor.c | 8 ++++---- extras/dht/dht.c | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/dht_sensor/dht_sensor.c b/examples/dht_sensor/dht_sensor.c index 46292da..425d5c0 100644 --- a/examples/dht_sensor/dht_sensor.c +++ b/examples/dht_sensor/dht_sensor.c @@ -15,7 +15,7 @@ * to read and print a new temperature and humidity measurement * from a sensor attached to GPIO pin 4. */ -uint8_t const dht_gpio = 12; +uint8_t const dht_gpio = 4; void dhtMeasurementTask(void *pvParameters) { @@ -29,9 +29,9 @@ void dhtMeasurementTask(void *pvParameters) while(1) { if (dht_read_data(dht_gpio, &humidity, &temperature)) { - printf("Humidity: %d.%d%% Temp: %d.%dC\n", - humidity / 10, humidity % 10, - temperature / 10, abs(temperature) % 10); + printf("Humidity: %d%% Temp: %dC\n", + humidity / 10, + temperature / 10); } else { printf("Could not read data from sensor\n"); } diff --git a/extras/dht/dht.c b/extras/dht/dht.c index cd84eba..3930735 100644 --- a/extras/dht/dht.c +++ b/extras/dht/dht.c @@ -64,13 +64,14 @@ static bool dht_await_pin_state(uint8_t pin, uint32_t timeout, bool expected_pin_state, uint32_t *duration) { for (uint32_t i = 0; i < timeout; i += DHT_TIMER_INTERVAL) { + // need to wait at least a single interval to prevent reading a jitter + sdk_os_delay_us(DHT_TIMER_INTERVAL); if (gpio_read(pin) == expected_pin_state) { if (duration) { *duration = i; } return true; } - sdk_os_delay_us(DHT_TIMER_INTERVAL); } return false; @@ -135,7 +136,7 @@ static inline int16_t dht_convert_data(uint8_t msb, uint8_t lsb) data = msb & 0x7F; data <<= 8; data |= lsb; - if (msb & BIT(15)) { + if (msb & BIT(7)) { data = 0 - data; // convert it to negative } #elif DHT_TYPE == DHT11 @@ -169,7 +170,7 @@ bool dht_read_data(uint8_t pin, int16_t *humidity, int16_t *temperature) data[i/8] |= bits[i]; } - if (data[4] != (data[0] + data[1] + data[2] + data[3])) { + if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) { debug("Checksum failed, invalid data received from sensor\n"); return false; } From 5c12b7c7e92e2317c89f618d1280f8aa042aeb1b Mon Sep 17 00:00:00 2001 From: sheinz Date: Mon, 27 Jun 2016 18:06:06 +0300 Subject: [PATCH 18/26] Draft implementation of SPIFFS integration --- .gitmodules | 3 + examples/spiffs/Makefile | 9 ++ examples/spiffs/spiffs_example.c | 180 +++++++++++++++++++++ extras/spiffs/component.mk | 17 ++ extras/spiffs/esp_spiffs.c | 187 ++++++++++++++++++++++ extras/spiffs/esp_spiffs.h | 28 ++++ extras/spiffs/spiffs | 1 + extras/spiffs/spiffs_config.h | 263 +++++++++++++++++++++++++++++++ 8 files changed, 688 insertions(+) create mode 100644 examples/spiffs/Makefile create mode 100644 examples/spiffs/spiffs_example.c create mode 100644 extras/spiffs/component.mk create mode 100644 extras/spiffs/esp_spiffs.c create mode 100644 extras/spiffs/esp_spiffs.h create mode 160000 extras/spiffs/spiffs create mode 100644 extras/spiffs/spiffs_config.h diff --git a/.gitmodules b/.gitmodules index 7a3370e..00dadd8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,6 @@ path = bootloader/rboot url = https://github.com/raburton/rboot.git +[submodule "extras/spiffs/spiffs"] + path = extras/spiffs/spiffs + url = https://github.com/pellepl/spiffs.git diff --git a/examples/spiffs/Makefile b/examples/spiffs/Makefile new file mode 100644 index 0000000..b342df7 --- /dev/null +++ b/examples/spiffs/Makefile @@ -0,0 +1,9 @@ +PROGRAM=spiffs_example +EXTRA_COMPONENTS = extras/spiffs +FLASH_SIZE = 32 + +# spiffs configuration +SPIFFS_BASE_ADDR = 0x200000 +SPIFFS_SIZE = 0x100000 + +include ../../common.mk diff --git a/examples/spiffs/spiffs_example.c b/examples/spiffs/spiffs_example.c new file mode 100644 index 0000000..226ee51 --- /dev/null +++ b/examples/spiffs/spiffs_example.c @@ -0,0 +1,180 @@ +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include "esp8266.h" + +#include "spiffs.h" +#include "esp_spiffs.h" + + +#define TEST_FILE_NAME_LEN 16 +#define TEST_FILES 32 +#define TEST_FILE_MAX_SIZE 8192 + +typedef struct { + char name[TEST_FILE_NAME_LEN]; + uint16_t size; + uint8_t first_data_byte; +} TestFile; + +static TestFile test_files[TEST_FILES]; + +inline static void fill_test_data(uint8_t *src, uint16_t size, uint8_t first_byte) +{ + while (size--) { + *src++ = first_byte++; + } +} + +static bool write_test_files() +{ + uint8_t *buf = (uint8_t*)malloc(TEST_FILE_MAX_SIZE); + bool result = true; + + for (uint8_t i = 0; i < TEST_FILES; i++) { + sprintf(test_files[i].name, "file_%d.dat", i); + spiffs_file f = SPIFFS_open(&fs, test_files[i].name, + SPIFFS_CREAT|SPIFFS_RDWR|SPIFFS_TRUNC, 0); + if (f < 0) { + printf("Open file operation failed\n"); + result = false; + break; + } + test_files[i].size = rand() % TEST_FILE_MAX_SIZE; + test_files[i].first_data_byte = rand() % 256; + fill_test_data(buf, test_files[i].size, test_files[i].first_data_byte); + + printf("Writing file %s size=%d\n", test_files[i].name, + test_files[i].size); + int32_t written = SPIFFS_write(&fs, f, buf, test_files[i].size); + if (written != test_files[i].size) { + printf("Write file operation failed, written=%d\n", written); + result = false; + break; + } + SPIFFS_close(&fs, f); + } + free(buf); + return result; +} + +inline static bool verify_test_data(uint8_t *data, uint16_t size, + uint8_t first_byte) +{ + while (size--) { + if (*data++ != first_byte++) { + return false; + } + } + return true; +} + +static bool verify_test_files() +{ + uint8_t *buf = (uint8_t*)malloc(TEST_FILE_MAX_SIZE); + bool result = true; + + for (uint8_t i = 0; i < TEST_FILES; i++) { + printf("Verifying file %s\n", test_files[i].name); + spiffs_file f = SPIFFS_open(&fs, test_files[i].name, SPIFFS_RDONLY, 0); + if (f < 0) { + printf("Open file operation failed\n"); + result = false; + break; + } + + int32_t n = SPIFFS_read(&fs, f, buf, test_files[i].size); + if (n != test_files[i].size) { + printf("Read file operation failed\n"); + result = false; + break; + } + + if (!verify_test_data(buf, test_files[i].size, + test_files[i].first_data_byte)) { + printf("Data verification failed\n"); + result = false; + break; + } + + SPIFFS_close(&fs, f); + } + + free(buf); + return result; +} + +static bool cleanup_test_files() +{ + bool result = true; + + for (uint8_t i = 0; i < TEST_FILES; i++) { + printf("Removing file %s\n", test_files[i].name); + if (SPIFFS_remove(&fs, test_files[i].name) != SPIFFS_OK) { + printf("Remove file operation failed\n"); + result = false; + break; + } + } + return result; +} + +inline static void print_info() +{ + uint32_t total, used; + + SPIFFS_info(&fs, &total, &used); + + printf("FS total=%d bytes, used=%d bytes\n", total, used); + printf("FS %d %% used\n", 100 * used/total); + + // File system structure visualisation + // SPIFFS_vis(&fs); +} + +void test_task(void *pvParameters) +{ + bool result = true; + + esp_spiffs_mount(); + esp_spiffs_unmount(); // FS must be unmounted before formating + if (SPIFFS_format(&fs) == SPIFFS_OK) { + printf("Format complete\n"); + } else { + printf("Format failed\n"); + } + esp_spiffs_mount(); + + while (1) { + vTaskDelay(5000 / portTICK_RATE_MS); + + result = write_test_files(); + + if (result) { + result = verify_test_files(); + } + + print_info(); + + if (result) { + result = cleanup_test_files(); + } + + if (result) { + printf("Test passed!\n"); + } else { + printf("Test failed!\n"); + while (1) { + vTaskDelay(1); + } + } + } +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + + xTaskCreate(test_task, (signed char *)"test_task", 1024, NULL, 2, NULL); +} diff --git a/extras/spiffs/component.mk b/extras/spiffs/component.mk new file mode 100644 index 0000000..fcd5572 --- /dev/null +++ b/extras/spiffs/component.mk @@ -0,0 +1,17 @@ +# Component makefile for extras/spiffs + +SPIFFS_BASE_ADDR ?= 0x300000 +SPIFFS_SIZE ?= 0x100000 + +INC_DIRS += $(spiffs_ROOT) +INC_DIRS += $(spiffs_ROOT)spiffs/src + +# args for passing into compile rule generation +spiffs_SRC_DIR = $(spiffs_ROOT)spiffs/src +spiffs_SRC_DIR += $(spiffs_ROOT) + +spiffs_CFLAGS = $(CFLAGS) +spiffs_CFLAGS += -DSPIFFS_BASE_ADDR=$(SPIFFS_BASE_ADDR) +spiffs_CFLAGS += -DSPIFFS_SIZE=$(SPIFFS_SIZE) + +$(eval $(call component_compile_rules,spiffs)) diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c new file mode 100644 index 0000000..d6ec7d6 --- /dev/null +++ b/extras/spiffs/esp_spiffs.c @@ -0,0 +1,187 @@ +/** + * ESP8266 SPIFFS HAL configuration. + * + * Part of esp-open-rtos + * Copyright (c) 2016 sheinz https://github.com/sheinz + * MIT License + */ +#include "esp_spiffs.h" +#include "spiffs.h" +#include +#include + +spiffs fs; + +static void *work_buf = 0; +static void *fds_buf = 0; +static void *cache_buf = 0; + +/* + * Flash addresses and size alignment is a rip-off of Arduino implementation. + */ + +static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst) +{ + uint32_t result = SPIFFS_OK; + uint32_t alignedBegin = (addr + 3) & (~3); + uint32_t alignedEnd = (addr + size) & (~3); + if (alignedEnd < alignedBegin) { + alignedEnd = alignedBegin; + } + + if (addr < alignedBegin) { + uint32_t nb = alignedBegin - addr; + uint32_t tmp; + if (sdk_spi_flash_read(alignedEnd - 4, &tmp, 4) != SPI_FLASH_RESULT_OK) { + printf("spi_flash_read failed\n"); + return SPIFFS_ERR_INTERNAL; + } + memcpy(dst, &tmp + 4 - nb, nb); + } + + if (alignedEnd != alignedBegin) { + if (sdk_spi_flash_read(alignedBegin, + (uint32_t*) (dst + alignedBegin - addr), + alignedEnd - alignedBegin) != SPI_FLASH_RESULT_OK) { + printf("spi_flash_read failed\n"); + return SPIFFS_ERR_INTERNAL; + } + } + + if (addr + size > alignedEnd) { + uint32_t nb = addr + size - alignedEnd; + uint32_t tmp; + if (sdk_spi_flash_read(alignedEnd, &tmp, 4) != SPI_FLASH_RESULT_OK) { + printf("spi_flash_read failed\n"); + return SPIFFS_ERR_INTERNAL; + } + + memcpy(dst + size - nb, &tmp, nb); + } + + return result; +} + +static const int UNALIGNED_WRITE_BUFFER_SIZE = 512; + +static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src) +{ + uint32_t alignedBegin = (addr + 3) & (~3); + uint32_t alignedEnd = (addr + size) & (~3); + if (alignedEnd < alignedBegin) { + alignedEnd = alignedBegin; + } + + if (addr < alignedBegin) { + uint32_t ofs = alignedBegin - addr; + uint32_t nb = (size < ofs) ? size : ofs; + uint8_t tmp[4] __attribute__((aligned(4))) = {0xff, 0xff, 0xff, 0xff}; + memcpy(tmp + 4 - ofs, src, nb); + if (sdk_spi_flash_write(alignedBegin - 4, (uint32_t*) tmp, 4) + != SPI_FLASH_RESULT_OK) { + printf("spi_flash_write failed\n"); + return SPIFFS_ERR_INTERNAL; + } + } + + if (alignedEnd != alignedBegin) { + uint32_t* srcLeftover = (uint32_t*) (src + alignedBegin - addr); + uint32_t srcAlign = ((uint32_t) srcLeftover) & 3; + if (!srcAlign) { + if (sdk_spi_flash_write(alignedBegin, (uint32_t*) srcLeftover, + alignedEnd - alignedBegin) != SPI_FLASH_RESULT_OK) { + printf("spi_flash_write failed\n"); + return SPIFFS_ERR_INTERNAL; + } + } + else { + uint8_t buf[UNALIGNED_WRITE_BUFFER_SIZE]; + for (uint32_t sizeLeft = alignedEnd - alignedBegin; sizeLeft; ) { + size_t willCopy = sizeLeft < sizeof(buf) ? sizeLeft : sizeof(buf); + memcpy(buf, srcLeftover, willCopy); + + if (sdk_spi_flash_write(alignedBegin, (uint32_t*) buf, willCopy) + != SPI_FLASH_RESULT_OK) { + printf("spi_flash_write failed\n"); + return SPIFFS_ERR_INTERNAL; + } + + sizeLeft -= willCopy; + srcLeftover += willCopy; + alignedBegin += willCopy; + } + } + } + + if (addr + size > alignedEnd) { + uint32_t nb = addr + size - alignedEnd; + uint32_t tmp = 0xffffffff; + memcpy(&tmp, src + size - nb, nb); + + if (sdk_spi_flash_write(alignedEnd, &tmp, 4) != SPI_FLASH_RESULT_OK) { + printf("spi_flash_write failed\n"); + return SPIFFS_ERR_INTERNAL; + } + } + + return SPIFFS_OK; +} + +static s32_t esp_spiffs_erase(u32_t addr, u32_t size) +{ + if (addr % SPI_FLASH_SEC_SIZE) { + printf("Unaligned erase addr=%x\n", addr); + } + if (size % SPI_FLASH_SEC_SIZE) { + printf("Unaligned erase size=%d\n", size); + } + + const uint32_t sector = addr / SPI_FLASH_SEC_SIZE; + const uint32_t sectorCount = size / SPI_FLASH_SEC_SIZE; + + for (uint32_t i = 0; i < sectorCount; ++i) { + sdk_spi_flash_erase_sector(sector + i); + } + return SPIFFS_OK; +} + +int32_t esp_spiffs_mount() +{ + spiffs_config config = {0}; + + config.hal_read_f = esp_spiffs_read; + config.hal_write_f = esp_spiffs_write; + config.hal_erase_f = esp_spiffs_erase; + + size_t workBufSize = 2 * SPIFFS_CFG_LOG_PAGE_SZ(); + size_t fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&fs, 5); + size_t cacheBufSize = SPIFFS_buffer_bytes_for_cache(&fs, 5); + + work_buf = malloc(workBufSize); + fds_buf = malloc(fdsBufSize); + cache_buf = malloc(cacheBufSize); + printf("spiffs memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", + workBufSize, fdsBufSize, cacheBufSize); + + int32_t err = SPIFFS_mount(&fs, &config, work_buf, fds_buf, fdsBufSize, + cache_buf, cacheBufSize, 0); + + if (err != SPIFFS_OK) { + printf("Error spiffs mount: %d\n", err); + } + + return err; +} + +void esp_spiffs_unmount() +{ + SPIFFS_unmount(&fs); + + free(work_buf); + free(fds_buf); + free(cache_buf); + + work_buf = 0; + fds_buf = 0; + cache_buf = 0; +} diff --git a/extras/spiffs/esp_spiffs.h b/extras/spiffs/esp_spiffs.h new file mode 100644 index 0000000..3022d51 --- /dev/null +++ b/extras/spiffs/esp_spiffs.h @@ -0,0 +1,28 @@ +/** + * ESP8266 SPIFFS HAL configuration. + * + * Part of esp-open-rtos + * Copyright (c) 2016 sheinz https://github.com/sheinz + * MIT License + */ +#ifndef __ESP_SPIFFS_H__ +#define __ESP_SPIFFS_H__ + +#include "spiffs.h" + +extern spiffs fs; + +/** + * Provide SPIFFS with all necessary configuration, allocate memory buffers + * and mount SPIFFS. + * + * Return SPIFFS return code. + */ +int32_t esp_spiffs_mount(); + +/** + * Unmount SPIFFS and free all allocated buffers. + */ +void esp_spiffs_unmount(); + +#endif // __ESP_SPIFFS_H__ diff --git a/extras/spiffs/spiffs b/extras/spiffs/spiffs new file mode 160000 index 0000000..c6e94fd --- /dev/null +++ b/extras/spiffs/spiffs @@ -0,0 +1 @@ +Subproject commit c6e94fdca5c1601b90c027167f8d453c48e482c4 diff --git a/extras/spiffs/spiffs_config.h b/extras/spiffs/spiffs_config.h new file mode 100644 index 0000000..7b8c1a7 --- /dev/null +++ b/extras/spiffs/spiffs_config.h @@ -0,0 +1,263 @@ +/* + * spiffs_config.h + * + * Created on: Jul 3, 2013 + * Author: petera + */ + +#ifndef SPIFFS_CONFIG_H_ +#define SPIFFS_CONFIG_H_ + +// ----------- 8< ------------ +#include +#include +#include +#include +#include +#include +// #include // for vPortEnterCritical/vPortExitCritical +// ----------- >8 ------------ + +typedef signed int s32_t; +typedef unsigned int u32_t; +typedef signed short s16_t; +typedef unsigned short u16_t; +typedef signed char s8_t; +typedef unsigned char u8_t; + +// compile time switches + +// Set generic spiffs debug output call. +#ifndef SPIFFS_DBG +#define SPIFFS_DBG(...) //printf(__VA_ARGS__) +#endif +// Set spiffs debug output call for garbage collecting. +#ifndef SPIFFS_GC_DBG +#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__) +#endif +// Set spiffs debug output call for caching. +#ifndef SPIFFS_CACHE_DBG +#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__) +#endif +// Set spiffs debug output call for system consistency checks. +#ifndef SPIFFS_CHECK_DBG +#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__) +#endif + +// Enable/disable API functions to determine exact number of bytes +// for filedescriptor and cache buffers. Once decided for a configuration, +// this can be disabled to reduce flash. +#ifndef SPIFFS_BUFFER_HELP +#define SPIFFS_BUFFER_HELP 1 +#endif + +// Enables/disable memory read caching of nucleus file system operations. +// If enabled, memory area must be provided for cache in SPIFFS_mount. +#ifndef SPIFFS_CACHE +#define SPIFFS_CACHE 1 +#endif +#if SPIFFS_CACHE +// Enables memory write caching for file descriptors in hydrogen +#ifndef SPIFFS_CACHE_WR +#define SPIFFS_CACHE_WR 1 +#endif + +// Enable/disable statistics on caching. Debug/test purpose only. +#ifndef SPIFFS_CACHE_STATS +#define SPIFFS_CACHE_STATS 0 +#endif +#endif + +// Always check header of each accessed page to ensure consistent state. +// If enabled it will increase number of reads, will increase flash. +#ifndef SPIFFS_PAGE_CHECK +#define SPIFFS_PAGE_CHECK 1 +#endif + +// Define maximum number of gc runs to perform to reach desired free pages. +#ifndef SPIFFS_GC_MAX_RUNS +#define SPIFFS_GC_MAX_RUNS 3 +#endif + +// Enable/disable statistics on gc. Debug/test purpose only. +#ifndef SPIFFS_GC_STATS +#define SPIFFS_GC_STATS 0 +#endif + +// Garbage collecting examines all pages in a block which and sums up +// to a block score. Deleted pages normally gives positive score and +// used pages normally gives a negative score (as these must be moved). +// To have a fair wear-leveling, the erase age is also included in score, +// whose factor normally is the most positive. +// The larger the score, the more likely it is that the block will +// picked for garbage collection. + +// Garbage collecting heuristics - weight used for deleted pages. +#ifndef SPIFFS_GC_HEUR_W_DELET +#define SPIFFS_GC_HEUR_W_DELET (5) +#endif +// Garbage collecting heuristics - weight used for used pages. +#ifndef SPIFFS_GC_HEUR_W_USED +#define SPIFFS_GC_HEUR_W_USED (-1) +#endif +// Garbage collecting heuristics - weight used for time between +// last erased and erase of this block. +#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE +#define SPIFFS_GC_HEUR_W_ERASE_AGE (50) +#endif + +// Object name maximum length. Note that this length include the +// zero-termination character, meaning maximum string of characters +// can at most be SPIFFS_OBJ_NAME_LEN - 1. +#ifndef SPIFFS_OBJ_NAME_LEN +#define SPIFFS_OBJ_NAME_LEN (32) +#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. +#ifndef SPIFFS_COPY_BUFFER_STACK +#define SPIFFS_COPY_BUFFER_STACK (64) +#endif + +// Enable this to have an identifiable spiffs filesystem. This will look for +// a magic in all sectors to determine if this is a valid spiffs system or +// not on mount point. If not, SPIFFS_format must be called prior to mounting +// again. +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (0) +#endif + +#if SPIFFS_USE_MAGIC +// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is +// enabled, the magic will also be dependent on the length of the filesystem. +// For example, a filesystem configured and formatted for 4 megabytes will not +// be accepted for mounting with a configuration defining the filesystem as 2 +// megabytes. +#ifndef SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH (0) +#endif +#endif + +// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level +// These should be defined on a multithreaded system + +// define this to enter a mutex if you're running on a multithreaded system +#ifndef SPIFFS_LOCK +#define SPIFFS_LOCK(fs) // vPortEnterCritical() +#endif +// define this to exit a mutex if you're running on a multithreaded system +#ifndef SPIFFS_UNLOCK +#define SPIFFS_UNLOCK(fs) // vPortExitCritical() +#endif + +// Enable if only one spiffs instance with constant configuration will exist +// on the target. This will reduce calculations, flash and memory accesses. +// Parts of configuration must be defined below instead of at time of mount. +#ifndef SPIFFS_SINGLETON +#define SPIFFS_SINGLETON 1 +#endif + +#if SPIFFS_SINGLETON +// Instead of giving parameters in config struct, singleton build must +// give parameters in defines below. +#ifndef SPIFFS_CFG_PHYS_SZ +#define SPIFFS_CFG_PHYS_SZ(ignore) (SPIFFS_SIZE) +#endif +#ifndef SPIFFS_CFG_PHYS_ERASE_SZ +#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (4*1024) +#endif +#ifndef SPIFFS_CFG_PHYS_ADDR +#define SPIFFS_CFG_PHYS_ADDR(ignore) (SPIFFS_BASE_ADDR) +#endif +#ifndef SPIFFS_CFG_LOG_PAGE_SZ +#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) +#endif +#ifndef SPIFFS_CFG_LOG_BLOCK_SZ +#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (4*1024) +#endif +#endif + +// Enable this if your target needs aligned data for index tables +#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1 +#endif + +// Enable this if you want the HAL callbacks to be called with the spiffs struct +#ifndef SPIFFS_HAL_CALLBACK_EXTRA +#define SPIFFS_HAL_CALLBACK_EXTRA 0 +#endif + +// Enable this if you want to add an integer offset to all file handles +// (spiffs_file). This is useful if running multiple instances of spiffs on +// same target, in order to recognise to what spiffs instance a file handle +// belongs. +// NB: This adds config field fh_ix_offset in the configuration struct when +// mounting, which must be defined. +#ifndef SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FILEHDL_OFFSET 0 +#endif + +// Enable this to compile a read only version of spiffs. +// This will reduce binary size of spiffs. All code comprising modification +// of the file system will not be compiled. Some config will be ignored. +// HAL functions for erasing and writing to spi-flash may be null. Cache +// can be disabled for even further binary size reduction (and ram savings). +// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL. +// If the file system cannot be mounted due to aborted erase operation and +// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be +// returned. +// Might be useful for e.g. bootloaders and such. +#ifndef SPIFFS_READ_ONLY +#define SPIFFS_READ_ONLY 0 +#endif + +// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function +// in the api. This function will visualize all filesystem using given printf +// function. +#ifndef SPIFFS_TEST_VISUALISATION +#define SPIFFS_TEST_VISUALISATION 1 +#endif +#if SPIFFS_TEST_VISUALISATION +#ifndef spiffs_printf +#define spiffs_printf(...) printf(__VA_ARGS__) +#endif +// spiffs_printf argument for a free page +#ifndef SPIFFS_TEST_VIS_FREE_STR +#define SPIFFS_TEST_VIS_FREE_STR "_" +#endif +// spiffs_printf argument for a deleted page +#ifndef SPIFFS_TEST_VIS_DELE_STR +#define SPIFFS_TEST_VIS_DELE_STR "/" +#endif +// spiffs_printf argument for an index page for given object id +#ifndef SPIFFS_TEST_VIS_INDX_STR +#define SPIFFS_TEST_VIS_INDX_STR(id) "i" +#endif +// spiffs_printf argument for a data page for given object id +#ifndef SPIFFS_TEST_VIS_DATA_STR +#define SPIFFS_TEST_VIS_DATA_STR(id) "d" +#endif +#endif + +// Types depending on configuration such as the amount of flash bytes +// given to spiffs file system in total (spiffs_file_system_size), +// the logical block size (log_block_size), and the logical page size +// (log_page_size) + +// Block index type. Make sure the size of this type can hold +// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size +typedef u16_t spiffs_block_ix; +// Page index type. Make sure the size of this type can hold +// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size +typedef u16_t spiffs_page_ix; +// Object id type - most significant bit is reserved for index flag. Make sure the +// size of this type can hold the highest object id on a full system, +// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2 +typedef u16_t spiffs_obj_id; +// Object span index type. Make sure the size of this type can +// hold the largest possible span index on the system - +// i.e. (spiffs_file_system_size / log_page_size) - 1 +typedef u16_t spiffs_span_ix; + +#endif /* SPIFFS_CONFIG_H_ */ From d25b8b2a55be217034f2063bf7943a752e86b6e5 Mon Sep 17 00:00:00 2001 From: sheinz Date: Sun, 10 Jul 2016 01:33:23 +0300 Subject: [PATCH 19/26] Create SPIFFS image and flash it. mkspiffs is added to create SPIFFS image from directory with files. Build process changed to flash SPIFFS image if necessary --- common.mk | 3 +- examples/spiffs/Makefile | 2 + examples/spiffs/files/test.txt | 1 + extras/spiffs/component.mk | 33 ++++ extras/spiffs/mkspiffs/Makefile | 37 +++++ extras/spiffs/mkspiffs/README.md | 34 +++++ extras/spiffs/mkspiffs/mkspiffs.c | 243 ++++++++++++++++++++++++++++++ 7 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 examples/spiffs/files/test.txt create mode 100644 extras/spiffs/mkspiffs/Makefile create mode 100644 extras/spiffs/mkspiffs/README.md create mode 100644 extras/spiffs/mkspiffs/mkspiffs.c diff --git a/common.mk b/common.mk index 172fbe2..f4bfe06 100644 --- a/common.mk +++ b/common.mk @@ -210,7 +210,8 @@ $(FW_FILE): $(PROGRAM_OUT) $(FIRMWARE_DIR) $(Q) $(ESPTOOL) elf2image --version=2 $(ESPTOOL_ARGS) $< -o $(FW_FILE) flash: $(FW_FILE) - $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) 0x0 $(RBOOT_BIN) 0x1000 $(RBOOT_CONF) 0x2000 $(FW_FILE) + $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) write_flash $(ESPTOOL_ARGS) \ + 0x0 $(RBOOT_BIN) 0x1000 $(RBOOT_CONF) 0x2000 $(FW_FILE) $(SPIFFS_ESPTOOL_ARGS) erase_flash: $(ESPTOOL) -p $(ESPPORT) --baud $(ESPBAUD) erase_flash diff --git a/examples/spiffs/Makefile b/examples/spiffs/Makefile index b342df7..b0be23f 100644 --- a/examples/spiffs/Makefile +++ b/examples/spiffs/Makefile @@ -7,3 +7,5 @@ SPIFFS_BASE_ADDR = 0x200000 SPIFFS_SIZE = 0x100000 include ../../common.mk + +$(eval $(call make_spiffs_image,files)) diff --git a/examples/spiffs/files/test.txt b/examples/spiffs/files/test.txt new file mode 100644 index 0000000..c86fb0c --- /dev/null +++ b/examples/spiffs/files/test.txt @@ -0,0 +1 @@ +This file will go to SPIFFS image. diff --git a/extras/spiffs/component.mk b/extras/spiffs/component.mk index fcd5572..cf0a5a0 100644 --- a/extras/spiffs/component.mk +++ b/extras/spiffs/component.mk @@ -14,4 +14,37 @@ spiffs_CFLAGS = $(CFLAGS) spiffs_CFLAGS += -DSPIFFS_BASE_ADDR=$(SPIFFS_BASE_ADDR) spiffs_CFLAGS += -DSPIFFS_SIZE=$(SPIFFS_SIZE) + +# Create an SPIFFS image of specified directory and flash it with +# the rest of the firmware. +# +# Argumens: +# $(1) - directory with files which go into spiffs image +# +# Example: +# $(eval $(call make_spiffs_image,files)) +define make_spiffs_image +SPIFFS_IMAGE = $(addprefix $(FIRMWARE_DIR),spiffs.bin) +MKSPIFFS_DIR = $(ROOT)/extras/spiffs/mkspiffs +MKSPIFFS = $$(MKSPIFFS_DIR)/mkspiffs + +all: $$(SPIFFS_IMAGE) + +clean: clean_spiffs_img clean_mkspiffs + +$$(SPIFFS_IMAGE): $$(MKSPIFFS) $(1) + $$< $(1) $$@ + +$$(MKSPIFFS): + $$(MAKE) -C $$(MKSPIFFS_DIR) SPIFFS_SIZE=$(SPIFFS_SIZE) + +clean_spiffs_img: + $$(Q) rm -f spiffs.img + +clean_mkspiffs: + $$(Q) $$(MAKE) -C $$(MKSPIFFS_DIR) clean + +SPIFFS_ESPTOOL_ARGS = $(SPIFFS_BASE_ADDR) $$(SPIFFS_IMAGE) +endef + $(eval $(call component_compile_rules,spiffs)) diff --git a/extras/spiffs/mkspiffs/Makefile b/extras/spiffs/mkspiffs/Makefile new file mode 100644 index 0000000..7517456 --- /dev/null +++ b/extras/spiffs/mkspiffs/Makefile @@ -0,0 +1,37 @@ +# Check if SPIFFS_SIZE defined only if not cleaning +ifneq ($(MAKECMDGOALS),clean) +ifndef SPIFFS_SIZE +define ERROR_MSG +Variable SPIFFS_SIZE is not defined. +Cannot build mkspiffs without SPIFFS_SIZE. +Please specify it in your application Makefile. + +endef +$(error $(ERROR_MSG)) +endif +endif + +SOURCES := spiffs_hydrogen.c +SOURCES += spiffs_cache.c +SOURCES += spiffs_gc.c +SOURCES += spiffs_check.c +SOURCES += spiffs_nucleus.c +SOURCES += mkspiffs.c + +OBJECTS := $(SOURCES:.c=.o) + +VPATH = ../spiffs/src + +CFLAGS += -I.. +CFLAGS += -DSPIFFS_BASE_ADDR=0 # for image base addr is start of the image +CFLAGS += -DSPIFFS_SIZE=$(SPIFFS_SIZE) + +all: mkspiffs + +mkspiffs: $(OBJECTS) + +clean: + @rm -f mkspiffs + @rm -f *.o + +.PHONY: all clean diff --git a/extras/spiffs/mkspiffs/README.md b/extras/spiffs/mkspiffs/README.md new file mode 100644 index 0000000..5f6943d --- /dev/null +++ b/extras/spiffs/mkspiffs/README.md @@ -0,0 +1,34 @@ +# mkspiffs Create spiffs image + +mkspiffs is a command line utility to create an image of SPIFFS in order +to write to flash. + +## Usage + +mkspiffs will be built automatically if you include the following line in your +makefile: + +``` +$(eval $(call make_spiffs_image,files)) +``` + +where *files* is the directory with files that should go into SPIFFS image. + +Or you can build mkspiffs manually with: + +``` +make SPIFFS_SIZE=0x100000 +``` + +mkspiffs cannot be built without specifying SPIFFS size because it uses the +same SPIFFS sources as the firmware. And for the firmware SPIFFS size is +compile time defined. + +Please note that if you change SPIFFS_SIZE you need to rebuild mkspiffs. +The easiest way is to run `make clean` for you project. + +To manually generate SPIFFS image from directory, run: + +``` +mkspiffs DIRECTORY IMAGE_NAME +``` diff --git a/extras/spiffs/mkspiffs/mkspiffs.c b/extras/spiffs/mkspiffs/mkspiffs.c new file mode 100644 index 0000000..9f231a8 --- /dev/null +++ b/extras/spiffs/mkspiffs/mkspiffs.c @@ -0,0 +1,243 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 sheinz (https://github.com/sheinz) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "spiffs_config.h" +#include "../spiffs/src/spiffs.h" + +static spiffs fs; +static void *image = 0; +static void *work_buf = 0; +static void *fds_buf = 0; +static void *cache_buf = 0; + +static void print_usage(const char *prog_name, const char *error_msg) +{ + if (error_msg) { + printf("Error: %s\n", error_msg); + } + printf("Usage: "); + printf("\t%s DIRECTORY IMAGE_NAME\n\n", prog_name); + printf("Example:\n"); + printf("\t%s ./my_files spiffs.img\n\n", prog_name); +} + +static s32_t _read_data(u32_t addr, u32_t size, u8_t *dst) +{ + memcpy(dst, (uint8_t*)image + addr, size); + return SPIFFS_OK; +} + +static s32_t _write_data(u32_t addr, u32_t size, u8_t *src) +{ + memcpy((uint8_t*)image + addr, src, size); + return SPIFFS_OK; +} + +static s32_t _erase_data(u32_t addr, u32_t size) +{ + memset((uint8_t*)image + addr, 0xFF, size); + return SPIFFS_OK; +} + +static bool init_spiffs(bool allocate_mem) +{ + spiffs_config config = {0}; + printf("Initializing SPIFFS, size=%d\n", SPIFFS_SIZE); + + config.hal_read_f = _read_data; + config.hal_write_f = _write_data; + config.hal_erase_f = _erase_data; + + int workBufSize = 2 * SPIFFS_CFG_LOG_PAGE_SZ(); + int fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&fs, 5); + int cacheBufSize = SPIFFS_buffer_bytes_for_cache(&fs, 5); + + if (allocate_mem) { + image = malloc(SPIFFS_SIZE); + work_buf = malloc(workBufSize); + fds_buf = malloc(fdsBufSize); + cache_buf = malloc(cacheBufSize); + printf("spiffs memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", + workBufSize, fdsBufSize, cacheBufSize); + } + + int32_t err = SPIFFS_mount(&fs, &config, work_buf, fds_buf, fdsBufSize, + cache_buf, cacheBufSize, 0); + + if (err != SPIFFS_OK) { + printf("Error spiffs mount: %d\n", err); + return false; + } + + return true; +} + +static bool format_spiffs() +{ + SPIFFS_unmount(&fs); + + if (SPIFFS_format(&fs) == SPIFFS_OK) { + printf("Format complete\n"); + } else { + printf("Failed to format SPIFFS\n"); + return false; + } + + if (!init_spiffs(false)) { + printf("Failed to mount SPIFFS\n"); + return false; + } + return true; +} + +static void spiffs_free() +{ + free(image); + image = NULL; + + free(work_buf); + work_buf = NULL; + + free(fds_buf); + fds_buf = NULL; + + free(cache_buf); + cache_buf = NULL; +} + +static bool process_file(const char *src_file, const char *dst_file) +{ + int fd; + const int buf_size = 256; + uint8_t buf[buf_size]; + int data_len; + + fd = open(src_file, O_RDONLY); + if (fd < 0) { + printf("Error openning file: %s\n", src_file); + } + + spiffs_file out_fd = SPIFFS_open(&fs, dst_file, + SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); + while ((data_len = read(fd, buf, buf_size)) != 0) { + if (SPIFFS_write(&fs, out_fd, buf, data_len) != data_len) { + printf("Error writing to SPIFFS file\n"); + break; + } + } + SPIFFS_close(&fs, out_fd); + close(fd); + return true; +} + +static bool process_directory(const char *direcotry) +{ + DIR *dp; + struct dirent *ep; + char path[256]; + + dp = opendir(direcotry); + if (dp != NULL) { + while ((ep = readdir(dp)) != 0) { + if (!strcmp(ep->d_name, ".") || + !strcmp(ep->d_name, "..")) { + continue; + } + if (ep->d_type != DT_REG) { + continue; // not a regular file + } + sprintf(path, "%s/%s", direcotry, ep->d_name); + printf("Processing file %s\n", path); + if (!process_file(path, ep->d_name)) { + printf("Error processing file\n"); + break; + } + } + closedir(dp); + } else { + printf("Error reading direcotry: %s\n", direcotry); + } + return true; +} + +static bool write_image(const char *out_file) +{ + int fd; + int size = SPIFFS_SIZE; + uint8_t *p = (uint8_t*)image; + fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + printf("Error creating file %s\n", out_file); + return false; + } + + printf("Writing image to file: %s\n", out_file); + + while (size != 0) { + write(fd, p, SPIFFS_CFG_LOG_PAGE_SZ()); + p += SPIFFS_CFG_LOG_PAGE_SZ(); + size -= SPIFFS_CFG_LOG_PAGE_SZ(); + } + + close(fd); + return true; +} + +int main(int argc, char *argv[]) +{ + int result = 0; + + if (argc != 3) { + print_usage(argv[0], NULL); + return -1; + } + + if (init_spiffs(/*allocate_mem=*/true)) { + if (format_spiffs()) { + if (process_directory(argv[1])) { + if (!write_image(argv[2])) { + printf("Error writing image\n"); + } + } else { + printf("Error processing direcotry\n"); + } + } else { + printf("Error formating spiffs\n"); + } + } else { + printf("Error initialising SPIFFS\n"); + } + + spiffs_free(); + return result; +} From bfa20af8555719344db9b0a478445f4d218e5fec Mon Sep 17 00:00:00 2001 From: sheinz Date: Thu, 14 Jul 2016 15:44:02 +0300 Subject: [PATCH 20/26] Fix branch merging. Changes in esp_spiffs.c recovered. --- extras/spiffs/esp_spiffs.c | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index d6ec7d6..4b5ef77 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -9,6 +9,8 @@ #include "spiffs.h" #include #include +#include +#include spiffs fs; @@ -185,3 +187,69 @@ void esp_spiffs_unmount() fds_buf = 0; cache_buf = 0; } + +#define FD_OFFSET 3 + +// This implementation replaces implementation in core/newlib_syscals.c +long _write_r(struct _reent *r, int fd, const char *ptr, int len ) +{ + if(fd != r->_stdout->_file) { + long ret = SPIFFS_write(&fs, (spiffs_file)(fd - FD_OFFSET), + (char*)ptr, len); + return ret; + } + for(int i = 0; i < len; i++) { + /* Auto convert CR to CRLF, ignore other LFs (compatible with Espressif SDK behaviour) */ + if(ptr[i] == '\r') + continue; + if(ptr[i] == '\n') + uart_putc(0, '\r'); + uart_putc(0, ptr[i]); + } + return len; +} + +// This implementation replaces implementation in core/newlib_syscals.c +long _read_r( struct _reent *r, int fd, char *ptr, int len ) +{ + int ch, i; + + if(fd != r->_stdin->_file) { + long ret = SPIFFS_read(&fs, (spiffs_file)(fd - FD_OFFSET), ptr, len); + return ret; + } + uart_rxfifo_wait(0, 1); + for(i = 0; i < len; i++) { + ch = uart_getc_nowait(0); + if (ch < 0) break; + ptr[i] = ch; + } + return i; +} + +int _open_r(struct _reent *r, const char *pathname, int flags, int mode) +{ + uint32_t spiffs_flags = SPIFFS_RDONLY; + + if (flags & O_CREAT) spiffs_flags |= SPIFFS_CREAT; + if (flags & O_APPEND) spiffs_flags |= SPIFFS_APPEND; + if (flags & O_TRUNC) spiffs_flags |= SPIFFS_TRUNC; + if (flags & O_RDONLY) spiffs_flags |= SPIFFS_RDONLY; + if (flags & O_WRONLY) spiffs_flags |= SPIFFS_WRONLY; + + int ret = SPIFFS_open(&fs, pathname, spiffs_flags, mode); + if (ret > 0) { + return ret + FD_OFFSET; + } + return ret; +} + +int _close_r(struct _reent *r, int fd) +{ + return SPIFFS_close(&fs, (spiffs_file)(fd - FD_OFFSET)); +} + +int _unlink_r(struct _reent *r, const char *path) +{ + return SPIFFS_remove(&fs, path); +} From 22654a4de71a8a4411b2e217f51e88448f619c5c Mon Sep 17 00:00:00 2001 From: sheinz Date: Thu, 14 Jul 2016 16:13:03 +0300 Subject: [PATCH 21/26] SPIFFS: Support lseek, stat, fstat Support for lseek, stat, fstat added. Test extended to covert those functions. --- core/newlib_syscalls.c | 7 +++++-- examples/posix_fs/fs-test | 2 +- extras/spiffs/esp_spiffs.c | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c index c8104a9..577ecda 100644 --- a/core/newlib_syscalls.c +++ b/core/newlib_syscalls.c @@ -88,10 +88,13 @@ int _close_r(struct _reent *r, int fd); __attribute__((weak, alias("syscall_returns_enosys"))) int _unlink_r(struct _reent *r, const char *path); -__attribute__((alias("syscall_returns_enosys"))) +__attribute__((weak, alias("syscall_returns_enosys"))) int _fstat_r(struct _reent *r, int fd, void *buf); -__attribute__((alias("syscall_returns_enosys"))) +__attribute__((weak, alias("syscall_returns_enosys"))) +int _stat_r(struct _reent *r, const char *pathname, void *buf); + +__attribute__((weak, alias("syscall_returns_enosys"))) off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence); /* Generic stub for any newlib syscall that fails with errno ENOSYS diff --git a/examples/posix_fs/fs-test b/examples/posix_fs/fs-test index 218c523..12b1023 160000 --- a/examples/posix_fs/fs-test +++ b/examples/posix_fs/fs-test @@ -1 +1 @@ -Subproject commit 218c5235584429f407d619e5e35f90732ad505f3 +Subproject commit 12b10230cc56970857e6890bdd5663fbae74c4c3 diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index 4b5ef77..72419a1 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -253,3 +253,30 @@ int _unlink_r(struct _reent *r, const char *path) { return SPIFFS_remove(&fs, path); } + +int _fstat_r(struct _reent *r, int fd, void *buf) +{ + spiffs_stat s; + struct stat *sb = (struct stat*)buf; + + int result = SPIFFS_fstat(&fs, (spiffs_file)(fd - FD_OFFSET), &s); + sb->st_size = s.size; + + return result; +} + +int _stat_r(struct _reent *r, const char *pathname, void *buf) +{ + spiffs_stat s; + struct stat *sb = (struct stat*)buf; + + int result = SPIFFS_stat(&fs, pathname, &s); + sb->st_size = s.size; + + return result; +} + +off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence) +{ + return SPIFFS_lseek(&fs, (spiffs_file)(fd - FD_OFFSET), offset, whence); +} From 1db953e0c3e096f9e7ff442f6c50dece002df6e1 Mon Sep 17 00:00:00 2001 From: sheinz Date: Fri, 15 Jul 2016 00:08:34 +0300 Subject: [PATCH 22/26] SPIFFS: Add speed test. --- examples/posix_fs/fs-test | 2 +- examples/posix_fs/posix_fs_example.c | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/examples/posix_fs/fs-test b/examples/posix_fs/fs-test index 12b1023..2ad547a 160000 --- a/examples/posix_fs/fs-test +++ b/examples/posix_fs/fs-test @@ -1 +1 @@ -Subproject commit 12b10230cc56970857e6890bdd5663fbae74c4c3 +Subproject commit 2ad547adc5f725594b3c6752f036ff4401b221fc diff --git a/examples/posix_fs/posix_fs_example.c b/examples/posix_fs/posix_fs_example.c index d84be5e..4525be3 100644 --- a/examples/posix_fs/posix_fs_example.c +++ b/examples/posix_fs/posix_fs_example.c @@ -1,5 +1,6 @@ #include "espressif/esp_common.h" #include "esp/uart.h" +#include "esp/timer.h" #include "FreeRTOS.h" #include "task.h" #include "esp8266.h" @@ -10,6 +11,10 @@ #include "fs-test/fs_test.h" +static fs_time_t get_current_time() +{ + return timer_get_count(FRC2) / 5000; // to get roughly 1ms resolution +} void test_task(void *pvParameters) { @@ -24,12 +29,20 @@ void test_task(void *pvParameters) while (1) { vTaskDelay(5000 / portTICK_RATE_MS); - - if (fs_test_run(1000)) { + if (fs_load_test_run(100)) { printf("PASS\n"); } else { printf("FAIL\n"); } + + vTaskDelay(5000 / portTICK_RATE_MS); + float write_rate, read_rate; + if (fs_speed_test_run(get_current_time, &write_rate, &read_rate)) { + printf("Read speed: %.0f bytes/s\n", read_rate * 1000); + printf("Write speed: %.0f bytes/s\n", write_rate * 1000); + } else { + printf("FAIL\n"); + } } } From df796947bdfe3b452d93700fd68cf870f2d66f0a Mon Sep 17 00:00:00 2001 From: sheinz Date: Fri, 15 Jul 2016 00:41:29 +0300 Subject: [PATCH 23/26] SPIFFS: Update README.md --- examples/posix_fs/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 examples/posix_fs/README.md diff --git a/examples/posix_fs/README.md b/examples/posix_fs/README.md new file mode 100644 index 0000000..7f05bd4 --- /dev/null +++ b/examples/posix_fs/README.md @@ -0,0 +1,10 @@ +# POSIX file access example + +This example runs several file system tests on ESP8266. +It uses fs-test library to perform file operations test. fs-test library uses +only POSIX file functions so can be run on host system as well. + +Currently included tests: + * File system load test. Perform multiple file operations in random order. + * File system speed test. Measures files read/write speed. + From 66610c56cb03398c9af035ba57f0f19368f56de4 Mon Sep 17 00:00:00 2001 From: sheinz Date: Fri, 15 Jul 2016 01:21:32 +0300 Subject: [PATCH 24/26] SPIFFS: Improve SPIFFS image build Rebuild SPIFFS image if files change. Rebuild mkspiffs if SPIFFS_SIZE is changed in Makefile. --- extras/spiffs/component.mk | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/extras/spiffs/component.mk b/extras/spiffs/component.mk index cf0a5a0..b0b34c1 100644 --- a/extras/spiffs/component.mk +++ b/extras/spiffs/component.mk @@ -20,26 +20,29 @@ spiffs_CFLAGS += -DSPIFFS_SIZE=$(SPIFFS_SIZE) # # Argumens: # $(1) - directory with files which go into spiffs image -# +# # Example: # $(eval $(call make_spiffs_image,files)) define make_spiffs_image SPIFFS_IMAGE = $(addprefix $(FIRMWARE_DIR),spiffs.bin) MKSPIFFS_DIR = $(ROOT)/extras/spiffs/mkspiffs MKSPIFFS = $$(MKSPIFFS_DIR)/mkspiffs +SPIFFS_FILE_LIST = $(shell find $(1)) all: $$(SPIFFS_IMAGE) clean: clean_spiffs_img clean_mkspiffs -$$(SPIFFS_IMAGE): $$(MKSPIFFS) $(1) +$$(SPIFFS_IMAGE): $$(MKSPIFFS) $$(SPIFFS_FILE_LIST) $$< $(1) $$@ -$$(MKSPIFFS): +# if SPIFFS_SIZE in Makefile is changed rebuild mkspiffs +$$(MKSPIFFS): Makefile + $$(MAKE) -C $$(MKSPIFFS_DIR) clean $$(MAKE) -C $$(MKSPIFFS_DIR) SPIFFS_SIZE=$(SPIFFS_SIZE) clean_spiffs_img: - $$(Q) rm -f spiffs.img + $$(Q) rm -f $$(SPIFFS_IMAGE) clean_mkspiffs: $$(Q) $$(MAKE) -C $$(MKSPIFFS_DIR) clean From 924860a78f389a8ff4c912d3eb8f6e5181d1059c Mon Sep 17 00:00:00 2001 From: sheinz Date: Fri, 15 Jul 2016 15:22:03 +0300 Subject: [PATCH 25/26] SPIFFS: Update example, README.md Separate method to initialize SPIFFS memory buffers. REDME.md for spiffs component. Simplify spiffs example. --- examples/posix_fs/posix_fs_example.c | 3 +- examples/spiffs/Makefile | 2 +- examples/spiffs/spiffs_example.c | 194 ++++++++------------------- extras/spiffs/README.md | 153 +++++++++++++++++++++ extras/spiffs/esp_spiffs.c | 71 ++++++---- extras/spiffs/esp_spiffs.h | 25 +++- 6 files changed, 277 insertions(+), 171 deletions(-) create mode 100644 extras/spiffs/README.md diff --git a/examples/posix_fs/posix_fs_example.c b/examples/posix_fs/posix_fs_example.c index 4525be3..2f5ad14 100644 --- a/examples/posix_fs/posix_fs_example.c +++ b/examples/posix_fs/posix_fs_example.c @@ -18,8 +18,9 @@ static fs_time_t get_current_time() void test_task(void *pvParameters) { + esp_spiffs_init(); esp_spiffs_mount(); - esp_spiffs_unmount(); // FS must be unmounted before formating + SPIFFS_unmount(&fs); // FS must be unmounted before formating if (SPIFFS_format(&fs) == SPIFFS_OK) { printf("Format complete\n"); } else { diff --git a/examples/spiffs/Makefile b/examples/spiffs/Makefile index b0be23f..7327707 100644 --- a/examples/spiffs/Makefile +++ b/examples/spiffs/Makefile @@ -4,7 +4,7 @@ FLASH_SIZE = 32 # spiffs configuration SPIFFS_BASE_ADDR = 0x200000 -SPIFFS_SIZE = 0x100000 +SPIFFS_SIZE = 0x010000 include ../../common.mk diff --git a/examples/spiffs/spiffs_example.c b/examples/spiffs/spiffs_example.c index 226ee51..98decaf 100644 --- a/examples/spiffs/spiffs_example.c +++ b/examples/spiffs/spiffs_example.c @@ -4,171 +4,95 @@ #include "task.h" #include "esp8266.h" +#include "fcntl.h" +#include "unistd.h" + #include "spiffs.h" #include "esp_spiffs.h" -#define TEST_FILE_NAME_LEN 16 -#define TEST_FILES 32 -#define TEST_FILE_MAX_SIZE 8192 - -typedef struct { - char name[TEST_FILE_NAME_LEN]; - uint16_t size; - uint8_t first_data_byte; -} TestFile; - -static TestFile test_files[TEST_FILES]; - -inline static void fill_test_data(uint8_t *src, uint16_t size, uint8_t first_byte) +static void example_read_file_posix() { - while (size--) { - *src++ = first_byte++; - } -} + const int buf_size = 0xFF; + uint8_t buf[buf_size]; -static bool write_test_files() -{ - uint8_t *buf = (uint8_t*)malloc(TEST_FILE_MAX_SIZE); - bool result = true; - - for (uint8_t i = 0; i < TEST_FILES; i++) { - sprintf(test_files[i].name, "file_%d.dat", i); - spiffs_file f = SPIFFS_open(&fs, test_files[i].name, - SPIFFS_CREAT|SPIFFS_RDWR|SPIFFS_TRUNC, 0); - if (f < 0) { - printf("Open file operation failed\n"); - result = false; - break; - } - test_files[i].size = rand() % TEST_FILE_MAX_SIZE; - test_files[i].first_data_byte = rand() % 256; - fill_test_data(buf, test_files[i].size, test_files[i].first_data_byte); - - printf("Writing file %s size=%d\n", test_files[i].name, - test_files[i].size); - int32_t written = SPIFFS_write(&fs, f, buf, test_files[i].size); - if (written != test_files[i].size) { - printf("Write file operation failed, written=%d\n", written); - result = false; - break; - } - SPIFFS_close(&fs, f); - } - free(buf); - return result; -} - -inline static bool verify_test_data(uint8_t *data, uint16_t size, - uint8_t first_byte) -{ - while (size--) { - if (*data++ != first_byte++) { - return false; - } - } - return true; -} - -static bool verify_test_files() -{ - uint8_t *buf = (uint8_t*)malloc(TEST_FILE_MAX_SIZE); - bool result = true; - - for (uint8_t i = 0; i < TEST_FILES; i++) { - printf("Verifying file %s\n", test_files[i].name); - spiffs_file f = SPIFFS_open(&fs, test_files[i].name, SPIFFS_RDONLY, 0); - if (f < 0) { - printf("Open file operation failed\n"); - result = false; - break; - } - - int32_t n = SPIFFS_read(&fs, f, buf, test_files[i].size); - if (n != test_files[i].size) { - printf("Read file operation failed\n"); - result = false; - break; - } - - if (!verify_test_data(buf, test_files[i].size, - test_files[i].first_data_byte)) { - printf("Data verification failed\n"); - result = false; - break; - } - - SPIFFS_close(&fs, f); + int fd = open("test.txt", O_RDONLY); + if (fd < 0) { + printf("Error opening file\n"); + return; } - free(buf); - return result; + int read_bytes = read(fd, buf, buf_size); + printf("Read %d bytes\n", read_bytes); + + buf[read_bytes] = '\0'; // zero terminate string + printf("Data: %s\n", buf); + + close(fd); } -static bool cleanup_test_files() +static void example_read_file_spiffs() { - bool result = true; + const int buf_size = 0xFF; + uint8_t buf[buf_size]; - for (uint8_t i = 0; i < TEST_FILES; i++) { - printf("Removing file %s\n", test_files[i].name); - if (SPIFFS_remove(&fs, test_files[i].name) != SPIFFS_OK) { - printf("Remove file operation failed\n"); - result = false; - break; - } + spiffs_file fd = SPIFFS_open(&fs, "other.txt", SPIFFS_RDONLY, 0); + if (fd < 0) { + printf("Error opening file\n"); + return; } - return result; + + int read_bytes = SPIFFS_read(&fs, fd, buf, buf_size); + printf("Read %d bytes\n", read_bytes); + + buf[read_bytes] = '\0'; // zero terminate string + printf("Data: %s\n", buf); + + SPIFFS_close(&fs, fd); } -inline static void print_info() +static void example_write_file() +{ + uint8_t buf[] = "Example data, written by ESP8266"; + + int fd = open("other.txt", O_WRONLY|O_CREAT, 0); + if (fd < 0) { + printf("Error opening file\n"); + return; + } + + int written = write(fd, buf, sizeof(buf)); + printf("Written %d bytes\n", written); + + close(fd); +} + +static void example_fs_info() { uint32_t total, used; - SPIFFS_info(&fs, &total, &used); - - printf("FS total=%d bytes, used=%d bytes\n", total, used); - printf("FS %d %% used\n", 100 * used/total); - - // File system structure visualisation - // SPIFFS_vis(&fs); + printf("Total: %d bytes, used: %d bytes", total, used); } void test_task(void *pvParameters) { - bool result = true; - - esp_spiffs_mount(); - esp_spiffs_unmount(); // FS must be unmounted before formating - if (SPIFFS_format(&fs) == SPIFFS_OK) { - printf("Format complete\n"); - } else { - printf("Format failed\n"); + esp_spiffs_init(); + if (esp_spiffs_mount() != SPIFFS_OK) { + printf("Error mount SPIFFS\n"); } - esp_spiffs_mount(); while (1) { - vTaskDelay(5000 / portTICK_RATE_MS); + vTaskDelay(2000 / portTICK_RATE_MS); - result = write_test_files(); + example_write_file(); - if (result) { - result = verify_test_files(); - } + example_read_file_posix(); - print_info(); + example_read_file_spiffs(); - if (result) { - result = cleanup_test_files(); - } + example_fs_info(); - if (result) { - printf("Test passed!\n"); - } else { - printf("Test failed!\n"); - while (1) { - vTaskDelay(1); - } - } + printf("\n\n"); } } diff --git a/extras/spiffs/README.md b/extras/spiffs/README.md new file mode 100644 index 0000000..76d2081 --- /dev/null +++ b/extras/spiffs/README.md @@ -0,0 +1,153 @@ +# SPIFFS ESP8266 File system + +This component adds file system support for ESP8266. File system of choice +for ESP8266 is [SPIFFS](https://github.com/pellepl/spiffs). +It was specifically designed to use with SPI NOR flash on embedded systems. +The main advantage of SPIFFS is wear leveling, which prolongs life time +of a flash memory. + +## Features + + * SPIFFS - embedded file system for NOR flash memory. + * POSIX file operations. + * Static files upload to ESP8266 file system within build process. + * SPIFFS singleton configuration. Only one instance of FS on a device. + +## Usage + +In order to use file system in a project the following steps should be made: + * Add SPIFFS component in a project Makefile `EXTRA_COMPONENTS = extras/spiffs` + * Specify your flash size in the Makefile `FLASH_SIZE = 32` + * Specify the start address of file system region on the flash memory +`SPIFFS_BASE_ADDR = 0x200000` + * If you want to upload files to a file system during flash process specify +the directory with files `$(eval $(call make_spiffs_image,files))` + +In the end the Makefile should look like: + +``` +PROGRAM=spiffs_example +EXTRA_COMPONENTS = extras/spiffs +FLASH_SIZE = 32 + +SPIFFS_BASE_ADDR = 0x200000 +SPIFFS_SIZE = 0x100000 + +include ../../common.mk + +$(eval $(call make_spiffs_image,files)) +``` + +Note: Macro call to prepare SPIFFS image for flashing should go after +`include common.mk` + +### Files upload + +To upload files to a file system during flash process the following macro is +used: + +``` +$(eval $(call make_spiffs_image,files)) +``` + +It enables the build of a helper utility **mkspiffs**. This utility creates +an SPIFFS image with files in the specified directory. + +The SPIFFS image is created during build stage, after `make` is run. +The image is flashed into the device along with firmware during flash stage, +after `make flash` is run. + +**mkspiffs** utility uses the same SPIFFS source code and the same +configuration as ESP8266. So the created image should always be compatible +with SPIFFS on a device. + +The build process will catch any changes in files directory and rebuild the +image each time `make` is run. +The build process will handle SPIFFS_SIZE change and rebuild **mkspiffs** +utility and the image. + +## Example + +### Mount + +``` +esp_spiffs_init(); // allocate memory buffers +if (esp_spiffs_mount() != SPIFFS_OK) { + printf("Error mounting SPIFFS\n"); +} +``` + +### Format + +Formatting SPIFFS is a little bit awkward. Before formatting SPIFFS must be +mounted and unmounted. +``` +esp_spiffs_init(); +if (esp_spiffs_mount() != SPIFFS_OK) { + printf("Error mount SPIFFS\n"); +} +SPIFFS_unmount(&fs); // FS must be unmounted before formating +if (SPIFFS_format(&fs) == SPIFFS_OK) { + printf("Format complete\n"); +} else { + printf("Format failed\n"); +} +esp_spiffs_mount(); +``` + +### POSIX read + +Nothing special here. + +``` +const int buf_size = 0xFF; +uint8_t buf[buf_size]; + +int fd = open("test.txt", O_RDONLY); +if (fd < 0) { + printf("Error opening file\n"); +} + +read(fd, buf, buf_size); +printf("Data: %s\n", buf); + +close(fd); +``` + +### SPIFFS read + +SPIFFS interface is intended to be as close to POSIX as possible. + +``` +const int buf_size = 0xFF; +uint8_t buf[buf_size]; + +spiffs_file fd = SPIFFS_open(&fs, "other.txt", SPIFFS_RDONLY, 0); +if (fd < 0) { + printf("Error opening file\n"); +} + +SPIFFS_read(&fs, fd, buf, buf_size); +printf("Data: %s\n", buf); + +SPIFFS_close(&fs, fd); +``` + +### POSIX write + +``` +uint8_t buf[] = "Example data, written by ESP8266"; + +int fd = open("other.txt", O_WRONLY|O_CREAT, 0); +if (fd < 0) { + printf("Error opening file\n"); +} + +write(fd, buf, sizeof(buf)); + +close(fd); +``` + +## Resources + +[SPIFFS](https://github.com/pellepl/spiffs) diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index 72419a1..11a84d5 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -14,9 +14,21 @@ spiffs fs; -static void *work_buf = 0; -static void *fds_buf = 0; -static void *cache_buf = 0; +typedef struct { + void *buf; + uint32_t size; +} fs_buf_t; + +static fs_buf_t work_buf = {0}; +static fs_buf_t fds_buf = {0}; +static fs_buf_t cache_buf = {0}; + +/** + * Number of file descriptors opened at the same time + */ +#define ESP_SPIFFS_FD_NUMBER 5 + +#define ESP_SPIFFS_CACHE_PAGES 5 /* * Flash addresses and size alignment is a rip-off of Arduino implementation. @@ -147,6 +159,29 @@ static s32_t esp_spiffs_erase(u32_t addr, u32_t size) return SPIFFS_OK; } +void esp_spiffs_init() +{ + work_buf.size = 2 * SPIFFS_CFG_LOG_PAGE_SZ(); + fds_buf.size = SPIFFS_buffer_bytes_for_filedescs(&fs, ESP_SPIFFS_FD_NUMBER); + cache_buf.size= SPIFFS_buffer_bytes_for_cache(&fs, ESP_SPIFFS_CACHE_PAGES); + + work_buf.buf = malloc(work_buf.size); + fds_buf.buf = malloc(fds_buf.size); + cache_buf.buf = malloc(cache_buf.size); +} + +void esp_spiffs_deinit() +{ + free(work_buf.buf); + work_buf.buf = 0; + + free(fds_buf.buf); + fds_buf.buf = 0; + + free(cache_buf.buf); + cache_buf.buf = 0; +} + int32_t esp_spiffs_mount() { spiffs_config config = {0}; @@ -155,18 +190,13 @@ int32_t esp_spiffs_mount() config.hal_write_f = esp_spiffs_write; config.hal_erase_f = esp_spiffs_erase; - size_t workBufSize = 2 * SPIFFS_CFG_LOG_PAGE_SZ(); - size_t fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&fs, 5); - size_t cacheBufSize = SPIFFS_buffer_bytes_for_cache(&fs, 5); + printf("SPIFFS size: %d\n", SPIFFS_SIZE); + printf("SPIFFS memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", + work_buf.size, fds_buf.size, cache_buf.size); - work_buf = malloc(workBufSize); - fds_buf = malloc(fdsBufSize); - cache_buf = malloc(cacheBufSize); - printf("spiffs memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", - workBufSize, fdsBufSize, cacheBufSize); - - int32_t err = SPIFFS_mount(&fs, &config, work_buf, fds_buf, fdsBufSize, - cache_buf, cacheBufSize, 0); + int32_t err = SPIFFS_mount(&fs, &config, (uint8_t*)work_buf.buf, + (uint8_t*)fds_buf.buf, fds_buf.size, + cache_buf.buf, cache_buf.size, 0); if (err != SPIFFS_OK) { printf("Error spiffs mount: %d\n", err); @@ -175,19 +205,6 @@ int32_t esp_spiffs_mount() return err; } -void esp_spiffs_unmount() -{ - SPIFFS_unmount(&fs); - - free(work_buf); - free(fds_buf); - free(cache_buf); - - work_buf = 0; - fds_buf = 0; - cache_buf = 0; -} - #define FD_OFFSET 3 // This implementation replaces implementation in core/newlib_syscals.c diff --git a/extras/spiffs/esp_spiffs.h b/extras/spiffs/esp_spiffs.h index 3022d51..f074017 100644 --- a/extras/spiffs/esp_spiffs.h +++ b/extras/spiffs/esp_spiffs.h @@ -13,16 +13,27 @@ extern spiffs fs; /** - * Provide SPIFFS with all necessary configuration, allocate memory buffers - * and mount SPIFFS. + * Prepare for SPIFFS mount. + * + * The function allocates all the necessary buffers. + */ +void esp_spiffs_init(); + +/** + * Free all memory buffers that were used by SPIFFS. + * + * The function should be called after SPIFFS unmount if the file system is not + * going to need any more. + */ +void esp_spiffs_deinit(); + +/** + * Mount SPIFFS. + * + * esp_spiffs_init must be called first. * * Return SPIFFS return code. */ int32_t esp_spiffs_mount(); -/** - * Unmount SPIFFS and free all allocated buffers. - */ -void esp_spiffs_unmount(); - #endif // __ESP_SPIFFS_H__ From 55b7d29767bc78f6575ecc41ab4537adbbe66bc8 Mon Sep 17 00:00:00 2001 From: sheinz Date: Fri, 15 Jul 2016 15:44:22 +0300 Subject: [PATCH 26/26] SPIFFS: Fix SPIFFS rebuild if SIZE is changed. --- extras/spiffs/component.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extras/spiffs/component.mk b/extras/spiffs/component.mk index b0b34c1..a0a8928 100644 --- a/extras/spiffs/component.mk +++ b/extras/spiffs/component.mk @@ -36,6 +36,10 @@ clean: clean_spiffs_img clean_mkspiffs $$(SPIFFS_IMAGE): $$(MKSPIFFS) $$(SPIFFS_FILE_LIST) $$< $(1) $$@ +# Rebuild SPIFFS if Makefile is changed, where SPIFF_SIZE is defined +$$(spiffs_ROOT)spiffs_config.h: Makefile + $$(Q) touch $$@ + # if SPIFFS_SIZE in Makefile is changed rebuild mkspiffs $$(MKSPIFFS): Makefile $$(MAKE) -C $$(MKSPIFFS_DIR) clean