跨平台移植
将基于 PSDK 开发的负载设备控制程序移植到不同版本的软硬件平台上时,需要先初始化 Hal 和 Osal 层,注册关键的配置信息。通过加载静态库、引用指定的资源文件并声明结构体,设置负载设备控制程序跨平台移植所需的配置信息。最后使用指定的接口将 Platform 模块注册到负载设备的控制程序中,获取硬件资源和操作系统资源,实现负载设备控制程序的跨平台移植。
说明:
- Linux 平台下的 Payload SDK 遵循 POSIX 标准实现,不需要额外的移植工作,但要求 Linux 内核版本不低于 V3.10。
示例代码
- FreeRTOS
- Hal 层适配:
samples\sample_c\platform\rtos_freertos\hc32f460\02_app\hal
- Osal 层适配:
samples\sample_c\platform\rtos_freertos\common\osal
- Hal 层适配:
说明:
- PSDK Platform 模块的 API 接口,在
psdk_lib/include/uav_platform.h
文件中。
概述
为能使基于 PSDK 开发的负载设备控制程序移植到不同的软硬件平台,需要通过 Hal(Hardware Abstraction Layer,硬件接口层)适配不同的硬件平台,通过 Osal(Operating System Abstraction Layer,操作系统抽象层)实现与不同操作系统的兼容,如下图所示。
基础概念
Hal 层
Hal(Hardware Abstraction Layer,硬件接口层)是 PSDK 硬件接口抽象层,位于操作系统、负载设备控制程序和硬件接口间。开发者需要按照 UAV_Platform_RegHalUartHandler()
接口中的函数原型,实现并将适配 Hal 层的函数注册到负载设备控制程序中,使基于 PSDK 开发的负载设备控制程序,通过 Hal 层即可直接访问负载设备硬件的底层资源,控制负载设备执行相应的动作,使负载设备控制程序能够适配不同的硬件平台。
串口设备
使用串口通信的设备适配 Hal 层函数需要执行如下操作:
- 实现适配 Hal 层 UART 操作函数
- 串口初始化:
T_UAVReturnCode (*init)(void)
- 串口反初始化:
T_UAVReturnCode (*deInit)(void)
- 发送数据:
T_UAVReturnCode (*write)(const uint8_t *buf, uint32_t len)
- 接收数据:
T_UAVReturnCode (*read)(uint8_t *buf, uint32_t len, uint32_t *realLen)
- 获取串口状态:
T_UAVReturnCode (*getStatus)(void)
- 设置波特率:
T_UAVReturnCode (*setBaudRate)(E_UAVHalUartBaudRate baudRateIndex)
- 波特率:
E_UAVHalUartBaudRate baudRateIndex
- 串口初始化:
- 使用
UAV_Platform_RegHalUartHandler()
接口注册串口操作函数
说明:
- 负载设备串口的参数:
- 波特率:用户可通过
baudRateIndex
参数指定,默认是115200
。- 停止位:1
- 数据位:8
- 奇偶校验:无
Osal 层
Osal(Operating System Abstraction Layer,操作系统抽象层)是 PSDK 的操作系统抽象层,位于负载设备控制程序和操作系统间。开发者需要按照 UAV_Platform_RegOsalHandler()
接口中的函数原型,实现并将适配不同操作系统的函数注册到负载设备控制程序中,使用 PSDK 开发的负载设备控制程序即可直接访问操作系统以及操作系统内核的资源,将负载设备控制程序移植到不同的操作系统上。
线程函数
使用线程机制管理负载设备控制程序执行相应的任务,开发者需要实现创建线程、销毁线程和线程睡眠的函数。
- 创建线程:
T_UAVReturnCode (*TaskCreate)(const char *name, void *(*taskFunc)(void *), uint32_t stackSize, void *arg, T_UAVTaskHandle *task)
- 销毁线程:
T_UAVReturnCode (*TaskDestroy)(T_UAVTaskHandle task)
- 线程睡眠:
T_UAVReturnCode (*TaskSleepMs)(uint32_t timeMs)
互斥锁
互斥锁是一种用于防止多个线程同时对同一队列、计数器和中断处理程序等公共资源(如共享内存等)执行读写操作的机制,能够有效避免进程死锁或长时间的等待。使用互斥锁机制,需要开发者实现创建互斥锁、销毁互斥锁、互斥锁上锁和互斥锁解锁。
- 创建互斥锁:
T_UAVReturnCode (*MutexCreate)(T_UAVMutexHandle *mutex)
- 销毁互斥锁:
T_UAVReturnCode (*MutexDestroy)(T_UAVMutexHandle mutex)
- 互斥锁上锁:
T_UAVReturnCode (*MutexLock)(T_UAVMutexHandle mutex)
- 互斥锁解锁:
T_UAVReturnCode (*MutexUnlock)(T_UAVMutexHandle mutex)
信号量
信号量是一种用于防止多线程同时操作相同代码段的机制。开发者使用该机制时,需要实现创建信号量、销毁信号量、等待信号量、释放信号量和等待超时信号量函数。
创建信号量:
T_UAVReturnCode (*SemaphoreCreate)(uint32_t initValue, T_UAVSemaHandle *semaphore)
说明:
- 使用该接口时,请设置
initValue
信号量的初始值。
- 使用该接口时,请设置
销毁信号量:
T_UAVReturnCode (*SemaphoreDestroy)(T_UAVSemaHandle semaphore)
等待信号量:
T_UAVReturnCode (*SemaphoreWait)(T_UAVSemaHandle semaphore)
说明:
- 等待信号量接口等待时间的最大值为 32767ms。
等待超时信号量:
T_UAVReturnCode (*SemaphoreTimedWait)(T_UAVSemaHandle semaphore, uint32_t waitTimeMs)
释放信号量:
T_UAVReturnCode (*SemaphorePost)(T_UAVSemaHandle semaphore)
时间接口
- 获取当前系统的时间(ms):
T_UAVReturnCode (*GetTimeMs)(uint32_t *ms)
- 获取当前系统的时间(us):
T_UAVReturnCode (*GetTimeUs)(uint64_t *us)
内存管理接口
- 申请内存:
void *(*Malloc)(uint32_t size)
- 释放内存:
void (*Free)(void *ptr)
实现跨平台移植
1. 跨平台接口适配
跨平台接口适配 | 适配方案 | ||
---|---|---|---|
Hal 层适配 | 串口 | RTOS | 请根据 MCU 的型号配置对应的串口管脚,并实现串口初始化、串口读数据和串口写数据的回调函数。详细实现方法请参见:samples\sample_c\platform\rtos_freertos\hc32f460\02_app\hal\hal_uart.c |
网口 | Linux | 使用网口将第三方开发平台连接至 Autel Robotics 无人机后,需要在系统初始化时,完成负载网络参数的配置,配置完成后,可以使用网口相关的功能。详细实现方法请参见:.\include\uav_platform.h | |
Osal 层适配 | Linux | 使用标准库 `pthread` 封装 `T_UAVOsalHandler` 中的线程函数、互斥锁、信号量以及时间接口等接口。详细实现方法请参见:samples/sample_c/platform/linux/common/osal/osal.c | |
RTOS | 使用 `CMSIS` 封装的 `thread` 接口,封装 `T_UAVOsalHandler` 中的线程函数、互斥锁、信号量以及时间接口等接口。详细实现方法请参见:samples/sample_c/platform/rtos_freertos/common/osal/osal.c |
2. 注册跨平台适配接口
结构体声明
请完整地填充 T_UAVHalUartHandler
和 T_UAVOsalHandler
中的接口内容,确保所注册的接口能够正常使用。
- T_UAVHalUartHandler uartHandler
typedef enum
{
UAV_BAUDRATE_115200=0,
UAV_BAUDRATE_19200,
UAV_BAUDRATE_230400,
UAV_BAUDRATE_460800,
UAV_BAUDRATE_1000000,
UAV_BAUDRATE_2000000,
UAV_BAUDRATE_MAX,
}E_UAVHalUartBaudRate;
T_UAVHalUartHandler uavHalUartHandler1 = {
.baudRateIndex = UAV_BAUDRATE_115200,
.init = uart1_Init,
.deInit = uart1_DeInit,
.write = uart1_write,
.read = uart1_Read,
.getStatus = uart1_GetStatus,
.setBaudRate = uart1_SetBaudRate,
};
- T_UAVOsalHandler osalHandler
T_UAVOsalHandler uavOSHandler = {
.TaskCreate = os_task_create,
.TaskStart = os_task_start,
.TaskDestroy = os_task_destroy,
.TaskSleepMs = os_task_sleep_ms,
.MutexCreate = os_mutex_create,
.MutexDestroy = os_mutex_destroy,
.MutexLock = os_mutex_lock,
.MutexUnlock = os_mutex_unlock,
.SemaphoreCreate = os_semaphore_create,
.SemaphoreDestroy = os_semaphore_destroy,
.SemaphoreWait = os_semaphore_wait,
.SemaphoreTimedWait = os_semaphor_time_wait,
.SemaphorePost = os_semaphore_post,
.GetTimeMs = os_get_time_ms,
.GetTimeUs = os_get_time_us,
.Malloc = os_malloc,
.Free = os_free,
.MsToTicks = os_ms_to_ticks,
.TaskList = os_task_list,
.FreeHeapSize = os_get_free_heap_size,
};
请依次调用 UAV_Platform_RegOsalHandler()
、UAV_Platform_RegHalUartHandler()
函数注册基础 Hal 层和 Osal 层,若接口注册不成功,请根据返回码和日志信息排查错误问题。
说明:
- 跨平台移植模块必须在其他 PSDK 功能模块前被注册,若 Platform 模块注册失败或未注册,开发者将无法使用基于 PSDK 开发的负载设备。
T_UAVReturnCode UAV_Core_ApplicationStart(void)
{
static uint32_t heap_size = 0;
T_UAVReturnCode returnCode;
T_UAVUserInfo userInfo;
T_UAVOsalHandler uavOSHandler = {
.TaskCreate = os_task_create,
.TaskStart = os_task_start,
.TaskDestroy = os_task_destroy,
.TaskSleepMs = os_task_sleep_ms,
.MutexCreate = os_mutex_create,
.MutexDestroy = os_mutex_destroy,
.MutexLock = os_mutex_lock,
.MutexUnlock = os_mutex_unlock,
.SemaphoreCreate = os_semaphore_create,
.SemaphoreDestroy = os_semaphore_destroy,
.SemaphoreWait = os_semaphore_wait,
.SemaphoreTimedWait = os_semaphor_time_wait,
.SemaphorePost = os_semaphore_post,
.GetTimeMs = os_get_time_ms,
.GetTimeUs = os_get_time_us,
.Malloc = os_malloc,
.Free = os_free,
.MsToTicks = os_ms_to_ticks,
.TaskList = os_task_list,
.FreeHeapSize = os_get_free_heap_size,
};
T_UAVLoggerConsole printConsole = {
.func = log_data,
.consoleLevel = UAV_LOGGER_CONSOLE_LOG_LEVEL_INFO,
};
returnCode = UAV_Platform_RegOsalHandler(&uavOSHandler);
if(returnCode != UAV_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
return;
}
returnCode = UAV_Platform_RegHalUartHandler(&UAV_HalUartHandler0);
if(returnCode != UAV_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
return;
}
returnCode = UAV_Logger_AddConsole(&printConsole);
if(returnCode != UAV_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
return;
}
returnCode = UAV_User_FillInUserInfo(&userInfo);
if(returnCode != UAV_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
UAV_LOG_ERROR("fill user info error, please check user info config");
goto out;
}
returnCode=UAV_Core_Init(&userInfo);
if(returnCode != UAV_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
UAV_LOG_ERROR("uav core init failed !!!");
goto out;
}
returnCode = UAV_Core_SetFirmwareVersion(firmwareVersion);
if(returnCode != UAV_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
UAV_LOG_ERROR("set firmware version failed !!!");
goto out;
}
/** register upgradation.*/
returnCode = UAV_Upgrade_Init(&UAV_Upgrade);
if(returnCode != UAV_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
UAV_LOG_ERROR("UAV_Upgrade_Init failed !!!");
goto out;
}
else {
UAV_LOG_INFO("UAV_Upgrade_Init success!");
}
UAV_LOG_INFO("UAV_Upgrade_Init success !!!!");
return;
out:
UAV_LOG_ERROR("UAV_Upgrade_Init fail !!!!");
}