涂鸦 Wi-Fi SDK开发系列教程——6.TuyaOS API 接口函数介绍

本文主要介绍和 tuya iot os API相关的函数接口,内容主要包括:

  1. Log打印和错误码介绍
  2. 线程
  3. 软件定时器
  4. 内存管理
  5. 信号量
  6. 互斥量
  7. 队列

本文 github 仓库地址:https://github.com/Tuya-Community/tuya-os-api-examples

如何编译这些 examples 呢?

这里以编译 log_print_demo 为例进行演示。
在这里插入图片描述

1. log 打印和错误码介绍

1.1 错误码

错误码的作用:当在 SDK 开发过程中遇到程序执行错误的情况时,可以根据返回的错误码判断程序出现的问题。

错误码的位置:可以在 tuya_iot_sdk 下的 /sdk/include/tuya_error_code.h 中可找到对应的 error code。

1.2 log 日志

log 日志存放位置:在 tuya iot sdk 中和日志相关的文件为 uni_log.h,该文件位置通常在tuya_iot_sdk 下的 /sdk/include/uni_log.h

日志打印接口和日志等级接口:log 打印中常用到的函数接口为日志打印接口和日志等级接口。日志打印接口可以根据输出信息的等级不同选择不同的打印接口,还可以通过修改 log 输出等级从而控制不同等级信息的输出;同时可以用日志等级接口设置调整打印输出等级,SDK 中默认的日志等级为 DEBUG ,打印输出的东西越多系统占用的资源也就越多,会拖慢系统运行的速度和占用更多的内存,所以在功能开发完成后的正式版本中建议将日志等级设置为NOTICE

日志打印接口如下:

函数接口函数说明
PR_ERR(fmt, ...)用于打印错误信息,程序正常运行不应发生的信息
PR_WARN(fmt, ...)用于打印警告信息
PR_NOTICE(fmt, ...)用于打印需要注意的信息
PR_INFO(fmt, ...)用于打印通知信息
PR_DEBUG(fmt, ...)用于打印程序运行调试信息
PR_TRACE(fmt, ...)用于打印程序运行路径信息

日志等级接口如下:


OPERATE_RET SetLogManageAttr(IN CONST LOG_LEVEL curLogLevel);

设置 log 日志输出等级,等级越高输出信息也就越多。也就是说如果日志等级设置为 TY_LOG_LEVEL_TRACE 那么会打印所有信息,设置为 TY_LOG_LEVEL_NOTICE 则只会打印 NOTICE, WARN, ERR 三种日志信息。

Parameters:

  • curLogLevel: 设置的 log 等级。可设置值为:

    #define TY_LOG_LEVEL_ERR       0
    #define TY_LOG_LEVEL_WARN      1
    #define TY_LOG_LEVEL_NOTICE    2
    #define TY_LOG_LEVEL_INFO      3
    #define TY_LOG_LEVEL_DEBUG     4
    #define TY_LOG_LEVEL_TRACE     5
    

Return:

  • OPRT_OK: 函数执行成功
  • other: 函数执行失败

1.3 应用示例

日志打印和设置不同日志等级的输出情况示例:根据执行的日志截图可以发现,当把日志等级设置为TY_LOG_LEVEL_NOTICE时,只有PR_NOTICE, PR_WARNPR_ERR 可以打印出来,而其他三个无法输出;当把日志等级设置为TY_LOG_LEVEL_DEBUG时,只有PR_DEBUG, PR_INFO, PR_NOTICE, PR_WARNPR_ERR 可以打印出来,而PR_TRACE无法输出。

点击到 GitHub 查看完整工程代码

void log_printf_demo(void)
{
    PR_NOTICE("*************************************************");
    SetLogManageAttr(TY_LOG_LEVEL_NOTICE);
    PR_NOTICE("log level is NOTICE");
    PR_ERR("This is error log");
    PR_WARN("This is warn log");
    PR_NOTICE("This is notice log");
    PR_INFO("This is info log");
    PR_DEBUG("This is debug log");
    PR_TRACE("This is trace log");
    PR_NOTICE("*************************************************");
    SetLogManageAttr(TY_LOG_LEVEL_DEBUG);
    PR_NOTICE("log level is DEBUG");
    PR_ERR("This is error log");
    PR_WARN("This is warn log");
    PR_NOTICE("This is notice log");
    PR_INFO("This is info log");
    PR_DEBUG("This is debug log");
    PR_TRACE("This is trace log");
    PR_NOTICE("*************************************************");
}

log_print_demo

2.线程(系统)

线程的文件位置:在tuya_iot_sdk 下的 /sdk/include/tuya_hal_thread.h

在 TuyaOS 中与线程相关的函数主要有四个接口可用,创建线程 tuya_hal_thread_create(),释放线程 tuya_hal_thread_release(),检查线程是否是本身 tuya_hal_thread_is_self() 和设置自身线程名称 tuya_hal_thread_set_self_name()

2.1 tuya_hal_thread_create()


int tuya_hal_thread_create(THREAD_HANDLE* thread,
                           const char* name,
                           uint32_t stack_size,
                           uint32_t priority,
                           THREAD_FUNC_T func,
                           void* const arg);

在 OS 中最常使用的便是该函数了,该函数的功能是用来创建一个线程。

Parameters:

  • thread: [out]线程句柄。

  • name: 线程的名字。

  • stack_size: 线程的栈大小,单位:bit。

  • priority: 线程的优先级。

    /* 这些关于优先级的宏定义在 /sdk/include/uni_thread.h 中,所以使用它们的时候,注意添加 uni_thread.h 的头文件 */
    #define TRD_PRIO_0     5    /* High */
    #define TRD_PRIO_1     4
    #define TRD_PRIO_2     3
    #define TRD_PRIO_3     2
    #define TRD_PRIO_4     1
    #define TRD_PRIO_5     0
    #define TRD_PRIO_6     0    /* low */
    
  • func: 线程入口函数。

  • arg: 线程入口函数的参数,可以为NULL

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

2.2 tuya_hal_thread_release()


int tuya_hal_thread_release(THREAD_HANDLE thread);

释放创建的线程。

Parameters:

  • thread: 线程句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

2.3 tuya_hal_thread_is_self()


int tuya_hal_thread_is_self(THREAD_HANDLE thread, BOOL_T* is_self);

用于判断当前执行线程是否为 thread 线程。

Parameters:

  • thread: 线程句柄。
  • is_self: [out] is_self == 1 当前执行的线程是 thread (这里的 thread 是指调用该函数时具体输入的线程句柄,而并非真的就是 thread);is_self == 0 当前执行的线程不是 thread

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

2.4 tuya_hal_thread_set_self_name()


int tuya_hal_thread_set_self_name(const char* name);

更改自身线程的名字。

Parameters:

  • name: 该线程要设置的名字。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

2.5 应用示例

鉴于在实际开发中创建线程和释放线程函数比较常用,检查线程是否是本身和设置自身线程名称函数使用较少。下面 demo 主要演示如何创建和释放线程:

在Demo 中创建了一个名字叫 thread demo 的线程,这个线程主要做的是打印运行提示和线程运行的计数值thread_demo_count,当计数大于10的时候会将thread demo 的线程释放掉,也就不会在打印了。

点击到 GitHub 查看完整工程代码

#include "uni_log.h"
#include "uni_thread.h"
#include "tuya_error_code.h"
#include "tuya_hal_system.h"

#include "thread_demo.h"

THREAD_HANDLE thread_demo_handle = NULL;
static thread_demo_count = 0;

void thread_demo_task_func(void)
{
    OPERATE_RET op_ret = OPRT_OK;

    for (;;) {
        PR_NOTICE("thread demo is running, count: %d", thread_demo_count);
        if (thread_demo_count >= 10) {
            break;
        }

        thread_demo_count++;
        tuya_hal_system_sleep(1000);
    }

    PR_NOTICE("thread demo task will release");
    op_ret = tuya_hal_thread_release(thread_demo_handle);
    if (OPRT_OK != op_ret) {
        PR_ERR("release thread demo task failed, err_num:%d", op_ret);
        return;
    }
}

void thread_demo_init(void) 
{
    OPERATE_RET op_ret = OPRT_OK;

    op_ret = tuya_hal_thread_create(&thread_demo_handle, "thread demo", 64*8, TRD_PRIO_4, thread_demo_task_func, NULL);
    if (op_ret != OPRT_OK) {
        PR_ERR("creat thread demo task failed, err_num:%d", op_ret);
        return;
    }
}

thread_demo

3.软件定时器(系统)

软件定时器的文件位置:在tuya_iot_sdk 下的 /sdk/include/sys_timer.h

在TuyaOS 中与软件定时器相关的接口一共有 12 个,可以看到软件定时器的接口较多,所以下面将会对其进行简单分类后再介绍。

第一部分:软件定时器的初始化和释放;

第二部分:软件定时器的常用功能。如软件定时器的添加、启动、停止、删除和判断软件定时器是否在运行;

第三部分:TuyaOS 软件定时器的其他功能。如触发一个软件定时器、得到软件定时器的个数、得到和设置软件定时器的休眠间隔和设置软件定时器的栈大小。

3.1 软件定时器的初始化和释放

由于软件定时器的初始化在 SDK 中就已经完成,后续建议不要再对软件定时器进行初始化和释放了,以下两个函数在开发过程中一般无需调用。

3.1.1 system_timer_init()

OPERATE_RET system_timer_init(void);

软件定时器初始化。SDK 启动过程中已经初始化过了,用户在使用过程中不用再次进行初始化。

Parameters:

  • NULL

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。


3.1.2 system_timer_release()

OPERATE_RET system_timer_release(void);

释放软件定时器的资源。这个接口是与 system_timer_init 相对应的。

Parameters:

  • NULL

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。


3.2 软件定时器的常用功能

这里的接口是我们在实际开发中使用频率较高的一些函数接口。

3.2.1 sys_add_timer()

OPERATE_RET sys_add_timer(IN CONST P_TIMER_FUNC pTimerFunc,\
                          IN CONST PVOID_T pTimerArg,\
                          OUT TIMER_ID *p_timerID);

添加一个软件定时器。

Parameters:

  • pTimerFunc: 回调函数。
  • pTimerArg: 回调函数参数。
  • p_timerID: [OUT]软件定时器ID。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

3.2.2 sys_start_timer()

OPERATE_RET sys_start_timer(IN CONST TIMER_ID timerID,\
                            IN CONST TIME_MS timeCycle,\
                            IN CONST TIMER_TYPE timer_type);

启动一个软件定时器。

Parameters:

  • timerID: 软件定时器ID。
  • timeCycle: 定时时间,单位:MS。
  • timer_type: 定时器类型,可通过这里配置定时器是单次模式TIMER_ONCE,还是循环模式TIMER_CYCLE

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

3.2.3 sys_stop_timer()

OPERATE_RET sys_stop_timer(IN CONST TIMER_ID timerID);

停止一个定时器。与删除不同的是,定时器停止后可以使用 sys_start_timer() 而不用添加定时器就再次启动该定时器,当然相关资源的占用依然存在。

Parameters:

  • timerID: 软件定时器ID。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

3.2.4 sys_delete_timer()

OPERATE_RET sys_delete_timer(IN CONST TIMER_ID timerID);

删除一个定时器。删除后,如果想要再次启动该定时器,需要先使用 sys_add_timer() 成功添加定时器,才能再次启动。

Parameters:

  • timerID: 软件定时器ID。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

3.2.5 IsThisSysTimerRun()

BOOL_T IsThisSysTimerRun(IN CONST TIMER_ID timer_id);

判断一个定时器是否在运行。

Parameters:

  • timer_id: 软件定时器ID。

Return:

  • TRUE: 定时器在运行。
  • FAIL: 定时器没有在运行。

3.2.6 应用示例

应用示例功能说明:添加并启动一个软件定时器,等到软件定时器执行10次后,关闭软件定时器。

点击到 GitHub 查看完整工程代码

#include "software_timer.h"
#include "uni_log.h"
#include "uni_thread.h"
#include "sys_timer.h"

TIMER_ID my_timer_id;
static int sw_run_count = 0;

void my_timer_cb(UINT_T timerID, PVOID_T pTimerArg)
{
    OPERATE_RET op_ret = OPRT_OK;

    PR_NOTICE("------this is timer %d callback, count: %d", timerID, sw_run_count);
    sw_run_count++;

    if (sw_run_count >= 10) {
        if (IsThisSysTimerRun(my_timer_id)) {
            op_ret = sys_stop_timer(my_timer_id);
            if (OPRT_OK != op_ret) {
                PR_ERR("sys stop timer failed, error code %d", op_ret);
                return;
            }
            PR_NOTICE("timer %d is stop.", my_timer_id);
        }
    }
}

void sw_timer_task(void)
{
    OPERATE_RET op_ret = OPRT_OK;

    op_ret = sys_add_timer(my_timer_cb, NULL, &my_timer_id);
    if (OPRT_OK != op_ret) {
        PR_ERR("sys add timer failed, error code %d", op_ret);
        return;
    }
    PR_NOTICE("timer add success, timer id: %d.", my_timer_id);

    op_ret = sys_start_timer(my_timer_id, 2000, TIMER_CYCLE);
    if (OPRT_OK != op_ret) {
        PR_ERR("sys start timer failed, error code %d", op_ret);
        return;
    }
    PR_NOTICE("timer %d start success.", my_timer_id);
}

sw_timer_demo

3.3 软件定时器的其他功能

相对来说这里的函数使用到的频率很低了。

3.3.1 sys_trigger_timer()

OPERATE_RET sys_trigger_timer(IN CONST TIMER_ID timerID);

立刻触发该定时器。

Parameters:

  • timerID: 软件定时器ID。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

3.3.2 sys_get_timer_num()

INT_T sys_get_timer_num(void);

得到当前活跃的软件定时器个数(启动的定时器个数,停止和删除的定时器不算)。

Parameters:

  • NULL

Return:

  • 当前活跃的定时器个数。

3.3.3 system_timer_get_sleep_interval()

ULONG_T system_timer_get_sleep_interval(VOID);

获取定时器的最小间隔。

Parameters:

  • NULL

Return:

  • 获取定时器的最小间隔。

3.3.4 system_timer_set_sleep_interval()

VOID system_timer_set_sleep_interval(ULONG_T interval);

设置定时的最小休眠间隔。

Parameters:

  • interval: 要设置的最小睡眠间隔。

Return:

  • NULL

3.3.5 system_timer_cfg_stack_size()

OPERATE_RET system_timer_cfg_stack_size(UINT_T stack_size);

设置软件定时器的栈大小。一般默认即可,非必要不要进行修改。

Parameters:

  • stack_size: 配置软件定时器的栈大小。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

4.内存管理(系统)

内存管理的文件位置:在tuya_iot_sdk 下的 /sdk/include/tuya_hal_memory.h

TuyaOS 中关于内存管理的 API 特别简单,只有申请和释放两个。

4.1 tuya_hal_system_malloc()


VOID_T *tuya_hal_system_malloc(CONST SIZE_T size);

用于分配内存。

Parameters:

  • size: 要申请的栈空间大小。

Return:

  • NULL: 内存申请失败。
  • other: 内存成功申请到的地址。

4.2 tuya_hal_system_free()


VOID_T tuya_hal_system_free(VOID_T* ptr);

释放申请到的内存。

Parameters:

  • ptr: 需要释放的内存指针。

Return:

NULL


4.3 应用示例

应用示例说明:演示内存申请和释放函数的使用方法。在Demo 中会申请3个int 的内存大小,然后把前两个进行赋值,打印申请到的地址和内存中存的数据。

点击到 GitHub 查看完整工程代码

OPERATE_RET device_init(VOID) 
{
    int *str;

    PR_NOTICE("******************** memory demo begin ********************");
    str = tuya_hal_system_malloc(5*sizeof(int));
    if (NULL == str) {
        PR_ERR("tuya_hal_system_malloc is error");
        return;
    }
    PR_NOTICE("memset");
    memset(str, 0, 5*sizeof(int));
    str[0] = 300;
    str[1] = 200;
    PR_NOTICE("str address: %x", str);
    PR_NOTICE("str[0]:%d, str[1]:%d, str[2]:%d", str[0], str[1], str[2]);
    if (NULL != str) {
        PR_NOTICE("memory will free");
        tuya_hal_system_free(str);
        str = NULL;
        PR_NOTICE("******************** memory demo end ********************");
    }

    return OPRT_OK;
}

memory_demo

5.信号量(系统)

信号量的文件位置:在tuya_iot_sdk 下的 /sdk/include/tuya_hal_semaphore.h

信号量常用于对共享资源的访问控制和任务同步。

5.1 tuya_hal_semaphore_create_init()


INT_T tuya_hal_semaphore_create_init(SEM_HANDLE *pHandle, CONST UINT_T semCnt, CONST UINT_T sem_max);

创建并初始化一个信号量。

Parameters:

  • pHandle: [OUT]信号量句柄。
  • semCnt: 开始时的信号量个数。
  • sem_max: 信号量的最大个数。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

5.2 tuya_hal_semaphore_release()


INT_T tuya_hal_semaphore_release(CONST SEM_HANDLE semHandle);

释放一个信号量的资源,与 tuya_hal_semaphore_create_init() 函数相对应。

Parameters:

  • semHandle: 要释放资源的信号量句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

5.3 tuya_hal_semaphore_wait()


INT_T tuya_hal_semaphore_wait(CONST SEM_HANDLE semHandle);

等待一个信号量。调用这个函数它会消耗一个信号量(信号量-1),如果信号量为 0 的话(信号量不能为负的),它会阻塞到这里等待信号量。

Parameters:

  • semHandle: 信号量句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

5.4 tuya_hal_semaphore_waittimeout()


INT_T tuya_hal_semaphore_waittimeout(CONST SEM_HANDLE semHandle, unsigned int timeout);

等待一个信号量,带有超时功能。很容易发现的是,和上一个函数的不同在于它多了一个超时的设定,也就是说它不会想上一个函数一样一直阻塞到这里等待信号量到达的,到达一定的超时时间它就不再阻塞等待了。

Parameters:

  • semHandle: 信号量句柄。
  • timeout: 等待超时时间。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

5.5 tuya_hal_semaphore_post()


INT_T tuya_hal_semaphore_post(CONST SEM_HANDLE semHandle);

放入一个信号量。(信号量+1)

Parameters:

  • semHandle: 信号量句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

5.6 应用示例

需要再次一提的是关于 tuya_hal_semaphore_create_init()tuya_hal_semaphore_release() 这两个函数,creat 函数创建了一个信号量,release 函数则是在该信号量使用完成后对信号量的资源的一个回收作用,也就是释放该信号了的资源然后把它删除掉的意思。

应用示例说明:创建两个任务,一个任务创建一个信号量并每 5s post 一个信号量;另一个任务等待信号量,接收到信号量后会打印一个 hello 出来。

点击到 GitHub 查看完整工程代码

#include "sem.h"
#include "uni_log.h"
#include "uni_thread.h"
#include "tuya_hal_system.h"
#include "tuya_hal_semaphore.h"

SEM_HANDLE my_sem;

void sem_wait_task_handle(void)
{
    for (;;) {
        tuya_hal_semaphore_wait(my_sem);
        PR_NOTICE("HELLO");
    }
}

void sem_release_task_handle(void)
{
    tuya_hal_semaphore_create_init(&my_sem, 0, 1);
    for (;;) {
        tuya_hal_semaphore_post(my_sem);
        PR_NOTICE("sem is posted.");
        tuya_hal_system_sleep(5000);
    }
}

void sem_task_init(void)
{
    tuya_hal_thread_create(NULL, "sem release", 64*8, TRD_PRIO_5, sem_release_task_handle, NULL);
    tuya_hal_thread_create(NULL, "sem wait", 64*8, TRD_PRIO_5, sem_wait_task_handle, NULL);
}

semaphore_demo

6. 互斥量(系统)

互斥量的文件位置:在tuya_iot_sdk 下的 /sdk/include/tuya_hal_mutex.h

互斥量也就是互斥型信号量,它其实是和二值型信号量比较相似的,但互斥型信号量的作用是用于资源保护,能够避免优先级反转的现象的。

6.1 tuya_hal_mutex_create_init()


OPERATE_RET tuya_hal_mutex_create_init(MUTEX_HANDLE *pMutexHandle);

创造并初始化一个互斥量。

Parameters:

  • pMutexHandle: [OUT]互斥量句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

6.2 tuya_hal_mutex_release()


OPERATE_RET tuya_hal_mutex_release(const MUTEX_HANDLE mutexHandle);

释放一个信号量的资源(与 tuya_hal_mutex_create_init() 相对应)。

Parameters:

  • mutexHandle: 信号量句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

6.3 tuya_hal_mutex_lock()


OPERATE_RET tuya_hal_mutex_lock(const MUTEX_HANDLE mutexHandle);

互斥量上锁。

Parameters:

  • mutexHandle: 信号量句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

6.4 tuya_hal_mutex_unlock()


OPERATE_RET tuya_hal_mutex_unlock(const MUTEX_HANDLE mutexHandle);

互斥量解锁。

Parameters:

  • mutexHandle: 信号量句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

6.5 应用示例

应用示例说明:创建两个任务,两个使用互斥量进行一些打印输出。

点击到 GitHub 查看完整工程代码

#include "mutex.h"
#include "uni_log.h"
#include "tuya_hal_mutex.h"
#include "uni_thread.h"
#include "tuya_hal_system.h"
#include "tuya_hal_thread.h"

MUTEX_HANDLE my_mutex;

int demo_value = 0;

void task_1_handle(void) 
{
    for (;;) {
        PR_NOTICE("task 1 wait unlock");
        tuya_hal_mutex_lock(my_mutex);
        PR_NOTICE("task 1 lock");

        demo_value = demo_value + 2;
        PR_NOTICE("task 1 demo value:%d", demo_value);
        tuya_hal_system_sleep(3000);

        tuya_hal_mutex_unlock(my_mutex);
        PR_NOTICE("task 1 unlock");
        tuya_hal_system_sleep(100);
    }
}

void task_2_handle(void) 
{
    for (;;) {
        PR_NOTICE("task 2 wait unlock");
        tuya_hal_mutex_lock(my_mutex);
        PR_NOTICE("task 2 lock");

        demo_value--;
        PR_NOTICE("task 2 demo value:%d", demo_value);
        tuya_hal_system_sleep(5000);

        tuya_hal_mutex_unlock(my_mutex);
        PR_NOTICE("task 2 unlock");
        tuya_hal_system_sleep(100);
    }
}

void mutex_task_init(void)
{
    tuya_hal_mutex_create_init(&my_mutex);
    tuya_hal_thread_create(NULL, "task 1", 64*8, TRD_PRIO_5, task_1_handle, NULL);
    tuya_hal_thread_create(NULL, "task 2", 64*8, TRD_PRIO_5, task_2_handle, NULL);
}

通过下面的日志可以发现,在 task 2 上锁的时候,task 1 会先等待互斥量解锁,等 task 1 一解锁便马上开始下面的操作。

mutex_demo

7.队列(系统)

队列的文件位置:在tuya_iot_sdk 下的 /sdk/include/uni_queue.h

队列在创建时就要设定队列深度(队列可以保存的最大单元数目)和每个单元的大小,队列是先进先出的。

这里主要介绍的是 TuyaOS 中和队列功能相关的 API,由于队列的功能函数接口较多,所有这里将这些函数接口分为三类进行介绍,

  • 第一部分:队列的创建和释放(去初始化);

  • 第二部分:队列的最基本的功能,入队列和出队列;

  • 第三部分:其他一些函数功能的介绍。如得到队列的剩余空间、得到当前队列中的入列数、清空队列和删除队列中的部分数。

7.1 队列的创建和释放

7.1.1 CreateQueueObj()

P_QUEUE_CLASS CreateQueueObj(const unsigned int queTolNum, const unsigned int queUnitSize);

创建一个队列。

Parameters:

  • queTolNum: 队列的个数。
  • queUnitSize:队列中单个数占用的内存大小。

Return:

  • NULL: 队列创建失败。
  • other: 队列创建成功,返回创建的队列的地址。

7.1.2 ReleaseQueueObj()

void ReleaseQueueObj(P_QUEUE_CLASS pQueObj);

释放一个队列,和 CreateQueueObj 相对应。

Parameters:

  • pQueObj: 要释放队列。

Return:

NULL


7.2 队列的基本功能

7.2.1 InQueue()

unsigned char InQueue(P_QUEUE_CLASS pQueObj, const unsigned char *pQueUnit, const unsigned int queNum);

数据入队。

Parameters:

  • pQueObj: 要入队的目标队列。
  • pQueUnit: 要入队的数据首地址
  • queNum: 要入队数据个数。

Return:

  • 1: 函数执行成功。
  • other: 函数执行失败。

7.2.2 OutQueue()

unsigned char OutQueue(P_QUEUE_CLASS pQueObj,unsigned char *pQueUnit, const unsigned int queNum);

数据出队。

Parameters:

  • pQueObj:要出队的队列。
  • pQueUnit: 出队数据存放的空间地址。
  • queNum: 要出队的数据个数。

Return:

  • 1: 函数执行成功。
  • other: 函数执行失败。

7.3 队列的其他功能

7.3.1 GetQueueMember()

unsigned char GetQueueMember(P_QUEUE_CLASS pQueObj, const unsigned int start, unsigned char *pQueUnit, const unsigned int queNum);

得到队列中的数据,和出队不同的是,可以从任何位置开始获取指定长度的数据,获取完成后并不会导致获取到的数据丢失。

Parameters:

  • pQueObj: 要操作的队列。
  • start: 获取数据的开始。从首个数据开始的话就填1。
  • pQueUnit: 获取到的数据存放的buffer地址。
  • queNum: 获取数据的个数。

Return:

  • 1: 函数执行成功。
  • other: 函数执行失败。

7.3.2 GetCurQueNum()

unsigned int GetCurQueNum(P_QUEUE_CLASS pQueObj);

得到当前队列中数据的个数。

Parameters:

  • pQueObj: 要操作的队列。

Return:

  • 1: 函数执行成功。
  • other: 函数执行失败。

7.3.3 GetCurFreeQueNum()

unsigned int GetCurFreeQueNum(P_QUEUE_CLASS pQueObj);

得到当前队列中空闲个数。

Parameters:

  • pQueObj: 要操作的队列。

Return:

  • 1: 函数执行成功。
  • other: 函数执行失败。

7.3.4 DelQueueMember()

unsigned char DelQueueMember(P_QUEUE_CLASS pQueObj, const unsigned int queNum);

删除队列中指定数目的数据。

Parameters:

  • pQueObj: 要操作的队列。
  • queNum: 删除的数据个数

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

7.3.5 ClearQueue()

unsigned char ClearQueue(P_QUEUE_CLASS pQueObj);

清空队列中的数据。

Parameters:

  • pQueObj: 要操作的队列。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

7.4 应用示例

队列一般用在进程间通信,为了演示的方便,所有队列的功能全部在一个线程进行演示。

Demo 创建了一个有 5 个单元,每个单元大小为 int 的队列,打印当前队列已经使用的单元个数和未使用的单元个数。随后队列入了8个数,并打印出队列当前剩余(未使用)的单元个数。队列出一个数,打印输出数的值和剩余单元个数。得到队列从第一个单元开始的4个单元的数值,输出这4个单元的数值和剩余单元的个数,可以发现的是通过 GetQueueMember() 和出列不同的是使用出列输出数值后,对应的剩余单元也会增加,而调用 GetQueueMember() 拿到的数值不会改变剩余的单元个数。随后又从队列中删掉了一个单元,输出剩余单元个数,清除该队列,输出单元个数,可以发现清楚后,所以单元都是可以的,最后释放了该队列。

点击到 GitHub 查看完整工程代码

#include "queue_demo.h"
#include "uni_log.h"
#include "tuya_hal_thread.h"
#include "uni_queue.h"
#include "uni_thread.h"

P_QUEUE_CLASS my_queue;
int in_number[] = {31, 32, 33, 5, 7};
int out_number[5];

void queue_task(void)
{
    unsigned char ret;
    int i;

    /* create queue */
    my_queue = CreateQueueObj(5, SIZEOF(int));
    if (NULL == my_queue) {
        PR_ERR("creat queue failed.");
        return;
    }
    PR_NOTICE("create queue success.");
    PR_NOTICE("cur queue num: %d", GetCurQueNum(my_queue));
    PR_NOTICE("cur free num: %d", GetCurFreeQueNum(my_queue));

    /* in queue */
    ret = InQueue(my_queue, in_number, 5);
    if (1 != ret) {
        PR_ERR("in queue failed.");
    } else {
        PR_NOTICE("queue input 5 numbers success.");
    }
    PR_NOTICE("cur free num: %d", GetCurFreeQueNum(my_queue));

    /* out queue */
    ret = OutQueue(my_queue, out_number, 1);
    if (1 != ret) {
        PR_ERR("out queue failed.");
    } else {
        PR_NOTICE("queue out 1 number success.");
    }
    PR_NOTICE("out_number[0]: %d", out_number[0]);
    PR_NOTICE("cur free num: %d", GetCurFreeQueNum(my_queue));

    /* GetQueueMember */
    ret = GetQueueMember(my_queue, 1, out_number, 4);
    if (1 != ret) {
        PR_ERR("queue get member failed.");
    } else {
        PR_NOTICE("GetQueueMember success.");
    }
    for (i=0; i<4; i++) {
        PR_NOTICE("out_number[%d]:%d", i, out_number[i]);
    }
    PR_NOTICE("cur free num: %d", GetCurFreeQueNum(my_queue));

    /* delete 1 queue number */
    ret = DelQueueMember(my_queue, 1);
    if (1 != ret) {
        PR_ERR("delete queue number error.");
    } else {
        PR_NOTICE("delete queue number success.");
    }
    PR_NOTICE("cur free num: %d", GetCurFreeQueNum(my_queue));

    /* clean queue */
    ret = ClearQueue(my_queue);
    if (1 != ret) {
        PR_ERR("clean queue failed.");
    } else {
        PR_NOTICE("clean queue success.");
    }
    PR_NOTICE("cur free num: %d", GetCurFreeQueNum(my_queue));

    /* release queue */
    ReleaseQueueObj(my_queue);
    PR_NOTICE("queue is release.");
}

queue_demo

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值