OpenCPU开发例程的详细解释,包括各种功能的测试,如线程、队列等 源代码为osi_demo.c
初步学习,可能有误,仅供参考
demo详解
代码
/* Copyright (C) 2022 FIBOCOM Technologies Limited and/or its affiliates("FIBOCOM").
* All rights reserved.
*
* This software is supplied "AS IS" without any warranties.
* FIBOCOM assumes no responsibility or liability for the use of the software,
* conveys no license or title under any patent, copyright, or mask work
* right to the product. FIBOCOM reserves the right to make changes in the
* software without notification. FIBOCOM also make no representation or
* warranty that such application will be suitable for the specified use
* without further testing or modification.
*/
#define OSI_LOG_TAG OSI_MAKE_LOG_TAG('M', 'Y', 'A', 'P')
#include "fibo_opencpu.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef __uint32_t uint32_t ;
static void prvInvokeGlobalCtors(void)
{
extern void (*__init_array_start[])();
extern void (*__init_array_end[])();
size_t count = __init_array_end - __init_array_start;
for (size_t i = 0; i < count; ++i)
__init_array_start[i]();
}
static void test_ticks()
{
UINT32 ticks = 0;
ticks = fibo_get_sys_tick();
fibo_textTrace("before ticks = %u", ticks);
fibo_taskSleep(1000);
ticks = fibo_get_sys_tick();
fibo_textTrace("after ticks = %u", ticks);
}
uint32_t g_size;
uint32_t g_avail_size;
uint32_t g_max_block_size;
static void test_mem()
{
char *pt = (char *)fibo_malloc(51200);
if (pt != NULL)
{
fibo_textTrace("malloc address %u", (unsigned int)pt);
fibo_free(pt);
}
fibo_heapinfo_get(&g_size, &g_avail_size, &g_max_block_size);
fibo_textTrace("g_size = %u, g_avail_size = %u, g_max_block_size = %u", g_size, g_avail_size, g_max_block_size);
}
static void test_reset(int mode)
{
if (mode == 0)
fibo_soft_reset();
else
fibo_soft_power_off();
}
/* sem test begin */
UINT32 g_test_sem;
static void testSemThread(void *param)
{
fibo_taskSleep(2000);
fibo_textTrace("execute sem_signal...");
fibo_sem_signal(g_test_sem);
fibo_taskSleep(1000);
fibo_sem_signal(g_test_sem);
fibo_thread_delete();
}
static void test_sem()
{
g_test_sem = fibo_sem_new(0);
fibo_thread_create(testSemThread, "test_sem", 1024, NULL, OSI_PRIORITY_NORMAL);
fibo_sem_wait(g_test_sem);
fibo_textTrace("after sem_wait...");
fibo_sem_try_wait(g_test_sem, 5000);
fibo_textTrace("after sem_try_wait...");
fibo_sem_try_wait(g_test_sem, 5000);
fibo_textTrace("after sem_try_wait...");
fibo_sem_free(g_test_sem);
}
/* sem test end */
/* mutex test begin */
UINT32 g_test_mutex;
static void test_mutex()
{
g_test_mutex = fibo_mutex_create();
fibo_textTrace("after mutex create...");
fibo_mutex_lock(g_test_mutex);
fibo_textTrace("after mutex lock...");
fibo_mutex_unlock(g_test_mutex);
fibo_textTrace("after mutex unlock...");
fibo_mutex_try_lock(g_test_mutex, 3000);
fibo_textTrace("after mutex try lock...");
fibo_mutex_delete(g_test_mutex);
fibo_textTrace("after mutex delete...");
}
/* mytex test end */
/* test timer begin */
void *g_test_timer = NULL;
void *g_test_timer2 = NULL;
void *g_period_timer = NULL;
void *g_period_timer2 = NULL;
void timer_function(void *arg)
{
fibo_textTrace("timer function execute ...");
fibo_timer_delete(g_test_timer);
}
void test_timer()
{
g_test_timer = fibo_timer_create(timer_function, NULL, false);
fibo_textTrace("test_timer_creat 1...");
fibo_timer_start(g_test_timer, 6000, false);
}
void timer_function2(void *arg)
{
fibo_textTrace("timer function2 execute ...");
fibo_timer_delete(g_test_timer2);
}
void test_timer2()
{
g_test_timer2 = fibo_timer_create(timer_function2, NULL, false);
fibo_textTrace("test_timer_creat 2");
fibo_timer_start(g_test_timer2, 6000, false);
}
void timer_function_period(void *arg)
{
static int nr = 5;
fibo_textTrace("timer period function execute ...");
nr--;
if(nr == 0)
fibo_timer_delete(g_period_timer);
}
void test_timer_period()
{
g_period_timer = fibo_timer_create(timer_function_period, NULL, false);
fibo_timer_start(g_period_timer, 3000, true);
}
void timer_function_period2(void *arg)
{
static int nr = 5;
fibo_textTrace("timer period function2 execute cnt: %d...", nr);
nr--;
if(nr == 0)
{
fibo_timer_delete(g_period_timer2);
}
}
void test_timer_period2()
{
g_period_timer2 = fibo_timer_create(timer_function_period2, NULL, false);
fibo_textTrace("test_timer_period2 ...");
fibo_timer_start(g_period_timer2, 3000, true);
}
/* test timer end */
void test_rand()
{
srand(1000);
for (int i = 0; i < 10; i++)
{
fibo_textTrace("rand %d : %d", i, rand());
}
}
/* test queue */
UINT32 g_queue_id = 0;
static void testQueueThread(void *param)
{
int value = 8888;
fibo_taskSleep(2000);
fibo_queue_put(g_queue_id, &value, 0);
fibo_thread_delete();
}
void test_queue()
{
int value = 0;
g_queue_id = fibo_queue_create(5, sizeof(int));
fibo_thread_create(testQueueThread, "test_queue", 4096, NULL, OSI_PRIORITY_NORMAL);
fibo_queue_get(g_queue_id, (void *)&value, 0);
fibo_textTrace("test queue value = %d", value);
}
UINT32 g_queue_id2 = 0;
static void testQueueThread2(void *param)
{
int i = 0;
int value = 1111;
fibo_taskSleep(2000);
for (i = 1; i < 10; i++)
{
value = 1111 *i;
fibo_queue_put_to_front(g_queue_id2, &value, 0);
fibo_textTrace("test queue2 value put to front(%d) = %d", i, value);
}
fibo_thread_delete();
}
void test_queue2()
{
int value = 0;
g_queue_id2 = fibo_queue_create(10, sizeof(int));
fibo_thread_create(testQueueThread2, "test_queue2", 4096, NULL, OSI_PRIORITY_NORMAL);
fibo_taskSleep(5000);
for (int i = 1; i < 10; i++)
{
fibo_queue_get(g_queue_id2, (void *)&value, 0);
fibo_textTrace("test queue2 value get(%d) = %d", i, value);
}
}
/* test queue end */
static void nullThread(void *param)
{
for (int n = 0; n < 5; n++)
{
fibo_textTrace("null Thread in %d", n);
fibo_taskSleep(1000);
}
fibo_thread_delete();
}
static void oc_osi_demo(void *param)
{
fibo_textTrace("application thread enter, param 0x%x", param);
test_ticks(); //测试时钟函数
test_mem(); //测试内存管理函数
test_sem(); //测试信号量函数
test_mutex(); //测试互斥锁函数
test_timer(); //测试定时器函数
test_timer2();
test_rand(); //随机数
test_queue(); //队列
test_queue2();
test_timer_period(); //周期性定时函数
test_timer_period2();
test_reset(0); //复位函数
for (int n = 0; n < 10; n++)
{
fibo_textTrace("hello world %d", n);
fibo_taskSleep(1000);
}
fibo_taskSleep(1000);
//test_reset(0);
UINT32 thread_id = 0;
fibo_thread_create_ex(nullThread, "nullthread",
1024, NULL, OSI_PRIORITY_NORMAL, &thread_id); //创建一个新线程并打印线程ID
fibo_textTrace("nullThread id = 0x%x", thread_id);
fibo_thread_delete(); //删除线程
}
void* appimg_enter(void *param) //入口函数
{
fibo_textTrace("application image enter, param 0x%x", param);
prvInvokeGlobalCtors();
fibo_thread_create(oc_osi_demo, "oc_osi_demo", 1024, NULL, OSI_PRIORITY_NORMAL);
return 0;
}
void appimg_exit(void) //退出函数
{
fibo_textTrace("application image exit");
}
部分系统函数
fibo_textTrace(输出日志)
INT32 fibo_textTrace
(
char *fmt, …
)
TRACE 输出的接口。从抓 LOG 的工具 coolwatcher 输出,fmt 字符串长度最大 255。
fibo_thread_create(创建线程)
(
void* pvTaskCode,
INT8 * pcName,
UINT32 usStackDepth,
void *pvParameters,
UINT32 uxPriority
)
任务函数接口
任务名称
任务栈大小,接口 U32 类型数据,理论可申请0xFFFFFFFF 这么大的栈空间,实际单个最大可 250K 左右,内存一般剩余 2M 多空间
任务函数输入参数
任务优先级
fibo_heapinfo_get(获取内存堆信息)
- 是一个函数,它用于获取当前系统内存堆的信息,返回值是一个指向结构体
fibo_heap_info_t
的指针,结构体fibo_heap_info_t
包含以下字段: total_size
:表示当前系统内存堆的总大小(单位:字节)。used_size
:表示当前系统内存堆已被使用的大小(单位:字节)。max_free_size
:表示当前系统内存堆中最大可用内存块的大小(单位:字节)。frag_size
:表示当前系统内存堆中内存碎片的大小(单位:字节)。
调用 fibo_heapinfo_get()
函数可以获取当前系统内存堆的信息,方便开发者进行内存管理和优化。通常在调试和优化阶段使用该函数,可以帮助开发者发现内存泄漏、内存碎片等问题。
fibo_sem_signal(信号量操作)
信号量+1,信号量为一个 UINT8 的值,使用时需要保证其不会溢出
fibo_sem_wait
信号量-1,当信号量为0时产生进程调度操作
fibo_sem_try_wait
与上述一致,但是增加了超时机制
fibo_malloc(申请内存)
举例:char *pt = (char *)fibo_malloc(51200);
获取内存地址:fibo_textTrace(“malloc address %u”, (unsigned int)pt);
释放内存:fibo_free(pt);
函数
appimg_enter(入口函数)
void* appimg_enter(void *param)
{
fibo_textTrace("application image enter, param 0x%x", param);
prvInvokeGlobalCtors();//初始化全局静态构造函数
fibo_thread_create(oc_osi_demo, "oc_osi_demo", 1024, NULL, OSI_PRIORITY_NORMAL);
return 0;
}
所有代码都会从入口函数开始执行,先初始化,再创建主线程
prvInvokeGlobalCtors(初始化)
static void prvInvokeGlobalCtors(void)
{
extern void (*__init_array_start[])();
extern void (*__init_array_end[])();
size_t count = __init_array_end - __init_array_start;
for (size_t i = 0; i < count; ++i)
__init_array_start[i]();
}
这段代码的作用是调用全局静态构造函数(Global Static Constructor),也被称为初始化函数。全局静态构造函数是在程序启动时自动调用的一些函数,它们用于初始化全局静态变量或执行一些其他的初始化工作。
这段代码中,首先声明了两个外部变量 __init_array_start[]
和 __init_array_end[]
,它们是在链接器脚本(Linker Script)中定义的符号,用于指示存储在程序的 .init_array 段中的初始化函数的起始地址和结束地址。在 C++ 中,全局静态构造函数是按照它们在 .init_array 段中出现的顺序来调用的。
接下来,代码计算了存储在 .init_array 段中的初始化函数的数量(即 count = __init_array_end - __init_array_start
)。然后,通过一个 for 循环依次调用这些初始化函数,从而完成全局静态构造函数的调用过程。
这段代码是用于调用全局静态构造函数的,一般来说在标准 C/C++ 环境下编写的程序中都会包含这段代码。但是在嵌入式开发中,是否必须依赖于具体的开发环境和目标平台。
test_sem_thread(测试线程)
static void testSemThread(void *param)
{
fibo_taskSleep(2000);
fibo_textTrace("execute sem_signal...");
fibo_sem_signal(g_test_sem);
fibo_taskSleep(1000);
fibo_sem_signal(g_test_sem);
fibo_thread_delete();
}
test_sem(测试信号量)
static void test_sem()
{
g_test_sem = fibo_sem_new(0);
fibo_thread_create(testSemThread, "test_sem", 1024, NULL, OSI_PRIORITY_NORMAL);
fibo_sem_wait(g_test_sem);
fibo_textTrace("after sem_wait...");
fibo_sem_try_wait(g_test_sem, 5000);
fibo_textTrace("after sem_try_wait...");
fibo_sem_try_wait(g_test_sem, 5000);
fibo_textTrace("after sem_try_wait...");
fibo_sem_free(g_test_sem);
}
- 这段代码的执行顺序如下:
- 主线程中创建一个初始值为0的信号量g_test_sem。
- 主线程创建一个名为"test_sem"的新线程testSemThread,并将信号量g_test_sem作为参数传递给该线程。
- testSemThread线程等待2秒钟,然后执行第一次信号量信号操作:使用fibo_sem_signal函数释放g_test_sem信号量。
- 主线程中调用fibo_sem_wait函数等待信号量g_test_sem。
- 当testSemThread释放g_test_sem信号量时,主线程的fibo_sem_wait函数返回,主线程输出"after sem_wait…"。
- 主线程中使用fibo_sem_try_wait函数尝试等待g_test_sem信号量,等待时间为5秒。
- testSemThread线程执行第二次信号量信号操作:使用fibo_sem_signal函数再次释放g_test_sem信号量。
- 主线程的fibo_sem_try_wait函数尝试等待g_test_sem信号量时,因为信号量已经被释放,所以不会等待,fibo_sem_try_wait函数返回0,主线程输出"after sem_try_wait…"。
- 主线程中再次使用fibo_sem_try_wait函数尝试等待g_test_sem信号量,等待时间为5秒。
- 因为g_test_sem信号量已经被释放,主线程的fibo_sem_try_wait函数不会等待,直接返回0,主线程输出"after sem_try_wait…"。
- 主线程释放g_test_sem信号量,并使用fibo_sem_free函数释放信号量内存。
- testSemThread线程调用fibo_thread_delete函数结束线程的执行。
test_queue2 (测试队列)
UINT32 g_queue_id2 = 0;
static void testQueueThread2(void *param)
{
int i = 0;
int value = 1111;
fibo_taskSleep(2000);
for (i = 1; i < 10; i++)
{
value = 1111 *i;
fibo_queue_put_to_front(g_queue_id2, &value, 0);
fibo_textTrace("test queue2 value put to front(%d) = %d", i, value);
}
fibo_thread_delete();
}
void test_queue2()
{
int value = 0;
g_queue_id2 = fibo_queue_create(10, sizeof(int));
fibo_thread_create(testQueueThread2, "test_queue2", 4096, NULL, OSI_PRIORITY_NORMAL);
fibo_taskSleep(5000);
for (int i = 1; i < 10; i++)
{
fibo_queue_get(g_queue_id2, (void *)&value, 0);
fibo_textTrace("test queue2 value get(%d) = %d", i, value);
}
}
程序实现了在主线程中创建一个线程,在该线程中创建队列后返回主线程打印的功能
执行顺序为
- 在主线程中创建一个队列 g_queue_id2,大小为 10,元素类型为 int;
- 在主线程中创建一个名为 testQueueThread2 的线程,优先级为正常优先级,栈大小为 4096;
- testQueueThread2 线程启动,等待 2s 后开始执行以下循环: a. 将 value 设为 1111*i; b. 将 value 放入队列 g_queue_id2 的队首; c. 打印输出 “test queue2 value put to front(%d) = %d”;
- 主线程等待 5s;
- 在主线程中进行以下循环,共执行 9 次: a. 从队列 g_queue_id2 的队首取出一个元素,存储到 value 中; b. 打印输出 “test queue2 value get(%d) = %d”;
- 程序执行结束。