nodemcu-firmware/components/base_nodemcu/user_main.c

195 lines
5.5 KiB
C

/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: user_main.c
*
* Description: entry file of user application
*
* Modification history:
* 2014/1/1, v1.0 create this file.
*******************************************************************************/
#include "lua.h"
#include "platform.h"
#include <string.h>
#include <stdlib.h>
#include "vfs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "flash_api.h"
#include "driver/console.h"
#include "task/task.h"
#include "sections.h"
#include "nodemcu_esp_event.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#define SIG_LUA 0
#define SIG_UARTINPUT 1
// We don't get argument size data from the esp_event dispatch, so it's
// not possible to copy and forward events from the default event queue
// to one running within our task context. To cope with this, we instead
// have to effectively make a blocking inter-task call, by having our
// default loop handler post a nodemcu task event with a pointer to the
// event data, and then *block* until that task event has been processed.
// This is less elegant than I would like, but trying to run the entire
// LVM in the context of the system default event loop RTOS task is an
// even worse idea, so here we are.
typedef struct {
esp_event_base_t event_base;
int32_t event_id;
void *event_data;
} relayed_event_t;
static task_handle_t relayed_event_task;
static SemaphoreHandle_t relayed_event_handled;
// This function runs in the context of the system default event loop RTOS task
static void relay_default_loop_events(
void *arg, esp_event_base_t base, int32_t id, void *data)
{
(void)arg;
relayed_event_t event = {
.event_base = base,
.event_id = id,
.event_data = data,
};
_Static_assert(sizeof(&event) >= sizeof(task_param_t), "pointer-vs-int");
// Only block if we actually posted the request, otherwise we'll deadlock!
if (task_post_medium(relayed_event_task, (intptr_t)&event))
xSemaphoreTake(relayed_event_handled, portMAX_DELAY);
else
printf("ERROR: failed to forward esp event %s/%d", base, id);
}
static void handle_default_loop_event(task_param_t param, task_prio_t prio)
{
(void)prio;
const relayed_event_t *event = (const relayed_event_t *)param;
nodemcu_esp_event_reg_t *evregs = &_esp_event_cb_table_start;
for (; evregs < &_esp_event_cb_table_end; ++evregs)
{
bool event_base_match =
(evregs->event_base_ptr == NULL) || // ESP_EVENT_ANY_BASE marker
(*evregs->event_base_ptr == event->event_base);
bool event_id_match =
(evregs->event_id == event->event_id) ||
(evregs->event_id == ESP_EVENT_ANY_ID);
if (event_base_match && event_id_match)
evregs->callback(event->event_base, event->event_id, event->event_data);
}
xSemaphoreGive(relayed_event_handled);
}
// +================== New task interface ==================+
static void start_lua ()
{
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
NODE_DBG("Task task_lua started.\n");
lua_main( 2, lua_argv );
}
static void handle_input(task_param_t flag, task_prio_t priority) {
(void)priority;
lua_handle_input (flag);
}
static task_handle_t input_task;
task_handle_t user_get_input_sig(void) {
return input_task;
}
bool user_process_input(bool force) {
return task_post_low(input_task, force);
}
void nodemcu_init(void)
{
NODE_ERR("\n");
// Initialize platform first for lua modules.
if( platform_init() != PLATFORM_OK )
{
// This should never happen
NODE_DBG("Can not init platform for modules.\n");
return;
}
if (flash_safe_get_size_byte() != flash_rom_get_size_byte()) {
NODE_ERR("Incorrect flash size reported, adjusting...\n");
// Fit hardware real flash size.
flash_rom_set_size_byte(flash_safe_get_size_byte());
// Reboot to get SDK to use (or write) init data at new location
esp_restart ();
// Don't post the start_lua task, we're about to reboot...
return;
}
#if defined ( CONFIG_NODEMCU_BUILD_SPIFFS )
// This can take a while, so be nice and provide some feedback while waiting
printf ("Mounting flash filesystem...\n");
if (!vfs_mount("/FLASH", 0)) {
// Failed to mount -- try reformat
NODE_ERR("Formatting file system. Please wait...\n");
if (!vfs_format()) {
NODE_ERR( "*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
}
// Note that fs_format leaves the file system mounted
}
#endif
}
void __attribute__((noreturn)) app_main(void)
{
task_init();
input_task = task_get_id (handle_input);
relayed_event_handled = xSemaphoreCreateBinary();
relayed_event_task = task_get_id(handle_default_loop_event);
esp_event_loop_create_default();
esp_event_handler_register(
ESP_EVENT_ANY_BASE,
ESP_EVENT_ANY_ID,
relay_default_loop_events,
NULL);
ConsoleSetup_t cfg;
cfg.bit_rate = CONFIG_NODEMCU_CONSOLE_BIT_RATE;
cfg.data_bits = CONSOLE_NUM_BITS_8;
cfg.parity = CONSOLE_PARITY_NONE;
cfg.stop_bits = CONSOLE_STOP_BITS_1;
cfg.auto_baud =
#ifdef CONFIG_NODEMCU_CONSOLE_BIT_RATE_AUTO
true;
#else
false;
#endif
console_init (&cfg, input_task);
setvbuf(stdout, NULL, _IONBF, 0);
nodemcu_init ();
nvs_flash_init ();
esp_netif_init ();
start_lua ();
task_pump_messages ();
__builtin_unreachable ();
}