RTOS Development Guide_Rev1.0
Document Revision History
Version |
Date |
Author |
Changes |
|---|---|---|---|
Rev1.0 |
23-09-12 |
CLY |
Created document |
Rev1.1 |
24-03-25 |
sxx |
Renamed document |
Rev1.2 |
24-10-08 |
ymx |
Optimized document structure, added |
Rev1.3 |
24-12-12 |
ymx |
Removed all function links to solve DingTalk/Feishu link issues |
Rev1.4 |
26-01-27 |
ljz |
Added interface |
Rev1.5 |
26-04-22 |
mbb |
Reformatted layout, added platform RTOS architecture description, RTOS core concepts, demo examples, and quick start guide |
1 Introduction
This document describes the LTE-EC71X RTOS API information. The API declarations are located in components/kernel/lierda_api/liot_os/liot_os.h.
1.1 RTOS Core Architecture
1.1.1 Overall Architecture Overview
The RTOS software stack uses a layered design. From bottom to top it consists of the hardware adaptation layer, kernel layer, and abstraction/wrapper layer. Each layer has clear responsibilities, balancing the performance demands of low-level hardware with the development efficiency of upper-layer applications.
┌─────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Business Task 1 │ │ Business Task 2 │ │ Business Task N │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Lierda Application Abstraction Layer │
│ (liot_os / OSAL) │
│ (Hides low-level differences and provides type-safe, │
│ easy-to-use standardized APIs) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Platform Adaptation Layer (BSP modified │
│ FreeRTOS) │
│ (Based on Kernel V9.0.0a, deeply customized for EC │
│ Cat.1 hardware) │
└─────────────────────────────────────────────────────────┘
1.1.2 Two-Layer Architecture Details
1.1.2.1 Platform Adaptation Layer: Customized FreeRTOS Kernel
Location:
components/thirdparty/freertosBaseline version: FreeRTOS Kernel V9.0.0a
Customization goal: deeply adapt to the hardware features and system resource constraints of the Yixin EC CAT1 series chips.
Major changes:
Memory management subsystem enhancement:
Integrated memory debug hooks, supporting heap leak detection and boundary checks.
Implemented standard TLSF algorithm for efficient dynamic management of external RAM.
Customized optimization for EC718PM PSRAM characteristics, expanding usable memory and adding exception handling.
Debug and observability support:
Integrated a unified debug log interface and provided a CMSIS-RTOS v2 compatibility layer for easier integration with ecosystem toolchains.
Platform hardware abstraction definitions:
Defined platform-specific configuration macros and memory layout.
Reserved interfaces for future multi-core support.
1.1.2.2 Application Abstraction Layer: Lierda Wrapper Interface
Location:
components/kernel/lierda_api/liot_osDesign goal: provide terminal developers a standardized, type-safe, easy-to-integrate OS abstraction layer.
Core features:
Simplified interface contract: reduced required parameters and defined a unified error code return mechanism.
Strong type constraints: introduced opaque handle types such as
liot_task_tto prevent direct manipulation of kernel data structures.Document standardization: follows Doxygen comment conventions and provides detailed Chinese explanations and examples.
Platform independence: abstracts lower-level calls to improve cross-platform portability.
1.1.2.3 Two-Layer Architecture vs. Native FreeRTOS
Dimension |
Native FreeRTOS Interface |
Yixin Hardware Adaptation Layer (BSP) |
Yixin Application Abstraction Layer (Lierda OSAL) |
|---|---|---|---|
Abstraction level |
Kernel-level |
Board support package |
Application framework layer |
Usage complexity |
High |
Medium |
Low |
Configuration flexibility |
Very high |
Medium (limited by hardware features) |
Lower (focused on application logic) |
Usability and safety |
Lower (requires deep kernel understanding) |
Medium (requires understanding memory mapping) |
Higher (strong typing and default parameter protection) |
Typical use case |
Kernel development, extreme tuning |
Driver porting, board-level management |
Business logic development, rapid prototyping |
1.2 RTOS Core Concepts
RTOS is the real-time operating system kernel for embedded systems. This module uses a FreeRTOS-wrapped implementation. Core concepts are as follows:
1.2.1 Task Scheduling Mechanism
A task is the basic execution unit in RTOS. All user business code should run inside tasks. The core scheduling rules are:
Preemptive priority scheduling: when a higher-priority task becomes ready, it immediately preempts the currently running lower-priority task.
Time-sliced round-robin for same priority: tasks with the same priority are scheduled in a time-slice loop, with a 1 ms time slice. Interrupt-triggered scheduling: after an ISR completes, if it wakes a higher-priority task, context switch occurs immediately.
API-triggered scheduling: calling
liot_rtos_task_yield()(voluntary yield),liot_rtos_task_sleep_ms()/liot_rtos_task_sleep_s()(sleep), etc. triggers the scheduler to select the highest-priority ready task.Task priority limits: tasks involving audio operations should not exceed priority 23; tasks not involving audio should not exceed priority 25. Do not perform complex business logic in ISRs to avoid blocking the system.
Task State Transition Diagram
liot_rtos_task_create()
│
▼
┌──────────────────────────────────┐
│ Ready │◄─────────────────────────┐
└───────────────┬──────────────────┘ │
│ Scheduler selects (highest priority) │
▼ │
┌──────────────────────────────────┐ Time slice expired/ │
│ Running │ yield/higher ready │
└──┬─────────────┬─────────────┬───┘─────────────────────────┘
│ │ │
│ sleep/ │ │ liot_rtos_task_suspend()
│ wait/lock │ │
▼ │ ▼
┌──────────────┐ │ ┌────────────────────┐
│ Blocked │ │ │ Suspended │
└──────┬───────┘ │ └─────────┬──────────┘
│ │ │
Timeout/semaphore │ liot_rtos_task_resume()
released/event met │ │
│ │ │
└─────────────┼───────────────┘
│ │
│ └───► Back to Ready
│
│ liot_rtos_task_delete()
▼
┌──────────────────────────────────┐
│ Deleted │
└──────────────────────────────────┘
1.2.2 Blocking APIs vs Non-blocking APIs
Type |
Characteristics |
Typical API |
Use Case |
|---|---|---|---|
Blocking |
If conditions are not met, the task blocks until the condition is met or timeout occurs |
|
Task synchronization, data reception, timed sleep |
Non-blocking |
If conditions are not met, the API returns immediately with an error code |
|
Polling status checks, quick resource availability checks |
1.2.3 Inter-task Communication Mechanisms and Selection Principles
1.2.3.1 Semaphore
Primary function: synchronization and counting.
Use cases:
Binary semaphore: used for task notification or triggers. For example, an ISR signals that data is ready for a processing task.
Counting semaphore: used to manage multiple shared resources. For example, limit the number of tasks simultaneously accessing a hardware peripheral.
1.2.3.2 Mutex
Primary function: resource protection and mutual exclusion.
Use cases: ensure only one task accesses a shared resource at the same time (e.g., global variables, UART printing, I2C bus).
Features: compared to semaphores, mutexes support priority inheritance, effectively preventing priority inversion in RTOS.
Priority inversion example:
Without mutex (using binary semaphore to protect resource):
Time ─────────────────────────────────────────────────────────────────────────────►
Task H (high) ·····waiting·····│·········blocked (resource held by L)················│
Task M (mid) │ ████ preempts L ███████████│
Task L (low) ████████████████│holds resource████████████ preempted by M ──────────│
Problem: Task M preempts Task L while L holds the resource,
indirectly blocking higher-priority Task H.
With mutex (priority inheritance mechanism):
Time ─────────────────────────────────────────────────────────────────────────────►
Task H (high) ·····waiting for mutex····│····blocked····│ acquires mutex ██████████████│
Task M (mid) │ │ cannot preempt (L inherited H's priority) ──│
Task L (low) █████████████████████████│inherits H pri██│ releases mutex (reverts priority) │
Effect: Task L inherits Task H's priority while holding the mutex,
Task M cannot preempt, Task H acquires the resource ASAP.
1.2.3.3 Message Queue
Primary function: data transfer.
Use cases: when a task needs to send concrete data (not just a signal) to another task. Queues support asynchronous communication: tasks can enqueue messages and continue without waiting for the receiver.
1.2.3.4 Event Group (Flag)
Primary function: multi-event logic synchronization and notification (many-to-one synchronization). Unlike semaphores, event groups can use bitwise AND/OR logic, allowing one task to wait on multiple event combinations.
Use cases:
AND logic synchronization: task runs only when all conditions are met.
OR logic synchronization: task runs when any trigger occurs.
Event broadcast: one event can wake multiple tasks waiting on different bits within the event group.
1.2.4 Synchronization Mechanism Selection Guidelines
Choose the appropriate synchronization mechanism based on business scenarios. The following decision table is for reference:
Scenario |
Recommended mechanism |
Reason |
|---|---|---|
ISR notifies task (single event) |
Semaphore ( |
Safe to release in ISR, task blocks and waits, lowest overhead |
ISR passes data to task |
Message queue ( |
Supports passing concrete data and buffering multiple interrupt events |
Multi-condition sync (any condition) |
Event group OR ( |
One task can listen to multiple event sources and wake on any trigger |
Multi-condition sync (all conditions) |
Event group AND ( |
Task waits until all preconditions are ready |
Shared resource protection |
Mutex ( |
Supports priority inheritance and ensures one task accesses the resource exclusively |
Multiple tasks share one notification |
Event group broadcast ( |
One setting wakes multiple waiting tasks |
Counting / rate limiting |
Counting semaphore ( |
Limits concurrent access to a resource, such as connection pool management |
1.2.5 Heap Memory
Memory Allocation Architecture
┌──────────────────────────────────────────────────────────────────────┐
│ Application Layer Memory Usage │
├────────────────────────┬──────────────────┬──────────────────────────┤
│ liot_rtos_malloc/free │ Static task stack │ PSRAM dynamic allocation │
│ liot_rtos_realloc │ (global arrays, │ (EC718PM series only) │
│ liot_rtos_calloc │ user pre-alloc) │ │
│ (System heap - SRAM) │ │ │
├────────────────────────┴──────────────────┼──────────────────────────┤
│ FreeRTOS heap (TLSF algorithm) │ PSRAM heap (TLSF) │
├────────────────────────────────────────────┼──────────────────────────┤
│ SRAM (on-chip) │ PSRAM (off-chip) │
└────────────────────────────────────────────┴──────────────────────────┘
System heap (SRAM): allocated via
liot_rtos_malloc()and similar APIs; dynamically created task stacks and TCBs are also allocated from here.PSRAM heap: only supported on EC718PM series, used for large data buffer scenarios; query usage via
liot_psram_xPortGet*series APIs.Static task stack: use
liot_rtos_task_create_static()with user-preallocated global arrays/static variables as the task stack, no system heap allocation.Task stack: each dynamically created task allocates an independent stack from the system heap; stack size is specified at creation time.
Current heap memory allocation status is as follows:
Base package model |
F6B_A |
F6D_A |
F7B_A |
K2B_A |
K2F_A |
|---|---|---|---|---|---|
Supported module model |
NT26FCNB60WNA |
NT26FCND60NNA |
NT26FCNB70WNA |
NT26K2B1 |
NT26KCNF20NNA |
Chip type |
EC718pm |
EC718pm |
EC718pm |
EC716e |
EC716e |
Total RAM |
4 MB |
4 MB |
4 MB |
2 MB |
2 MB |
Available RAM |
1 MB |
1 MB |
1 MB |
512 KB |
512 KB |
PSRAM |
Supported |
Supported |
Supported |
Not supported |
Not supported |
1.3 Interrupt Context Development Constraints
The interaction between ISRs and tasks is a critical part of embedded development. The Lierda OS wrapper layer automatically detects interrupt context and adapts API calls to the FromISR versions when needed.
1.3.1 APIs Allowed in ISR
Category |
Available API |
Behavior description |
|---|---|---|
Semaphore |
|
Non-blocking and safe to release and wake tasks |
Message queue |
|
Send data to queue, non-blocking receive |
Event group |
|
Set/clear flags |
System |
|
Get time, critical section protection |
1.3.2 APIs Forbidden in ISR
The following APIs involve memory allocation, task scheduling, or blocking operations and must not be called from ISRs:
Create/delete operations: create, delete (involve dynamic memory allocation, unsafe in interrupts).
Blocking operations: sleep, mutex_lock, flag_wait (ISRs cannot block or sleep).
Control operations: task_suspend, task_resume, change_priority (involve task list traversal).
1.3.3 Typical ISR-to-Task Interaction Patterns
Best practices:
Do as little work as possible in the ISR: read registers, release semaphores, send queues, or set event flags.
Perform complex processing in a task: wake a business task via IPC from the ISR.
ISR-to-Task Minimal Example
static liot_sem_t isr_sem = NULL;
// ISR: only release semaphore
void EXTI_IRQHandler(void)
{
// Clear interrupt flag (hardware-specific)
// ...
// Release semaphore to wake processing task
liot_rtos_semaphore_release(isr_sem);
}
// Business task: blocks waiting for ISR notification, then performs lengthy processing
void data_process_task(void *pvParameters)
{
for (;;)
{
if (liot_rtos_semaphore_wait(isr_sem, LIOT_WAIT_FOREVER) == LIOT_OSI_SUCCESS)
{
// Execute time-consuming business logic here (forbidden in ISR)
// e.g., data parsing, protocol handling, storage writes, etc.
}
}
}
Preemption Scheduling Timing
Time ─────────────────────────────────────────────────────►
Low-priority task (running) ████████████
│ Interrupt occurs
▼
ISR executes ██ (releases semaphore)
│
▼ ISR exits, scheduler finds high-priority task ready
High-priority task (woken) ████████████████████
│ Enters blocked state
Low-priority task (resumes) ████████
1.4 Quick Start Guide
1.4.1 Typical Development Flow
Create tasks using
liot_rtos_task_create().Create synchronization mechanisms: semaphores, mutexes, or event groups as needed.
Create message queues if you need task-to-task data transfer.
Implement the business loop inside a task, using IPC mechanisms for synchronization and communication.
Clean up RTOS objects before task exit.
1.4.2 Example Usage (Minimal Demo)
#include "liot_os.h"
#define WORK_COUNT 10
// Task handles
static liot_task_t worker_handle = NULL;
static liot_sem_t work_sem = NULL;
// Worker task function (executes a limited number of times then exits)
void liot_worker_task(void *pvParameters)
{
int count = 0;
while (count < WORK_COUNT)
{
if (liot_rtos_semaphore_wait(work_sem, LIOT_WAIT_FOREVER) == LIOT_OSI_SUCCESS)
{
liot_trace("Worker received signal [%d/%d]", count + 1, WORK_COUNT);
count++;
}
}
// Work complete, clean up resources
liot_trace("Worker done, cleaning up...");
liot_rtos_semaphore_delete(work_sem);
work_sem = NULL;
worker_handle = NULL;
liot_rtos_task_delete(NULL);
}
// Main task function
void liot_main_task(void *pvParameters)
{
// Create semaphore
LiotOSStatus_t ret = liot_rtos_semaphore_create(&work_sem, 0);
if (ret != LIOT_OSI_SUCCESS)
{
liot_trace("Failed to create semaphore, err=%d", ret);
return;
}
// Create worker task
ret = liot_rtos_task_create(&worker_handle,
2048, // Stack size (bytes)
LIOT_APP_TASK_PRIORITY, // Priority
"Worker", // Task name
liot_worker_task, // Task entry function
NULL); // Parameter
if (ret != LIOT_OSI_SUCCESS)
{
liot_trace("Failed to create worker task, err=%d", ret);
liot_rtos_semaphore_delete(work_sem);
work_sem = NULL;
return;
}
// Main loop: release semaphore to wake worker task
for (int i = 0; i < WORK_COUNT; i++)
{
liot_rtos_semaphore_release(work_sem);
liot_rtos_task_sleep_s(1);
}
liot_trace("Main task done");
}
2 API Overview
2.1 Tasks
Function |
Description |
Context |
|---|---|---|
|
Create a task |
Task only |
|
Delete a task |
Task only |
|
Yield CPU usage |
Task only |
|
Get current task handle |
Task only |
|
Change task priority |
Task only |
|
Get task status information |
Task only |
|
Set task sleep time (milliseconds) |
Task only (blocking) |
|
Set task sleep time (seconds) |
Task only (blocking) |
|
Get task stack free space |
Task only |
|
Suspend a task |
Task only |
|
Resume a suspended task |
Task only |
|
Get RTOS uptime in milliseconds |
Task/ISR |
|
Get RTOS system tick count |
Task/ISR |
|
Determine if a task is alive |
Task only |
|
Create a task statically |
Task only |
2.2 Memory Management
Function |
Description |
|---|---|
|
Allocate memory dynamically |
|
Free dynamically allocated memory |
|
Reallocate memory block |
|
Allocate zero-initialized memory |
|
Get total FreeRTOS heap size |
|
Get free FreeRTOS heap size |
|
Get minimum ever free FreeRTOS heap size |
|
Get maximum free block size in FreeRTOS heap |
|
Get PSRAM total size |
|
Get PSRAM free size |
|
Get minimum ever free PSRAM size |
|
Get maximum free block size in PSRAM |
2.3 Critical Sections
Function |
Description |
|---|---|
|
Enter critical section |
|
Enter critical section from ISR |
|
Exit critical section |
|
Exit critical section from ISR |
2.4 Semaphores
Function |
Description |
Context |
|---|---|---|
|
Create a binary semaphore |
Task only |
|
Create a counting semaphore |
Task only |
|
Wait for semaphore |
Task (blocking)/ISR (LIOT_NO_WAIT only) |
|
Release semaphore |
Task/ISR |
|
Get semaphore count |
Task/ISR |
|
Delete semaphore |
Task only |
2.5 Mutexes
Function |
Description |
Context |
|---|---|---|
|
Create a mutex |
Task only |
|
Lock a mutex, timeout configurable |
Task only (blocking) |
|
Try to lock a mutex |
Task only (non-blocking) |
|
Unlock a mutex |
Task only |
|
Delete a mutex |
Task only |
2.6 Message Queues
Function |
Description |
Context |
|---|---|---|
|
Create a message queue |
Task only |
|
Wait for messages in queue |
Task (blocking)/ISR (LIOT_NO_WAIT only) |
|
Release message to queue |
Task/ISR |
|
Get number of messages in queue |
Task/ISR |
|
Delete a queue |
Task only |
|
Reset queue elements and change queue length |
Task only |
|
Query available queue space |
Task/ISR |
2.7 Timers
Function |
Description |
Context |
|---|---|---|
|
Create a timer |
Task only |
|
Start a timer |
Task/ISR |
|
Check whether timer is running |
Task/ISR |
|
Stop a timer |
Task only |
|
Delete a timer |
Task only |
|
Stop a timer from ISR |
ISR |
2.8 Event Groups
Function |
Description |
Context |
|---|---|---|
|
Create an event group |
Task only |
|
Get current event group bit state |
Task/ISR |
|
Wait for event group bits to meet conditions |
Task only (blocking) |
|
Set event bits in an event group |
Task/ISR |
|
Clear event bits in an event group |
Task/ISR |
|
Delete an event group |
Task only |
2.9 Others
Function |
Description |
|---|---|
|
Software random number |
|
Hardware random number |
3 Type Definitions
3.1 LiotOSStatus_t
Declaration
typedef int LiotOSStatus_t;
Description
RTOS API return value data type.
Return Value |
Description |
|---|---|
|
Success |
|
Invalid task parameter |
|
Task creation failed |
|
Not enough task memory |
|
Task deletion failed |
|
Task priority invalid |
|
Task name length invalid |
|
Invalid task handle |
|
Semaphore creation failed (note: spelling consistent with header file definition) |
|
Semaphore deletion failed |
|
Semaphore is full |
|
Semaphore release failed |
|
Semaphore get failed |
|
Semaphore failure |
|
Mutex creation failed |
|
Mutex deletion failed |
|
Mutex lock failed |
|
Mutex unlock failed |
|
Timer creation failed |
|
Timer start failed |
|
Timer stop failed |
|
Timer deletion failed |
|
Timer bind task failed |
|
Queue creation failed |
|
Queue deletion failed |
|
Queue is full |
|
Queue release failed |
|
Queue receive failed |
|
Get queue count failed |
|
Queue failure |
|
Queue reset failed |
3.2 liot_task_t
Declaration
typedef void *liot_task_t;
Description
Task handle type.
3.3 liot_sem_t
Declaration
typedef void *liot_sem_t;
Description
Semaphore handle type.
3.4 liot_mutex_t
Declaration
typedef void *liot_mutex_t;
Description
Mutex handle type.
3.5 liot_queue_t
Declaration
typedef void *liot_queue_t;
Description
Message queue handle type.
3.6 liot_timer_t
Declaration
typedef void *liot_timer_t;
Description
Timer handle type.
3.7 liot_wait_e
Declaration
typedef enum
{
LIOT_WAIT_FOREVER = 0xFFFFFFFFUL,
LIOT_NO_WAIT = 0
} liot_wait_e;
Description
LIOT_WAIT_FOREVER: wait foreverLIOT_NO_WAIT: do not wait
3.8 liot_timertype_e
Timer mode.
Declaration
typedef enum
{
LIOT_TimerOnce = 0, ///< One-shot timer.
LIOT_TimerPeriodic = 1 ///< Repeating timer.
} liot_timertype_e;
Description
LIOT_TimerOnce: one-shot modeLIOT_TimerPeriodic: periodic mode
3.9 liot_task_state_e
Task states.
Declaration
typedef enum
{
LIOT_Running = 0,
LIOT_Ready,
LIOT_Blocked,
LIOT_Suspended,
LIOT_Deleted,
LIOT_Invalid
} liot_task_state_e;
Description
LIOT_Running: running stateLIOT_Ready: ready stateLIOT_Blocked: blocked stateLIOT_Suspended: suspended stateLIOT_Deleted: deleted stateLIOT_Invalid: invalid state
3.10 liot_flag_op_e
Event group flag operations.
Declaration
typedef enum
{
LIOT_FLAG_AND = 5,
LIOT_FLAG_AND_CLEAR = 6,
LIOT_FLAG_OR = 7,
LIOT_FLAG_OR_CLEAR = 8
} liot_flag_op_e;
Description
LIOT_FLAG_AND: wait for all bits in the input event to be set; do not clear flags after processing.LIOT_FLAG_AND_CLEAR: wait for all bits and clear after processing.LIOT_FLAG_OR: wait for any bit to be set; do not clear after processing.LIOT_FLAG_OR_CLEAR: wait for any bit and clear after processing.
3.11 liot_StaticTask_t
Declaration
typedef void *liot_StaticTask_t;
Description
Static task data structure type.
4 API Details
4.1 Task APIs
4.1.1 liot_rtos_task_create
Create a task. This function does not support creating events. Task priority should not be set too high: for audio-related tasks it should not exceed 23; for non-audio tasks it should not exceed 25.
Declaration
extern LiotOSStatus_t liot_rtos_task_create(liot_task_t *taskRef,
uint32 stackSize,
uint8 priority,
char *taskName,
void (*taskStart)(void *),
void *argv,
...);
Parameters
taskRef: [Out] task handle.stackSize: [In] task stack size in bytes. Maximum: 128 * 1024 bytes.priority: [In] task priority range 0~30.
Recommended predefined priorities:
Priority name |
Value |
Description |
|---|---|---|
|
1 |
Idle task priority (reserved) |
|
4 |
Low priority |
|
8 |
Below normal |
|
12 |
Normal priority (default recommended) |
|
16 |
Above normal |
|
25 |
High priority |
|
30 |
Real-time priority (highest) |
taskName: [In] task name. Max length 32 bytes.taskStart: [In] task entry function.argv: [In] task argument pointer.
Return value
See Section 3.1.
Note: The priority limits 23 / 25 are recommended values. The SDK only checks that priority does not exceed 30 and does not distinguish audio-related tasks. Developers should follow these recommendations to avoid system stability issues.
4.1.2 liot_rtos_task_delete
Delete a task.
Declaration
extern LiotOSStatus_t liot_rtos_task_delete(liot_task_t taskRef);
Parameters
taskRef: [In] task handle. IfNULL, deletes the current task while other tasks continue running.
Return value
See Section 3.1.
Note:
If
taskRefisNULL, the calling task deletes itself. After deletion, the remaining code in that task will not execute and its stack will be reclaimed automatically.Stack reclamation: for dynamically created tasks (
liot_rtos_task_create), the task stack and TCB are automatically freed back to heap memory when deleted.
4.1.3 liot_rtos_task_yield
Yield CPU usage.
Declaration
extern void liot_rtos_task_yield(void);
Parameters
None.
Return value
None.
4.1.4 liot_rtos_task_get_current_ref
Get the current task handle.
Declaration
extern LiotOSStatus_t liot_rtos_task_get_current_ref(liot_task_t *taskRef);
Parameters
taskRef: [Out] task handle.
Return value
See Section 3.1.
4.1.5 liot_rtos_task_change_priority
Change task priority.
Declaration
extern LiotOSStatus_t liot_rtos_task_change_priority(liot_task_t taskRef, uint8 new_priority, uint8 *old_priority);
Parameters
taskRef: [In] task handle.new_priority: [In] new task priority.old_priority: [Out] previous task priority.
Return value
See Section 3.1.
4.1.6 liot_rtos_task_get_status
Get task status information.
Declaration
extern LiotOSStatus_t liot_rtos_task_get_status(liot_task_t task_ref, liot_task_status_s *status);
Parameters
task_ref: [In] task handle.status: [Out] task status information. See Section 4.1.6.1.
Return value
See Section 3.1.
4.1.7 liot_task_status_s
Structure definition
typedef struct
{
liot_task_t xHandle;
const char *pcTaskName;
liot_task_state_e eCurrentState;
unsigned long uxCurrentPriority;
uint16 usStackHighWaterMark;
} liot_task_status_s;
Parameters
Type |
Field |
Description |
|---|---|---|
|
|
Task handle |
|
|
Task name |
|
|
Task state |
|
|
Task priority |
|
|
Minimum remaining stack space for the task, used to assess potential overflow |
4.1.8 liot_rtos_task_sleep_ms
Sleep for a specified number of milliseconds.
Declaration
extern void liot_rtos_task_sleep_ms(uint32 ms);
Parameters
ms: [In] sleep duration in milliseconds.
Return value
None.
4.1.9 liot_rtos_task_sleep_s
Sleep for a specified number of seconds.
Declaration
extern void liot_rtos_task_sleep_s(uint32 s);
Parameters
s: [In] sleep duration in seconds.
Return value
None.
4.1.10 liot_rtos_task_get_stack_space
Get current task stack free space.
Declaration
extern uint32_t liot_rtos_task_get_stack_space(liot_task_t task_ref);
Parameters
task_ref: [In] task handle.
Return value
Current task free stack space in bytes. This value represents the historical minimum remaining stack (high watermark) since the task was created. During debugging, monitor this value — if it drops below 128 bytes, there is a stack overflow risk and the task stack should be increased.
4.1.11 liot_rtos_task_suspend
Suspend a specified task.
Declaration
extern LiotOSStatus_t liot_rtos_task_suspend(liot_task_t taskRef);
Parameters
taskRef: [In] task handle.
Return value
See Section 3.1.
4.1.12 liot_rtos_task_resume
Resume a suspended task.
Declaration
extern LiotOSStatus_t liot_rtos_task_resume(liot_task_t taskRef);
Parameters
taskRef: [In] task handle.
Return value
See Section 3.1.
4.1.13 liot_rtos_get_running_time
Get the module uptime in milliseconds.
Declaration
extern uint32_t liot_rtos_get_running_time(void);
Parameters
None.
Return value
Uptime in milliseconds.
4.1.14 liot_rtos_get_system_tick
Get the module system tick count since power-on.
Declaration
extern uint32 liot_rtos_get_system_tick(void);
Parameters
None.
Return value
System tick count since power-on.
4.1.15 liot_rtos_is_alive
Determine whether a task is running.
Declaration
extern bool liot_rtos_is_alive(liot_task_t taskRef);
Parameters
taskRef: [In] task handle.
Return value
true: task is alive.false: task is not alive.
4.1.16 liot_rtos_task_create_static
Create a task statically. The user provides both the task stack and the Task Control Block (TCB) as pre-allocated memory (e.g., global arrays or static variables). This interface does not allocate any of these resources from the system heap.
Declaration
extern LiotOSStatus_t liot_rtos_task_create_static(liot_task_t *taskRef,
uint32 stackSize,
uint8 priority,
char *taskName,
void (*taskStart)(void *),
void *stackMem,
void *StaticTask,
void *argv,
...);
Parameters
taskRef: [Out] task handle.stackSize: [In] size of memory pointed to bystackMem, in bytes.priority: [In] task priority range 0~30.taskName: [In] task name, max length 32 bytes.taskStart: [In] task entry function.stackMem: [In] pointer to an array of at leaststackSizebytes used as the task stack. Must have permanent lifetime.StaticTask: [In] pointer to aliot_StaticTask_tvariable to hold task data.argv: [In] task argument.
Return value
See Section 3.1.
4.2 Memory Management
4.2.1 liot_rtos_malloc
Allocate memory dynamically. liot_rtos_malloc is thread-safe, using FreeRTOS memory management internally with critical section protection for concurrent calls.
Declaration
extern void *liot_rtos_malloc(size_t size);
Parameters
size: [In] number of bytes to allocate.
Return value
Address of allocated memory.
4.2.2 liot_rtos_free
Free dynamically allocated memory.
Declaration
extern void liot_rtos_free(void *ptr);
Parameters
ptr: [In] pointer to memory to free.
Return value
None.
4.2.3 liot_rtos_realloc
Reallocate the size of a previously allocated memory block.
Declaration
extern void *liot_rtos_realloc(void *ptr, size_t size);
Parameters
ptr: [In] pointer to the original block.size: [In] new size.
Return value
Returns the pointer to the reallocated memory block on success (may differ from the original address), or NULL on failure.
Note:
If
reallocreturns NULL, the allocation failed but the original pointerptrremains valid and is not freed. The caller must still free the original memory.Never assign the return value of
reallocdirectly to the original pointer. Use a temporary variable to check for NULL first, then update the original pointer. Otherwise, a memory leak will occur on failure.
4.2.4 liot_rtos_calloc
Allocate zero-initialized memory.
This function initializes allocated memory to 0, unlike malloc. It is suitable for arrays or structures that require zeroed memory.
Declaration
extern void *liot_rtos_calloc(size_t n, size_t Size);
Parameters
n: [In] number of elements.Size: [In] size of each element.
Return value
Pointer to allocated memory, or NULL on failure.
4.2.5 liot_xPortGetTotalHeapSize
Get total FreeRTOS heap size.
Declaration
extern size_t liot_xPortGetTotalHeapSize(void);
Parameters
None.
Return value
Total heap size in bytes.
4.2.6 liot_xPortGetFreeHeapSize
Get current free size of the system heap.
Declaration
extern size_t liot_xPortGetFreeHeapSize(void);
Parameters
None.
Return value
Free heap size in bytes.
4.2.7 liot_xPortGetMinimumEverFreeHeapSize
Get the minimum ever free heap size during runtime.
Declaration
extern size_t liot_xPortGetMinimumEverFreeHeapSize(void);
Parameters
None.
Return value
Minimum ever free heap size in bytes.
4.2.8 liot_xPortGetMaximumFreeBlockSize
Get the maximum allocatable block size in the heap.
Declaration
extern size_t liot_xPortGetMaximumFreeBlockSize(void);
Parameters
None.
Return value
Maximum allocatable block size in bytes.
4.2.9 liot_psram_xPortGetTotalHeapSize
Get total PSRAM size.
Declaration
size_t liot_psram_xPortGetTotalHeapSize(void);
Parameters
None.
Return value
PSRAM total size.
4.2.10 liot_psram_xPortGetFreeHeapSize
Get available PSRAM size.
Declaration
size_t liot_psram_xPortGetFreeHeapSize(void);
Parameters
None.
Return value
Available PSRAM size.
4.2.11 liot_psram_xPortGetMinimumEverFreeHeapSize
Get minimum ever free PSRAM size during runtime.
Declaration
size_t liot_psram_xPortGetMinimumEverFreeHeapSize(void);
Parameters
None.
Return value
Minimum ever free PSRAM size.
4.2.12 liot_psram_xPortGetMaximumFreeBlockSize
Get maximum allocatable PSRAM block size.
Declaration
size_t liot_psram_xPortGetMaximumFreeBlockSize(void);
Parameters
None.
Return value
Maximum allocatable PSRAM block size.
4.3 Critical Sections
4.3.1 liot_rtos_enter_critical
Enter critical section protection.
Declaration
extern void liot_rtos_enter_critical(void);
Parameters
None.
Return value
None.
4.3.2 liot_rtos_enter_critical_from_isr
Enter critical section from ISR.
Declaration
extern uint32_t liot_rtos_enter_critical_from_isr(void);
Parameters
None.
Return value
Interrupt return value.
4.3.3 liot_rtos_exit_critical
Exit critical section protection.
Declaration
extern void liot_rtos_exit_critical(void);
Parameters
None.
Return value
None.
4.3.4 liot_rtos_exit_critical_from_isr
Exit critical section from ISR.
Declaration
extern void liot_rtos_exit_critical_from_isr(uint32_t isrm);
Parameters
isrm: [In] return value fromliot_rtos_enter_critical_from_isr().
Return value
None.
4.4 Semaphores
4.4.1 liot_rtos_semaphore_create
Create a semaphore.
Declaration
extern LiotOSStatus_t liot_rtos_semaphore_create(liot_sem_t *semaRef, uint32 initialCount);
Parameters
semaRef: [Out] semaphore handle.initialCount: [In] initial count value.
Return value
See Section 3.1.
Note: Creating semaphores in ISRs is prohibited.
4.4.2 liot_rtos_semaphore_create_ex
Create a semaphore with extra parameters. Semaphore creation involves memory allocation and is unsafe in interrupt context. Create semaphores during task initialization and only release them in interrupts.
Declaration
extern LiotOSStatus_t liot_rtos_semaphore_create_ex(liot_sem_t *semaRef, uint32 initialCount, uint32 max_cnt);
Parameters
semaRef: [Out] semaphore handle.initialCount: [In] initial count value.max_cnt: [In] maximum count value.
Return value
See Section 3.1.
4.4.3 liot_rtos_semaphore_wait
Wait for a semaphore.
Declaration
extern LiotOSStatus_t liot_rtos_semaphore_wait(liot_sem_t semaRef, uint32 timeout);
Parameters
semaRef: [In] semaphore handle.timeout: [In] wait time in milliseconds.0xFFFFFFFFmeans wait forever.
Return value
See Section 3.1.
Usage examples:
Scenario |
Timeout choice |
Description |
|---|---|---|
Task synchronization |
|
Wait for another task notification, such as data processing completion |
Post-interrupt handling |
|
Wait for ISR to release semaphore, trigger data processing |
Timeout protection |
Custom timeout (ms) |
Need response within a time window to avoid indefinite task blocking |
Non-blocking check |
|
Check semaphore immediately without blocking |
Timeout selection advice:
Critical synchronization: use
LIOT_WAIT_FOREVERto ensure completion before proceeding.Time-sensitive scenarios: set a reasonable timeout and handle retries or errors on timeout.
Polling checks: use
LIOT_NO_WAITwith task sleep for periodic checks.
4.4.4 liot_rtos_semaphore_release
Release a semaphore.
Declaration
extern LiotOSStatus_t liot_rtos_semaphore_release(liot_sem_t semaRef);
Parameters
semaRef: [In] semaphore handle.
Return value
See Section 3.1.
4.4.5 liot_rtos_semaphore_get_cnt
Get semaphore count.
Declaration
extern LiotOSStatus_t liot_rtos_semaphore_get_cnt(liot_sem_t semaRef, uint32 *cntPtr);
Parameters
semaRef: [In] semaphore handle.cntPtr: [Out] semaphore count value.
Return value
See Section 3.1.
4.4.6 liot_rtos_semaphore_delete
Delete a semaphore.
Declaration
extern LiotOSStatus_t liot_rtos_semaphore_delete(liot_sem_t semaRef);
Parameters
semaRef: [In] semaphore handle.
Return value
See Section 3.1.
4.5 Mutexes
4.5.1 liot_rtos_mutex_create
Create a mutex.
Declaration
extern LiotOSStatus_t liot_rtos_mutex_create(liot_mutex_t *mutexRef);
Parameters
mutexRef: [Out] mutex handle.
Return value
See Section 3.1.
4.5.2 liot_rtos_mutex_lock
Lock a mutex. The timeout can be customized.
Declaration
extern LiotOSStatus_t liot_rtos_mutex_lock(liot_mutex_t mutexRef, uint32 timeout);
Parameters
mutexRef: [In] mutex handle.timeout: [In] wait time in milliseconds.0xFFFFFFFFmeans wait forever.
Return value
See Section 3.1.
4.5.3 liot_rtos_mutex_try_lock
Attempt to acquire a mutex in a non-blocking manner. Returns immediately: succeeds if the mutex is available, or fails if the mutex is already held by another task without blocking.
Declaration
extern LiotOSStatus_t liot_rtos_mutex_try_lock(liot_mutex_t mutexRef);
Parameters
mutexRef: [In] mutex handle.
Return value
See Section 3.1.
4.5.4 liot_rtos_mutex_unlock
Unlock a mutex.
Declaration
extern LiotOSStatus_t liot_rtos_mutex_unlock(liot_mutex_t mutexRef);
Parameters
mutexRef: [In] mutex handle.
Return value
See Section 3.1.
4.5.5 liot_rtos_mutex_delete
Delete a mutex.
Declaration
extern LiotOSStatus_t liot_rtos_mutex_delete(liot_mutex_t mutexRef);
Parameters
mutexRef: [In] mutex handle.
Return value
See Section 3.1.
4.6 Message Queues
4.6.1 liot_rtos_queue_create
Create a message queue.
Declaration
extern LiotOSStatus_t liot_rtos_queue_create(liot_queue_t *msgQRef, uint32 maxSize, uint32 maxNumber);
Parameters
msgQRef: [Out] queue handle.maxSize: [In] element size in bytes.maxNumber: [In] queue length, maximum number of elements.
Return value
See Section 3.1.
4.6.2 liot_rtos_queue_wait
Wait for a message in the queue.
Declaration
extern LiotOSStatus_t liot_rtos_queue_wait(liot_queue_t msgQRef,
uint8 *recvMsg,
uint32 size,
uint32 timeout);
Parameters
msgQRef: [In] queue handle.recvMsg: [Out] buffer to receive the message.size: [In] this parameter is ignored and fixed to the queue’smaxSizefor compatibility.timeout: [In] wait time in milliseconds.0xFFFFFFFFmeans wait forever.
Return value
See Section 3.1.
4.6.3 liot_rtos_queue_release
Release a message into the queue. Supports releasing from ISR.
Declaration
extern LiotOSStatus_t liot_rtos_queue_release(liot_queue_t msgQRef,
uint32 size,
uint8 *msgPtr,
uint32 timeout);
Parameters
msgQRef: [In] queue handle.size: [In] ignored for compatibility; fixed to queuemaxSize.msgPtr: [In] pointer to the data to send.timeout: [In] wait time in milliseconds.0xFFFFFFFFmeans wait forever.
Return value
See Section 3.1.
Note: when timeout is 0 and the queue is not full, the message is enqueued immediately. If the queue is full, the function returns an error without blocking.
4.6.4 liot_rtos_queue_get_cnt
Get the number of messages in the queue.
Declaration
extern LiotOSStatus_t liot_rtos_queue_get_cnt(liot_queue_t msgQRef, uint32 *cntPtr);
Parameters
msgQRef: [In] queue handle.cntPtr: [Out] number of messages in the queue.
Return value
See Section 3.1.
4.6.5 liot_rtos_queue_delete
Delete a message queue.
Declaration
extern LiotOSStatus_t liot_rtos_queue_delete(liot_queue_t msgQRef);
Parameters
msgQRef: [In] queue handle.
Return value
See Section 3.1.
4.6.6 liot_rtos_queue_reset
Reset a queue.
Declaration
extern LiotOSStatus_t liot_rtos_queue_reset(liot_queue_t msgQRef);
Parameters
msgQRef: [In] queue handle.
Return value
See Section 3.1.
4.6.7 liot_rtos_queue_get_space
Query available queue space.
Declaration
extern uint32_t liot_rtos_queue_get_space(liot_queue_t msgQRef);
Parameters
msgQRef: [In] queue handle.
Return value
See Section 3.1.
4.7 Timers
4.7.1 liot_rtos_timer_create
Create an RTOS software timer.
Declaration
extern LiotOSStatus_t liot_rtos_timer_create(liot_timer_t *timerRef,
liot_timertype_e cyclicalEn,
void (*callBackRoutine)(void*),
void *timerArgc);
Parameters
timerRef: [Out] timer handle.cyclicalEn: [In] whether periodic mode is enabled.callBackRoutine: [In] timer callback function.timerArgc: [In] timer callback argument.
Return value
See Section 3.1.
4.7.2 liot_rtos_timer_start
Start a timer with millisecond precision. Supports starting from ISR.
Declaration
extern LiotOSStatus_t liot_rtos_timer_start(liot_timer_t timerRef, uint32 setTime);
Parameters
timerRef: [In] timer handle.setTime: [In] timeout in milliseconds.
Return value
See Section 3.1.
4.7.3 liot_rtos_timer_is_running
Check whether a timer is running.
Declaration
extern LiotOSStatus_t liot_rtos_timer_is_running(liot_timer_t timerRef);
Parameters
timerRef: [In] timer handle.
Return value
0: timer is not running.1: timer is running.
4.7.4 liot_rtos_timer_stop
Stop a timer.
Declaration
extern LiotOSStatus_t liot_rtos_timer_stop(liot_timer_t timerRef);
Parameters
timerRef: [In] timer handle.
Return value
See Section 3.1.
4.7.5 liot_rtos_timer_delete
Delete a timer.
Declaration
extern LiotOSStatus_t liot_rtos_timer_delete(liot_timer_t timerRef);
Parameters
timerRef: [In] timer handle.
Return value
See Section 3.1.
4.7.6 liot_rtos_timer_stop_isr
Stop a timer from ISR.
Declaration
extern LiotOSStatus_t liot_rtos_timer_stop_isr(liot_timer_t timerRef);
Parameters
timerRef: [In] timer handle.
Return value
See Section 3.1.
4.8 Event Groups
4.8.1 liot_rtos_flag_create
Create an event group.
Declaration
extern LiotOSStatus_t liot_rtos_flag_create(liot_flag_t *flagRef);
Parameters
flagRef: [Out] event group handle.
Return value
See Section 3.1.
4.8.2 liot_rtos_flag_get
Get the current state of an event group.
Declaration
extern uint32 liot_rtos_flag_get(liot_flag_t flagRef);
Parameters
flagRef: [In] event group handle.
Return value
Event group flags.
4.8.3 liot_rtos_flag_wait
Wait for specific bits in an event group. This allows a task to block until the specified condition is met.
Declaration
extern LiotOSStatus_t liot_rtos_flag_wait(liot_flag_t flagRef, UINT32 mask, liot_flag_op_e operation, UINT32 *flag, UINT32 timeout);
Parameters
flagRef: [In] event group handle.mask: [In] bit mask specifying which bits to wait for.operation: [In] event flag operation. See Section 4.10.flag: [Out] indicates the bits that met the wait condition.timeout: [In] wait timeout.
Return value
See Section 3.1.
4.8.4 liot_rtos_flag_release
Set specific bits in an event group.
Declaration
extern LiotOSStatus_t liot_rtos_flag_release(liot_flag_t flagRef, UINT32 mask, liot_flag_op_e operation);
Parameters
flagRef: [In] event group handle.mask: [In] bit mask specifying which bits to set.operation: [In] event flag operation. See Section 4.10.
Return value
See Section 3.1.
4.8.5 liot_rtos_flag_clear
Clear specific bits in an event group.
Declaration
extern LiotOSStatus_t liot_rtos_flag_clear(liot_flag_t flagRef, UINT32 mask);
Parameters
flagRef: [In] event group handle.mask: [In] bit mask specifying which bits to clear.
Return value
See Section 3.1.
4.8.6 liot_rtos_flag_delete
Delete an event group.
Declaration
extern LiotOSStatus_t liot_rtos_flag_delete(liot_flag_t flagRef);
Parameters
flagRef: [In] event group handle.
Return value
See Section 3.1.
4.9 Others
4.9.1 liot_rtos_rand
Generate a software random number.
Declaration
extern uint32 liot_rtos_rand(void);
Parameters
None.
Return value
Generated random number.
4.9.2 liot_true_rand
Generate a hardware random number, a true random number with higher security.
Declaration
uint32 liot_true_rand(void);
Parameters
None.
Return value
Generated random number.
5 Code Examples
5.1 Full Example Code
This example demonstrates comprehensive RTOS API usage, including tasks, semaphores, message queues, timers, and event groups.
Example source location: examples/demo/src/demo_os.c
5.1.1 Example Description
This example demonstrates the following:
Creating a main task and child tasks
Using semaphores for task synchronization
Using message queues for task communication
Using timers for periodic operations
Using event groups for multi-task synchronization
Getting system uptime and memory usage information
5.1.2 Full Code
/**
* @File Name: liot_os_demo.c
* @brief RTOS API comprehensive usage example
*/
#include <stdio.h>
#include <string.h>
#include "lierda_app_main.h"
#include "liot_os.h"
#include "liot_type.h"
/*
This example demonstrates OS usage. It creates two tasks, one semaphore, and one message queue.
The main task is created first, and the subtask sends messages to the main task.
The main task prints received messages.
The test runs for 10 cycles and then ends.
*/
#define MSG_MAX_SIZE 64
#define MSG_MAX_NUM 10
#define MSG_TO_QUEUE "message from sub task to main task"
static liot_sem_t rtos_test_sem = NULL;
static liot_queue_t rtos_test_queue = NULL;
static liot_timer_t rtos_timer_queue = NULL;
static int test_count = 0;
// Timer callback function
void liot_os_demo_timer_cb(void *argv)
{
liot_rtos_semaphore_release(rtos_test_sem); // Notify subtask that main task has started
liot_trace("TIMER_task start");
liot_rtos_queue_release(rtos_test_queue, strlen(MSG_TO_QUEUE), (u8 *)MSG_TO_QUEUE, 0);
liot_trace("TIMER_task send msg");
}
// Event group handle
liot_flag_t xEventGroupHandle;
// Event bits
#define TASK_1_EVENT (1 << 0) // 0x01
#define TASK_2_EVENT (1 << 1) // 0x02
#define TASK_3_EVENT (1 << 2) // 0x04
#define ALL_TASKS_EVENT (TASK_1_EVENT | TASK_2_EVENT | TASK_3_EVENT) // 0x07
// Task 1 function
void vTask1(void *pvParameters) {
liot_trace("Task1 in");
UINT32 uxBits;
for (;;) {
liot_trace("Task1 1111Received event, starting task...");
// Wait for event
LiotOSStatus_t result = liot_rtos_flag_wait(xEventGroupHandle, TASK_1_EVENT, LIOT_FLAG_AND_CLEAR, &uxBits, LIOT_WAIT_FOREVER);
if (0 == result)
{
if (uxBits & TASK_1_EVENT) {
liot_trace("Task1 Received event, starting task...");
// Execute task
// ...
}
}
}
}
// Task 2 function
void vTask2(void *pvParameters) {
liot_trace("Task2 in");
UINT32 uxBits;
for (;;) {
liot_trace("Task2 22222Received event, starting task...");
// Wait for event
LiotOSStatus_t result = liot_rtos_flag_wait(xEventGroupHandle, TASK_2_EVENT, LIOT_FLAG_AND_CLEAR, &uxBits, LIOT_WAIT_FOREVER);
if (0 == result)
{
if (uxBits & TASK_2_EVENT) {
liot_trace("Task2 Received event, starting task...");
// Execute task
// ...
}
}
}
}
// Task 3 function
void vTask3(void *pvParameters) {
liot_trace("Task3 in");
UINT32 uxBits;
for (;;) {
liot_trace("Task3 333 Received event, starting task...");
LiotOSStatus_t result = liot_rtos_flag_wait(xEventGroupHandle, TASK_3_EVENT, LIOT_FLAG_AND_CLEAR, &uxBits, LIOT_WAIT_FOREVER);
if (0 == result)
{
if (uxBits & TASK_3_EVENT) {
liot_trace("Task3 Received event, starting task...");
// Execute task
// ...
}
}
}
}
// Timer callback function
void vTimerCallback(void *ctx) {
// Release event
liot_rtos_flag_release(xEventGroupHandle, ALL_TASKS_EVENT, LIOT_FLAG_OR);
liot_trace("Released event, notifying all tasks...");
}
/*!
* @brief Test event group synchronization for tasks.
*
* @details This function demonstrates how to use an event group to synchronize multiple tasks with flags.
* Steps:
* 1. Create an event group with liot_rtos_flag_create.
* 2. Create three tasks (vTask1, vTask2, vTask3), each waiting for a specific event flag.
* 3. Create a periodic timer that releases all event flags every 10 seconds.
* Each task waits for its flag, executes when received, and clears the flag.
* The timer callback releases all flags using LIOT_FLAG_OR.
*
* @note This function is for demonstration and testing only.
* Assume the event group and tasks are not reused during execution.
*
* @return None
*/
void liot_group_event_test()
{
// Create event group
LiotOSStatus_t result = liot_rtos_flag_create(&xEventGroupHandle);
if (0 != result) {
liot_trace("main Failed to create event group");
return;
}
liot_trace("main create flag event group");
// Create task 1
liot_task_t task1_handle = NULL;
result = liot_rtos_task_create(&task1_handle, 1024, LIOT_APP_TASK_PRIORITY, "Task1", &vTask1, NULL);
if (result == 0)
{
liot_trace("Task1 task create success %d", result);
}
else
{
liot_trace("Task1 task create fail %d", result);
}
// Create task 2
liot_task_t task2_handle = NULL;
result = liot_rtos_task_create(&task2_handle, 1024, LIOT_APP_TASK_PRIORITY, "Task2", &vTask2, NULL);
if (result == 0)
{
liot_trace("Task2 task create success %d", result);
}
else
{
liot_trace("Task2 task create fail %d", result);
}
// Create task 3
liot_task_t task3_handle = NULL;
result = liot_rtos_task_create(&task3_handle, 1024, LIOT_APP_TASK_PRIORITY, "Task3", &vTask3, NULL);
if (result == 0)
{
liot_trace("Task3 task create success %d", result);
}
else
{
liot_trace("Task3 task create fail %d", result);
}
liot_trace("main create task success");
// Create timer
liot_timer_t timer_handle;
liot_rtos_timer_create(&timer_handle, LIOT_TimerPeriodic, vTimerCallback, NULL);
liot_rtos_timer_start(timer_handle, 10000); // 10 seconds
}
// Main test task
void liot_os_demo_thread(void *argv)
{
test_count = 0;
liot_rtos_task_sleep_ms(5000);
char *msg = liot_rtos_malloc(MSG_MAX_SIZE);
if (msg == NULL)
{
return;
}
memset(msg, 0, MSG_MAX_SIZE);
liot_task_status_s xTaskStatus;
liot_rtos_task_get_status(NULL, &xTaskStatus);
// Get current task information
liot_trace("------------Get Task Info------------ ");
liot_trace("eCurrentState = %d ", xTaskStatus.eCurrentState);
liot_trace("pcTaskName = %s ", xTaskStatus.pcTaskName);
liot_trace("usStackHighWaterMark = %d ", xTaskStatus.usStackHighWaterMark);
liot_trace("uxCurrentPriority = %ld ", xTaskStatus.uxCurrentPriority);
liot_trace("xHandle = %x ", (void *)xTaskStatus.xHandle);
liot_trace("========== rtos systick:%ld", liot_rtos_get_system_tick());
liot_trace("========== rtos run systick:%ld", liot_rtos_get_running_time());
liot_trace("========== rtos rand:%ld", liot_rtos_rand());
liot_trace("========== rtos task is running:%d", liot_rtos_is_alive(NULL));
// Print SRAM information
liot_trace("========== rtos Get TotalHeapSize:%dKB,FreeHeapSize:%dKB,MinFreeHeapSize:%dKB,MaxFreeBlockSize:%dKB",
(liot_xPortGetTotalHeapSize()) >> 10, (liot_xPortGetFreeHeapSize()) >> 10,
(liot_xPortGetMinimumEverFreeHeapSize()) >> 10, (liot_xPortGetMaximumFreeBlockSize()) >> 10);
#if defined (PSRAM_FEATURE_ENABLE) && (PSRAM_EXIST==1)
// Print PSRAM information
liot_trace("========== rtos GetPsram TotalHeapSize:%dKB,FreeHeapSize:%dKB,MinFreeHeapSize:%dKB,MaxFreeBlockSize:%dKB",
(liot_psram_xPortGetTotalHeapSize()) >> 10, (liot_psram_xPortGetFreeHeapSize()) >> 10,
(liot_psram_xPortGetMinimumEverFreeHeapSize()) >> 10, (liot_psram_xPortGetMaximumFreeBlockSize()) >> 10);
#endif
// Create semaphore
liot_rtos_semaphore_create(&rtos_test_sem, 0);
// Create message queue
liot_rtos_queue_create(&rtos_test_queue, MSG_MAX_SIZE, MSG_MAX_NUM);
// Create timer
liot_rtos_timer_create(&rtos_timer_queue, 1, liot_os_demo_timer_cb, NULL);
liot_rtos_timer_start(rtos_timer_queue, 5000);
// Main loop
while (test_count <= 10)
{
liot_trace("main_task start");
liot_rtos_semaphore_wait(rtos_test_sem, 0xFFFFFFFF); // Wait for main task startup
liot_rtos_queue_wait(rtos_test_queue, (u8 *)msg, MSG_MAX_SIZE, 0xFFFFFFFF); // Wait for message from subtask
liot_trace("main_task recv msg: %s,test_count %d", msg, test_count);
test_count += 1;
memset(msg, 0, MSG_MAX_SIZE);
liot_rtos_task_sleep_ms(1000);
}
// Get task status
liot_rtos_task_get_status(NULL, &xTaskStatus);
liot_trace("------------Get Task Info------------ ");
liot_trace("eCurrentState = %d ", xTaskStatus.eCurrentState);
liot_trace("pcTaskName = %s ", xTaskStatus.pcTaskName);
liot_trace("usStackHighWaterMark = %d ", xTaskStatus.usStackHighWaterMark);
liot_trace("uxCurrentPriority = %ld ", xTaskStatus.uxCurrentPriority);
liot_trace("xHandle = %x ", (void *)xTaskStatus.xHandle);
liot_trace("------------Get Task Info------------ ");
// Release resources
liot_rtos_free(msg);
liot_trace("delete main task");
liot_rtos_semaphore_delete(rtos_test_sem);
rtos_test_sem = NULL;
liot_rtos_queue_delete(rtos_test_queue);
rtos_test_queue = NULL;
liot_rtos_timer_delete(rtos_timer_queue);
rtos_timer_queue = NULL;
// Event group test
liot_group_event_test();
// Keep running
while (1)
{
liot_rtos_task_sleep_ms(1000);
}
}
5.1.3 Execution Result
