mirror of
https://github.com/nodemcu/nodemcu-firmware.git
synced 2025-01-16 20:52:57 +08:00
9bbf8f43fb
RTOS driver evicted as it did not play nice with stdio etc. Implemented a minimal driver to fully support Lua console on UART0. Output on UART0 done via stdout (provided by the IDF). Input and setup handled via driver_console/console.c. In addition to the direct input function console_getc(), the driver also registers in the syscall tables to enable regular stdio input functions to work (yay!). The Lua VM is still using the direct interface since it's less overhead, but does also work when going through stdin/fd 0. Auto-bauding on the console is not yet functional; revisit when the UART docs are available. Module registration/linking/enabling moved over to be Kconfig based. See updates to base_nodemcu/include/module.h and base_nodemcu/Kconfig for details. The sdk-overrides directory/approach is no longer used. The IDF is simply too different to the old RTOS SDK - we need to adapt our code directly instead. Everything in app/ is now unused, and will need to be gradually migrated into components/ though it is probably better to migrate straight from the latest dev branch.
145 lines
3.8 KiB
C
145 lines
3.8 KiB
C
/**
|
|
This file encapsulates the SDK-based task handling for the NodeMCU Lua firmware.
|
|
*/
|
|
#include "task/task.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/queue.h"
|
|
#include "freertos/semphr.h"
|
|
|
|
#define TASK_HANDLE_MONIKER 0x68680000
|
|
#define TASK_HANDLE_MASK 0xFFF80000
|
|
#define TASK_HANDLE_UNMASK (~TASK_HANDLE_MASK)
|
|
#define TASK_HANDLE_ALLOCATION_BRICK 4 // must be a power of 2
|
|
#define TASK_DEFAULT_QUEUE_LEN 8
|
|
|
|
#define CHECK(p,v,msg) if (!(p)) { NODE_DBG ( msg ); return (v); }
|
|
|
|
#ifndef NODE_DBG
|
|
# define NODE_DBG(...) do{}while(0)
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
task_handle_t sig;
|
|
task_param_t par;
|
|
} task_event_t;
|
|
|
|
/*
|
|
* Private arrays to hold the 3 event task queues and the dispatch callbacks
|
|
*/
|
|
static xQueueHandle task_Q[TASK_PRIORITY_COUNT];
|
|
|
|
/* Rather than using a QueueSet (which requires queues to be empty when created)
|
|
* we use a binary semaphore to unblock the pump whenever something is posted */
|
|
static xSemaphoreHandle pending;
|
|
|
|
static task_callback_t *task_func;
|
|
static int task_count;
|
|
|
|
|
|
/*
|
|
* Initialise the task handle callback for a given priority. This doesn't need
|
|
* to be called explicitly as the get_id function will call this lazily.
|
|
*/
|
|
bool task_init_handler(task_prio_t priority, uint8 qlen) {
|
|
if (priority >= TASK_PRIORITY_COUNT)
|
|
return false;
|
|
|
|
if (task_Q[priority] == NULL)
|
|
{
|
|
task_Q[priority] = xQueueCreate (qlen, sizeof (task_event_t));
|
|
return task_Q[priority] != NULL;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
task_handle_t task_get_id(task_callback_t t) {
|
|
/* Initialise any uninitialised Qs with the default Q len */
|
|
for (task_prio_t p = TASK_PRIORITY_LOW; p != TASK_PRIORITY_COUNT; ++p)
|
|
{
|
|
if (!task_Q[p]) {
|
|
CHECK(task_init_handler( p, TASK_DEFAULT_QUEUE_LEN ), 0, "Task initialisation failed");
|
|
}
|
|
}
|
|
|
|
if ( (task_count & (TASK_HANDLE_ALLOCATION_BRICK - 1)) == 0 ) {
|
|
/* With a brick size of 4 this branch is taken at 0, 4, 8 ... and the new size is +4 */
|
|
task_func =(task_callback_t *)realloc(
|
|
task_func,
|
|
sizeof(task_callback_t)*(task_count+TASK_HANDLE_ALLOCATION_BRICK));
|
|
|
|
CHECK(task_func, 0 , "Malloc failure in task_get_id");
|
|
memset (task_func+task_count, 0, sizeof(task_callback_t)*TASK_HANDLE_ALLOCATION_BRICK);
|
|
}
|
|
|
|
task_func[task_count] = t;
|
|
return TASK_HANDLE_MONIKER | task_count++;
|
|
}
|
|
|
|
|
|
bool task_post (task_prio_t priority, task_handle_t handle, task_param_t param)
|
|
{
|
|
if (priority >= TASK_PRIORITY_COUNT ||
|
|
!task_Q[priority] ||
|
|
(handle & TASK_HANDLE_MASK) != TASK_HANDLE_MONIKER)
|
|
return false;
|
|
|
|
task_event_t ev = { handle, param };
|
|
bool res = pdPASS == xQueueSendToBackFromISR (task_Q[priority], &ev, NULL);
|
|
|
|
if (pending) /* only need to raise semaphore if it's been initialised */
|
|
xSemaphoreGiveFromISR (pending, NULL);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
static bool next_event (task_event_t *ev, task_prio_t *prio)
|
|
{
|
|
for (task_prio_t pr = TASK_PRIORITY_COUNT; pr != TASK_PRIORITY_LOW; --pr)
|
|
{
|
|
task_prio_t p = pr -1;
|
|
if (task_Q[p] && xQueueReceive (task_Q[p], ev, 0) == pdTRUE)
|
|
{
|
|
*prio = p;
|
|
return true;
|
|
}
|
|
}
|
|
return false; // no events queued
|
|
}
|
|
|
|
|
|
static void dispatch (task_event_t *e, uint8_t prio) {
|
|
task_handle_t handle = e->sig;
|
|
if ( (handle & TASK_HANDLE_MASK) == TASK_HANDLE_MONIKER) {
|
|
uint16_t entry = (handle & TASK_HANDLE_UNMASK);
|
|
if ( task_func && entry < task_count ){
|
|
/* call the registered task handler with the specified parameter and priority */
|
|
task_func[entry](e->par, prio);
|
|
return;
|
|
}
|
|
}
|
|
/* Invalid signals are ignored */
|
|
NODE_DBG ( "Invalid signal issued: %08x", handle);
|
|
}
|
|
|
|
|
|
void task_pump_messages (void)
|
|
{
|
|
vSemaphoreCreateBinary (pending);
|
|
for (;;)
|
|
{
|
|
task_event_t ev;
|
|
task_prio_t prio;
|
|
if (next_event (&ev, &prio))
|
|
dispatch (&ev, prio);
|
|
else
|
|
xSemaphoreTake (pending, portMAX_DELAY);
|
|
}
|
|
}
|