Skip to main content

Platform Porting

When porting the payload control program developed with PSDK to different versions of hardware and software platforms, you need to first initialize the Hal and Osal layers, register key configuration information, and set up the required configuration for cross-platform portability by loading static libraries, referencing specific resource files, and declaring structures. Finally, use the designated interface to register the Platform module into the payload device's control program to access hardware and operating system resources, achieving cross-platform portability of the payload control program.

Note:

  • On the Linux platform, the Payload SDK follows the POSIX standard, so no additional porting work is required. However, the Linux kernel version must be at least V3.10.

Example Code

  • FreeRTOS
    • Hal layer adaptation: samples\sample_c\platform\rtos_freertos\hc32f460\02_app\hal
    • Osal layer adaptation: samples\sample_c\platform\rtos_freertos\common\osal

Note:

  • The API interfaces for the PSDK Platform module are located in the psdk_lib/include/uav_platform.h file.

Overview

To ensure that payload control programs developed using PSDK can be ported to different hardware and software platforms, you need to adapt the hardware platform through the Hal (Hardware Abstraction Layer) and achieve compatibility with different operating systems via the Osal (Operating System Abstraction Layer), as shown in the diagram below.

img_17.png

Basic Concepts

Hal Layer

The Hal (Hardware Abstraction Layer) is the hardware interface abstraction layer of the PSDK, which sits between the operating system, payload control program, and hardware interfaces. Developers need to implement the functions for adapting the Hal layer and register them into the payload device control program using the UAV_Platform_RegHalUartHandler() interface. This allows the payload control program, developed with PSDK, to access the underlying hardware resources of the payload device through the Hal layer and control the payload device to perform corresponding actions, making the control program adaptable to different hardware platforms.

Serial Port Devices

For devices that communicate via serial port, the Hal layer function adaptation requires the following steps:

  • Implement Hal layer UART operation functions:
    • Initialize Serial Port: T_UAVReturnCode (*init)(void)
    • Deinitialize Serial Port: T_UAVReturnCode (*deInit)(void)
    • Send Data: T_UAVReturnCode (*write)(const uint8_t *buf, uint32_t len)
    • Receive Data: T_UAVReturnCode (*read)(uint8_t *buf, uint32_t len, uint32_t *realLen)
    • Get Serial Port Status: T_UAVReturnCode (*getStatus)(void)
    • Set Baud Rate: T_UAVReturnCode (*setBaudRate)(E_UAVHalUartBaudRate baudRateIndex)
    • Baud Rate: E_UAVHalUartBaudRate baudRateIndex
    • Register serial port operation functions using the UAV_Platform_RegHalUartHandler() interface

Note:

  • Payload device serial port parameters:
    • Baud Rate: Users can specify it using the baudRateIndex parameter, with the default being 115200.
    • Stop Bits: 1
    • Data Bits: 8
    • Parity: None

Osal Layer

The Osal (Operating System Abstraction Layer) is the PSDK operating system abstraction layer, located between the payload control program and the operating system. Developers need to implement and register OS-specific functions to the payload control program according to the function prototypes in the UAV_Platform_RegOsalHandler() interface. With this implementation, the payload control program developed using PSDK can directly access the operating system and its kernel resources, allowing the payload control program to be ported to different operating systems.

Thread Functions

To manage tasks in the payload control program, developers need to implement functions for creating threads, destroying threads, and putting threads to sleep.

  • Create Thread: T_UAVReturnCode (*TaskCreate)(const char *name, void *(*taskFunc)(void *), uint32_t stackSize, void *arg, T_UAVTaskHandle *task)
  • Destroy Thread: T_UAVReturnCode (*TaskDestroy)(T_UAVTaskHandle task)
  • Thread Sleep: T_UAVReturnCode (*TaskSleepMs)(uint32_t timeMs)

Mutexes

Mutexes are mechanisms used to prevent multiple threads from simultaneously reading and writing to shared resources (like memory, queues, counters, or interrupt handlers). This helps avoid deadlocks or long wait times. To use mutexes, developers need to implement functions for creating and destroying mutexes and locking and unlocking them.

  • Create Mutex: T_UAVReturnCode (*MutexCreate)(T_UAVMutexHandle *mutex)
  • Destroy Mutex: T_UAVReturnCode (*MutexDestroy)(T_UAVMutexHandle mutex)
  • Lock Mutex: T_UAVReturnCode (*MutexLock)(T_UAVMutexHandle mutex)
  • Unlock Mutex: T_UAVReturnCode (*MutexUnlock)(T_UAVMutexHandle mutex)

Semaphores

Semaphores are mechanisms used to prevent multiple threads from simultaneously accessing the same section of code. When using semaphores, developers need to implement functions for creating and destroying semaphores, as well as waiting and posting semaphores.

  • Create Semaphore: T_UAVReturnCode (*SemaphoreCreate)(uint32_t initValue, T_UAVSemaHandle *semaphore)

    Note:

    • When using this interface, the initValue is the initial value of the semaphore.
  • Destroy Semaphore: T_UAVReturnCode (*SemaphoreDestroy)(T_UAVSemaHandle semaphore)

  • Wait for Semaphore: T_UAVReturnCode (*SemaphoreWait)(T_UAVSemaHandle semaphore)

    Note:

    • The maximum wait time for the semaphore wait interface is 32767 ms.
  • Wait for Semaphore with Timeout: T_UAVReturnCode (*SemaphoreTimedWait)(T_UAVSemaHandle semaphore, uint32_t waitTimeMs)

  • Post Semaphore: T_UAVReturnCode (*SemaphorePost)(T_UAVSemaHandle semaphore)

Time Interfaces

  • Get Current System Time (in ms): T_UAVReturnCode (*GetTimeMs)(uint32_t *ms)
  • Get Current System Time (in us): T_UAVReturnCode (*GetTimeUs)(uint64_t *us)

Memory Management Interfaces

  • Allocate Memory: void *(*Malloc)(uint32_t size)
  • Free Memory: void (*Free)(void *ptr)

Implementing Cross-Platform Porting

1. Cross-Platform Interface Adaptation

Cross-Platform Interface AdaptationAdaptation Plan
Hal Layer AdaptationSerial PortRTOSPlease configure the corresponding serial port pins according to the MCU model, and implement the serial port initialization, serial port read data, and serial port write data callback functions. For detailed implementation, please refer to: samples\sample_c\platform\rtos_freertos\hc32f460\02_app\hal\hal_uart.c
EthernetLinuxAfter connecting the third-party development platform to the Autel Robotics aircraft via the network interface, you need to configure the payload network parameters during system initialization. Once configured, you can use the related network functions. For detailed implementation, please refer to: .\include\uav_platform.h
Osal Layer AdaptationLinuxAfter connecting the third-party development platform to the Autel Robotics aircraft via Ethernet, you need to configure the payload network parameters during system initialization. Once configured, you can use Ethernet-related functions. For detailed implementation, please refer to: samples/sample_c/platform/linux/common/osal/osal.c
RTOSUse the `thread` interface encapsulated by `CMSIS` to encapsulate the thread functions, mutexes, semaphores, and time interfaces in `T_UAVOsalHandler`. For detailed implementation, please refer to: samples/sample_c/platform/rtos_freertos/common/osal/osal.c

2. Register Cross-Platform Adaptation Interfaces

Structure Declaration Please fully populate the T_UAVHalUartHandler and T_UAVOsalHandler structure contents to ensure that the registered interfaces are functional.

  • 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,
};

Please call the UAV_Platform_RegOsalHandler() and UAV_Platform_RegHalUartHandler() functions sequentially to register the basic Hal layer and Osal layer. If the interface registration is unsuccessful, troubleshoot the error based on the return code and log information.

Note:

  • The cross-platform adaptation module must be registered before other PSDK functionality modules. If the Platform module registration fails or is not registered, developers will not be able to use the payload device developed based on 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 !!!!");
}