user_main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /******************************************************************************
  2. * Copyright 2013-2014 Espressif Systems (Wuxi)
  3. *
  4. * FileName: user_main.c
  5. *
  6. * Description: entry file of user application
  7. *
  8. * Modification history:
  9. * 2014/1/1, v1.0 create this file.
  10. *******************************************************************************/
  11. #include "lua.h"
  12. #include "platform.h"
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include "vfs.h"
  17. #include "flash_api.h"
  18. #include "user_interface.h"
  19. #include "user_modules.h"
  20. #include "ets_sys.h"
  21. #include "driver/uart.h"
  22. #include "driver/input.h"
  23. #include "task/task.h"
  24. #include "mem.h"
  25. #include "espconn.h"
  26. #include "sections.h"
  27. #ifdef LUA_USE_MODULES_RTCTIME
  28. #include "rtc/rtctime.h"
  29. #endif
  30. extern int lua_main (void);
  31. /* Contents of esp_init_data_default.bin */
  32. extern const uint32_t init_data[], init_data_end[];
  33. #define INIT_DATA_SIZE ((init_data_end - init_data)*sizeof(uint32_t))
  34. __asm__(
  35. ".align 4\n"
  36. "init_data: .incbin \"" ESP_INIT_DATA_DEFAULT "\"\n"
  37. "init_data_end:\n"
  38. );
  39. extern const char _irom0_text_start[], _irom0_text_end[], _flash_used_end[];
  40. #define IROM0_SIZE (_irom0_text_end - _irom0_text_start)
  41. #define PRE_INIT_TEXT_ATTR __attribute__((section(".p3.pre_init")))
  42. #define IROM_PTABLE_ATTR __attribute__((section(".irom0.ptable")))
  43. #define USED_ATTR __attribute__((used))
  44. #define PARTITION(n) (SYSTEM_PARTITION_CUSTOMER_BEGIN + n)
  45. #define SIZE_256K 0x00040000
  46. #define SIZE_1024K 0x00100000
  47. #define PT_CHUNK 0x00002000
  48. #define PT_ALIGN(n) ((n + (PT_CHUNK-1)) & (~((PT_CHUNK-1))))
  49. #define FLASH_BASE_ADDR ((char *) 0x40200000)
  50. #define NODEMCU_PARTITION_EAGLEROM PLATFORM_PARTITION(NODEMCU_EAGLEROM_PARTITION)
  51. #define NODEMCU_PARTITION_IROM0TEXT PLATFORM_PARTITION(NODEMCU_IROM0TEXT_PARTITION)
  52. #define NODEMCU_PARTITION_LFS PLATFORM_PARTITION(NODEMCU_LFS0_PARTITION)
  53. #define NODEMCU_PARTITION_SPIFFS PLATFORM_PARTITION(NODEMCU_SPIFFS0_PARTITION)
  54. #define RF_CAL_SIZE 0x1000
  55. #define PHY_DATA_SIZE 0x1000
  56. #define SYSTEM_PARAMETER_SIZE 0x3000
  57. #define MAX_PARTITIONS 20
  58. #define WORDSIZE sizeof(uint32_t)
  59. #define PTABLE_SIZE 7 /** THIS MUST BE MATCHED TO NO OF PT ENTRIES BELOW **/
  60. struct defaultpt {
  61. platform_rcr_t hdr;
  62. partition_item_t pt[PTABLE_SIZE+1]; // the +! is for the endmarker
  63. };
  64. #define PT_LEN (NUM_PARTITIONS*sizeof(partition_item_t))
  65. /*
  66. * See app/platform/platform.h for how the platform reboot config records are used
  67. * and these records are allocated. The first record is a default partition table
  68. * and this is statically declared in compilation below.
  69. */
  70. static const struct defaultpt rompt IROM_PTABLE_ATTR USED_ATTR = {
  71. .hdr = {.len = sizeof(struct defaultpt)/WORDSIZE - 1,
  72. .id = PLATFORM_RCR_PT},
  73. .pt = {
  74. { NODEMCU_PARTITION_EAGLEROM, 0x00000, 0x0B000},
  75. { SYSTEM_PARTITION_RF_CAL, 0x0D000, RF_CAL_SIZE},
  76. { SYSTEM_PARTITION_PHY_DATA, 0x0F000, PHY_DATA_SIZE},
  77. { NODEMCU_PARTITION_IROM0TEXT, 0x10000, 0x0000},
  78. { NODEMCU_PARTITION_LFS, 0x0, LUA_FLASH_STORE},
  79. { NODEMCU_PARTITION_SPIFFS, 0x0, SPIFFS_MAX_FILESYSTEM_SIZE},
  80. { SYSTEM_PARTITION_SYSTEM_PARAMETER, 0x0, SYSTEM_PARAMETER_SIZE},
  81. {0,(uint32_t) &_irom0_text_end,0}
  82. }
  83. };
  84. //TODO: map the TLS server and client certs into NODEMCU_TLSCERT_PARTITION
  85. static uint32_t first_time_setup(partition_item_t *pt, uint32_t n, uint32_t flash_size);
  86. static void phy_data_setup (partition_item_t *pt, uint32_t n);
  87. extern void _ResetHandler(void);
  88. /*
  89. * The non-OS SDK prolog has been fundamentally revised in V3. See SDK EN document
  90. * Partition Table.md for further discussion. This version of user_main.c is a
  91. * complete rework aligned to V3, with the redundant pre-V3 features removed.
  92. *
  93. * SDK V3 significantly reduces the RAM footprint required by the SDK and introduces
  94. * the use of a partition table (PT) to control flash allocation. The NodeMCU uses
  95. * this PT for overall allocation of its flash resources. The non_OS SDK calls the
  96. * user_pre_init() entry to do all of this startup configuration. Note that this
  97. * runs with Icache enabled -- that is the IROM0 partition is already mapped to the
  98. * address space at 0x40210000 and so that most SDK services are available, such
  99. * as system_get_flash_size_map() which returns the valid flash size (including the
  100. * 8Mb and 16Mb variants).
  101. *
  102. * The first 4K page of IROM0 (flash offset 0x10000) is used to maintain a set of
  103. * Resource Communication Records (RCR) for inter-boot configuration using a NAND
  104. * write-once algo (see app/platform/platform.h). One of the current records is the
  105. * SDK3.0 PT. This build statically compiles in an initial version at the start of
  106. * the PT, with a {0, _irom0_text_end,0} marker as the last record and some fields
  107. * also that need to be recomputed at runtime. This version is either replaced
  108. * by first boot processing after provisioning, or by a node.setpartitiontable()
  109. * API call. These replacement PTs are complete and can be passed directly for use
  110. * by the non-OS SDK.
  111. *
  112. * Note that we have released a host PC-base python tool, nodemcu-partition.py, to
  113. * configure the PT, etc during provisioning.
  114. */
  115. void user_pre_init(void) {
  116. STARTUP_COUNT;
  117. #ifdef LUA_USE_MODULES_RTCTIME
  118. // Note: Keep this as close to call_user_start() as possible, since it
  119. // is where the cpu clock actually gets bumped to 80MHz.
  120. rtctime_early_startup ();
  121. #endif
  122. int startup_option = platform_rcr_get_startup_option();
  123. if (startup_option & STARTUP_OPTION_CPU_FREQ_MAX) {
  124. REG_SET_BIT(0x3ff00014, BIT(0));
  125. ets_update_cpu_frequency(SYS_CPU_160MHZ);
  126. }
  127. int no_banner = startup_option & STARTUP_OPTION_NO_BANNER;
  128. partition_item_t *rcr_pt = NULL, *pt;
  129. enum flash_size_map fs_size_code = system_get_flash_size_map();
  130. // Flash size lookup is SIZE_256K*2^N where N is as follows (see SDK/user_interface.h)
  131. /* 0 1 2 3 4 5 6 7 8 9 */
  132. /* ½M ¼M 1M 2M 4M 2M 4M 4M 8M 16M */
  133. static char flash_size_scaler[] = "\001\000\002\003\004\003\004\004\005\006";
  134. uint32_t flash_size = SIZE_256K << flash_size_scaler[fs_size_code];
  135. uint32_t i = platform_rcr_read(PLATFORM_RCR_PT, (void **) &rcr_pt);
  136. uint32_t n = i / sizeof(partition_item_t);
  137. if (flash_size < SIZE_1024K) {
  138. os_printf("Flash size (%u) too small to support NodeMCU\n", flash_size);
  139. return;
  140. } else {
  141. if (!no_banner) {
  142. os_printf("system SPI FI size:%u, Flash size: %u\n", fs_size_code, flash_size );
  143. }
  144. }
  145. pt = os_malloc_iram(i); // We will work on and register a copy of the PT in iRAM
  146. // Return if anything is amiss; The SDK will halt if the PT hasn't been registered
  147. if ( !rcr_pt || !pt || n * sizeof(partition_item_t) != i) {
  148. return;
  149. }
  150. os_memcpy(pt, rcr_pt, i);
  151. if (pt[n-1].type == 0) {
  152. // If the last PT entry is a {0,XX,0} end marker, then we need first time setup
  153. n = first_time_setup(pt, n-1, flash_size); // return n because setup might shrink the PT
  154. }
  155. if (platform_rcr_read(PLATFORM_RCR_PHY_DATA, NULL)!=0) {
  156. phy_data_setup(pt, n);
  157. }
  158. // Now register the partition and return
  159. if( fs_size_code > 1 && system_partition_table_regist(pt, n, fs_size_code)) {
  160. if (no_banner) {
  161. system_set_os_print(0);
  162. }
  163. STARTUP_COUNT;
  164. return;
  165. }
  166. os_printf("Invalid system partition table\n");
  167. while (1) {};
  168. }
  169. /*
  170. * If the PLATFORM_RCR_PT record doesn't exist then the PHY_DATA partition might
  171. * not have been initialised. This must be set to the proper default init data
  172. * otherwise the SDK will halt on the "rf_cal[0] !=0x05,is 0xFF" error.
  173. */
  174. static void phy_data_setup (partition_item_t *pt, uint32_t n) {
  175. uint8_t header[sizeof(uint32_t)] = {0};
  176. int i;
  177. for (i = 0; i < n; i++) {
  178. if (pt[i].type == SYSTEM_PARTITION_PHY_DATA) {
  179. uint32_t addr = pt[i].addr;
  180. platform_s_flash_read(header, addr, sizeof(header));
  181. if (header[0] != 0x05) {
  182. uint32_t sector = pt[i].addr/INTERNAL_FLASH_SECTOR_SIZE;
  183. if (platform_flash_erase_sector(sector) == PLATFORM_OK) {
  184. os_printf("Writing Init Data to 0x%08x\n",addr);
  185. platform_s_flash_write(init_data, addr, INIT_DATA_SIZE);
  186. }
  187. }
  188. // flag setup complete so we don't retry this every boot
  189. platform_rcr_write(PLATFORM_RCR_PHY_DATA, &addr, 0);
  190. return;
  191. }
  192. }
  193. // If the PHY_DATA doesn't exist or the write fails then the
  194. // SDK will raise the rf_cal error anyway, so just return.
  195. }
  196. /*
  197. * First time setup does the one-off PT calculations and checks. If these are OK,
  198. * then writes back a new RCR for the updated PT and triggers a reboot. It returns
  199. * on failure.
  200. */
  201. static uint32_t first_time_setup(partition_item_t *pt, uint32_t n, uint32_t flash_size) {
  202. int i, j, last = 0, newn = n;
  203. /*
  204. * Scan down the PT adjusting and 0 entries to sensible defaults. Also delete any
  205. * zero-sized partitions (as the SDK barfs on these).
  206. */
  207. for (i = 0, j = 0; i < n; i ++) {
  208. partition_item_t *p = pt + i;
  209. switch (p->type) {
  210. case NODEMCU_PARTITION_IROM0TEXT:
  211. // If the IROM0 partition size is 0 then compute from the IROM0_SIZE. Note
  212. // that the size in the end-marker is used by the nodemcu-partition.py
  213. // script and not here.
  214. if (p->size == 0) {
  215. p->size = PT_ALIGN(IROM0_SIZE);
  216. }
  217. break;
  218. case NODEMCU_PARTITION_LFS:
  219. // Properly align the LFS partition size and make it consecutive to
  220. // the previous partition.
  221. p->size = PT_ALIGN(p->size);
  222. if (p->addr == 0)
  223. p->addr = last;
  224. break;
  225. /*
  226. * Set up the SPIFFS partition based on some sensible defaults:
  227. * size == 0 mean no SPIFFS partition.
  228. * size == ~0 means use all of the available flash for SPIFFS (resp the addr if set).
  229. * if size > 0 then float the default boundary to 1M if the SPIFFS will fit.
  230. */
  231. case NODEMCU_PARTITION_SPIFFS:
  232. if (p->size == ~0x0) { /* Maximum SPIFFS partition */
  233. if (p->addr == 0)
  234. p->addr = last;
  235. p->size = flash_size - SYSTEM_PARAMETER_SIZE - last;
  236. } else if (p->size > 0x0) { /* Explicit SPIFFS size */
  237. if (p->addr < last) // SPIFFS can't overlap the previous region;
  238. p->addr = 0;
  239. if (p->addr == 0)
  240. p->addr = (p->size <= flash_size - SYSTEM_PARAMETER_SIZE - 0x100000) ?
  241. 0x100000 : last;
  242. }
  243. /* else p->size == 0 No SPIFFS partition */
  244. break;
  245. case SYSTEM_PARTITION_SYSTEM_PARAMETER:
  246. p->addr = flash_size - SYSTEM_PARAMETER_SIZE;
  247. p->size = SYSTEM_PARAMETER_SIZE;
  248. }
  249. if (p->size == 0) {
  250. // Delete 0-sized partitions as the SDK barfs on these
  251. newn--;
  252. } else {
  253. /*
  254. * Do consistency tests on the partition. The address and size must
  255. * be flash sector aligned. Partitions can't overlap, and the last
  256. * patition must fit within the flash size.
  257. */
  258. if (p->addr & (INTERNAL_FLASH_SECTOR_SIZE - 1) ||
  259. p->size & (INTERNAL_FLASH_SECTOR_SIZE - 1) ||
  260. p->addr < last ||
  261. p->addr + p->size > flash_size) {
  262. os_printf("Partition %u invalid alignment\n", i);
  263. while(1) {/*system_soft_wdt_feed ();*/}
  264. }
  265. if (j < i) // shift the partition down if we have any deleted slots
  266. pt[j] = *p;
  267. j++;
  268. last = p->addr + p->size;
  269. }
  270. }
  271. platform_rcr_write(PLATFORM_RCR_PT, pt, newn*sizeof(partition_item_t));
  272. ets_delay_us(5000);
  273. _ResetHandler(); // Trigger reset; the new PT will be loaded on reboot
  274. }
  275. uint32 ICACHE_RAM_ATTR user_iram_memory_is_enabled(void) {
  276. return FALSE; // NodeMCU runs like a dog if iRAM is enabled
  277. }
  278. void nodemcu_init(void) {
  279. STARTUP_COUNT;
  280. NODE_DBG("Task task_lua starting.\n");
  281. // Call the Lua bootstrap startup directly. This uses the task interface
  282. // internally to carry out the main lua libraries initialisation.
  283. if(lua_main())
  284. lua_main(); // If it returns true then LFS restart is needed
  285. }
  286. #ifdef LUA_USE_MODULES_WIFI
  287. #include "../modules/wifi_common.h"
  288. void user_rf_pre_init(void)
  289. {
  290. //set WiFi hostname before RF initialization (adds ~479 us to boot time)
  291. wifi_change_default_host_name();
  292. }
  293. #endif
  294. /******************************************************************************
  295. * FunctionName : user_init
  296. * Description : entry of user application, init user function here
  297. * Parameters : none
  298. * Returns : none
  299. *******************************************************************************/
  300. void user_init(void) {
  301. #ifdef LUA_USE_MODULES_RTCTIME
  302. rtctime_late_startup ();
  303. #endif
  304. if( platform_init() != PLATFORM_OK ) {
  305. // This should never happen
  306. NODE_DBG("Can not init platform for modules.\n");
  307. return;
  308. }
  309. UartBautRate br = BIT_RATE_DEFAULT;
  310. uart_init (br, br);
  311. #ifndef NODE_DEBUG
  312. system_set_os_print(0);
  313. #endif
  314. system_init_done_cb(nodemcu_init);
  315. }
  316. #if 0
  317. /*
  318. * The SDK now establishes exception handlers for EXCCAUSE errors: ILLEGAL,
  319. * INSTR_ERROR, LOAD_STORE_ERROR, PRIVILEGED, UNALIGNED, LOAD_PROHIBITED,
  320. * STORE_PROHIBITED. These handlers are established in SDK/app_main.c.
  321. * LOAD_STORE_ERROR is handled by SDK/user_exceptions.o:load_non_32_wide_handler()
  322. * which is a fork of our version. The remaining are handled by a static function
  323. * at SDK:app+main.c:offset 0x0348. This wrappoer is only needed for debugging.
  324. */
  325. void __real__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn);
  326. void __wrap__xtos_set_exception_handler (uint32_t cause, exception_handler_fn fn) {
  327. os_printf("Exception handler %x %x\n", cause, fn);
  328. __real__xtos_set_exception_handler (cause, fn);
  329. }
  330. #endif