Porting

2025-01-16
No Rating

When porting the payload device control program developed based on PSDK to different software and hardware platforms, it is necessary to initialize the Hal and Osal layers first and register key configuration information. By loading the static library, referencing the specified resource file, and declaring structure, set the configuration information required for cross-platform migration of the payload device control program. Finally, use the specified interface to register the Platform module in the payload device control program, obtain hardware resources and operating system resources, and realize the cross-platform transplant of payload device control program.

Sample code

  • Linux

    • Hal layer adaptation: samples/sample_c/platform/linux/manifold2/hal
    • Osal layer adaptation: samples/sample_c/platform/linux/common/osal/
  • FreeRTOS

    • Hal layer adaptation: samples/sample_c/platform/rtos_freertos/stm32f4_discovery/hal
    • Osal layer adaptation: samples/sample_c/platform/rtos_freertos/common/osal/

Description: The API interface of the PSDK Platform module is in the psdk_lib/include/dji_platform.h file.

Overview

In order to transplant the payload device control program developed based on PSDK to different software and hardware platforms, it is necessary to adapt to different hardware platforms through Hal (Hardware Abstraction Layer), and through Osal (Operating System Abstraction Layer) to achieve compatibility with different operating systems, as shown in Figure 1. Code porting.

Figure 1. Code porting

Basic Concepts

Hal Layer

Hal (Hardware Abstraction Layer) is the PSDK hardware interface abstraction layer, which is located between the operating system, the payload device control program, and the hardware interface. Developers need to follow the function prototypes in the DjiPlatform_RegHalUartHandler(), DjiPlatform_RegHalUsbBulkHandler and DjiPlatform_RegHalNetworkHandler() interfaces to implement and register the functions that are adapted to the Hal layer to the payload device control program. The payload device control program developed based on PSDK can directly access the underlying resources of the payload device hardware through the Hal layer and control the payload device to perform corresponding actions, so that the payload device control program can adapt to different hardware platforms, such as STM32F407IGH6-EVAL or Manifold 2-C, etc.

Ethernet Port Device

To adapt the Hal layer function to the device that needs to use the network port, you need to perform the following operations:

  • Implement the function of adapting the network port of the Hal layer
    • Local network card initialization: T_DjiReturnCode (*NetworkInit)(const char *ipAddr, const char *netMask, T_DjiNetworkHandle *networkHandle)
    • Local network card deinitialization: T_DjiReturnCode (*NetworkDeInit)(T_DjiNetworkHandle networkHandle)
    • Get network card information: T_DjiReturnCode (*NetworkGetDeviceInfo)(T_DjiHalNetworkDeviceInfo *deviceInfo)
  • Use DjiPlatform_RegHalNetworkHandler() interface to register network port operation functions

Serial Device

To adapt a device using serial communication to the Hal layer function, you need to perform the following operations:

  • Implement the UART operation function that adapts to the Hal layer
    • Serial port initialization: T_DjiReturnCode (*UartInit)(E_DjiHalUartNum uartNum, uint32_t baudRate, T_DjiUartHandle *uartHandle)
    • Serial port deinitialization: T_DjiReturnCode (*UartDeInit)(T_DjiUartHandle uartHandle)
    • Send data: T_DjiReturnCode (*UartWriteData)(T_DjiUartHandle uartHandle, const uint8_t *buf, uint32_t len, uint32_t *realLen)
    • Receive data: T_DjiReturnCode (*UartReadData)(T_DjiUartHandle uartHandle, uint8_t *buf, uint32_t len, uint32_t *realLen)
    • Get serial port state: T_DjiReturnCode (*UartGetStatus)(E_DjiHalUartNum uartNum, T_DjiUartStatus *status)
  • Use DjiPlatform_RegHalUartHandler() interface to register serial port operation function

Illustration:

  • Parameters of the serial port of the payload device
    • Baud rate: 460800 (SkyPort V2/X-Port firmware version is lower than and includes V01.01.0100) or DJI Assistant 2 software setting value (SkyPort V2/X-Port firmware version is higher than V01.01.0100)
    • Stop bit: 1
    • Data bits: 8
    • Parity check: none
  • You can set the communication baud rate between the SkyPort V2/X-Port and the PSDK payload device through the DJI Assistant 2 software (the communication parameters of the PSDK device must be consistent with the SkyPort V2/X-Port), which perfectly adapts to different hardware platforms (some hardware platform does not support the default communication parameters or has functional defects) and adapts to different application scenarios (for example, when subscribing to a large amount of data, the communication baud rate needs to be appropriately increased).

Figure 2. Setting the communication baud rate

USB Device

To adapt a device using USB Bulk communication to the Hal layer function, you need to perform the following operations:

  • Implement the USB Bulk operation function that adapts to the Hal layer

    • USB Bulk initialization: T_DjiReturnCode (*UsbBulkInit)(T_DjiHalUsbBulkInfo usbBulkInfo, T_DjiUsbBulkHandle *usbBulkHandle)
    • USB Bulk deinitialization: T_DjiReturnCode (*UsbBulkDeInit)(T_DjiUsbBulkHandle usbBulkHandle)
    • USB Bulk write data: T_DjiReturnCode (*UsbBulkWriteData)(T_DjiUsbBulkHandle usbBulkHandle, const uint8_t *buf, uint32_t len, uint32_t *realLen)
    • USB Bulk read data: T_DjiReturnCode (*UsbBulkReadData)(T_DjiUsbBulkHandle usbBulkHandle, uint8_t *buf, uint32_t len, uint32_t *realLen)
    • Get USB Bulk information (Only for the case that SDK device side is USB Device): T_DjiReturnCode (*UsbBulkGetDeviceInfo)(T_DjiHalUsbBulkDeviceInfo *deviceInfo)
  • Use DjiPlatform_RegHalUsbBulkHandler() interface to register USB Bulk port operation function

In M300 RTK, M30/M30T, and M3E/M3T, the Service and Host mode of USB exits some differences:

  • M300 RTK: SDK device side is USB Host, the drone side is USB Device
  • M30/M30T: SDK device side is USB Device, the drone side is USB Host
  • M3E/M3T: SDK device side is USB Device, the drone side is USB Host
M300 RTK

The USB function limitations are as follows:

USB FunctionFunction Limitation
Virtual Serial PortGimbal management, Camera management, part of the basic communication
USB BulkGet Liveview, Get perception image, MOP function, Media file management

Virtual Serial Port:

  1. Linux platform: No additional configuration, the driver supports it by default. It can be searched through ls /dev/ttyACMx, please operate as a standard serial device.
  2. RTOS platform: The library of USB Host should be transplanted to read and write, please refer to the USB_Host transplant and realization of samples/sample_c/platform/rtos_freertos/stm32f4_discovery/middlewares/ST/STM32_USB_Host_Library/.

USB-Bulk:

  1. Linux platform: If the user develops a program at USB-C expansion port, methods of installing and calling static library libusb can be used for development.

    The installation method: sudo apt-get install libusb-1.0-0-dev

  2. RTOS platform: don't support the related drivers of USB Bulk.

M30/M30T

The USB function limitations are as follows:

USB FunctionFunction Limitation
RNDIS virtual network card/USB to Ethernet cardPush Liveview, Subscribe FPV/main camera stream
USB Bulk channel 1Push third-party camera stream, Get stream
USB Bulk channel 2Get perception image, Media file management

Illusttration:

When SDK device side is used to be USB Device, recommended USB network card can be used to connect. For example, AX88179A, RTL8152, and so on. And VID/PID information of corresponding network card should be transferred by registering the interface NetworkGetDeviceInfo to ensure that the drone side can recognize the USB network card normally.

M3E/M3T

The USB function limitations are as follows:

USB FunctionFunction Limitation
RNDIS virtual network card/USB to Ethernet cardPush Liveview, Subscribe FPV/main camera stream
USB Bulk channel 1Push third-party camera stream, Get stream
USB Bulk channel 2Get perception image
Configure the USB of Development Platform to Device Mode
  1. Configure the USB-Device: Configure the USB pin multiplexing, and set to USB-OTG or USB-Device mode. After the configuration, USB port can be linked to the USB Host of another device. The vid and pid information can be searched to determine whether it fulfills the expectation. If we configure the vid and pid of DJI Manifold 2-G to 0x0955 and 0x7020, and link the USB to another Ubuntu, we can easily search by lsusb. 1

  2. Configure the RNDIS network card: Firstly, make sure whether the platform support and open the USB Gadget. For details, please refer to hereopen in new window. Write the RNDIS configuration. After running as administator, the USB port can be linked to the USB Host of another device. Through ifconfig to search whether the corresponding network card is enumerated, and make sure whether fulfills the expectation. ping can be used to check whether the communication is succeeded. 23

  3. Configure the USB Bulk: Firstly, make sure whether the platform support and open the USB Gadget. For details, please refer to hereopen in new window. Write the USB bulk configuration and run the the bulk initialization program. After running as administator, the USB port can be linked to the USB Host of another device. Use "sudo su" to switch to root account and search the corresponding nerwork card through cat /sys/kernel/debug/usb/devices, and make sure whether fulfills the expectation. Please refer to hal_usb_bulk.c to get the write and read operation details of bulk device. 4

I2C Device

To adapt the Hal layer function to the device that needs to use the i2c device, you need to perform the following operations:

  • Implement the function of adapting the i2c device of the Hal layer

    • I2C device initialization: T_DjiReturnCode (*I2cInit)(T_DjiHalI2cConfig i2cConfig, T_DjiI2cHandle *i2cHandle)
    • I2C device deinitialization: T_DjiReturnCode (*I2cDeInit)(T_DjiI2cHandle i2cHandle)
    • I2C device write data: T_DjiReturnCode (*I2cWriteData)(T_DjiI2cHandle i2cHandle, uint16_t devAddress, const uint8_t *buf, uint32_t len, uint32_t *realLen)
    • I2C device read data: T_DjiReturnCode (*I2cReadData)(T_DjiI2cHandle i2cHandle, uint16_t devAddress, uint8_t *buf, uint32_t len, uint32_t *realLen)
  • Use DjiPlatform_RegHalI2cHandler() interface to register i2c device operation functions

Osal Layer

Osal (Operating System Abstraction Layer) is the operating system abstraction layer of PSDK, which is located between the payload device control program and the operating system. Developers need to follow the function prototype in the DjiPlatform_RegOsalHandler() interface to implement and register functions that are adapted to different operating systems into the payload device control program. Using the payload device control program developed by PSDK can directly access the operating system and the resources of the operating system kernel, and port the payload device control program to different operating systems.

Thread Function

To use the thread mechanism to manage the payload device control program to perform the corresponding tasks, the developer needs to implement the functions of creating threads, destroying threads, and thread sleeping.

  • Create thread: T_DjiReturnCode (*TaskCreate)(const char *name, void *(*taskFunc)(void *), uint32_t stackSize, void *arg, T_DjiTaskHandle *task)
  • Destroy thread: T_DjiReturnCode (*TaskDestroy)(T_DjiTaskHandle task)
  • Thread sleep: T_DjiReturnCode (*TaskSleepMs)(uint32_t timeMs)

Mutex

Mutex is a mechanism used to prevent multiple threads from performing read and write operations on the same queue, counter, interrupt handler, and other common resources (such as shared memory, etc.) at the same time, which can effectively avoid process deadlock or long waiting. Using the mutual exclusion lock mechanism requires developers to create, destroy, lock, and unlock a mutex.

  • Create mutex: T_DjiReturnCode (*MutexCreate)(T_DjiMutexHandle *mutex)
  • Destroy the mutex: T_DjiReturnCode (*MutexDestroy)(T_DjiMutexHandle mutex)
  • Mutex lock: T_DjiReturnCode (*MutexLock)(T_DjiMutexHandle mutex)
  • Mutex unlock: T_DjiReturnCode (*MutexUnlock)(T_DjiMutexHandle mutex)

Semaphore

A semaphore is a mechanism used to prevent multiple threads from operating on the same piece of code at the same time. When developers use this mechanism, they need to implement the functions of creating semaphore, destroying semaphore, waiting for semaphore, releasing semaphore, and waiting for timeout semaphore.

  • Create semaphore: T_DjiReturnCode (*SemaphoreCreate)(uint32_t initValue, T_DjiSemaHandle *semaphore)

Note: When using this interface, please set the initial value of the initValue semaphore.

  • Destroy the semaphore: T_DjiReturnCode (*SemaphoreDestroy)(T_DjiSemaHandle semaphore)
  • Wait for semaphore: T_DjiReturnCode (*SemaphoreWait)(T_DjiSemaHandle semaphore)

Description: The max value of the waiting time for the semaphore interface is 32767 ms.

  • Wait for timeout semaphore: T_DjiReturnCode (*SemaphoreTimedWait)(T_DjiSemaHandle semaphore, uint32_t waitTimeMs)
  • Release the semaphore: T_DjiReturnCode (*SemaphorePost)(T_DjiSemaHandle semaphore)

Time interface

  • Get the current system time (ms): T_DjiReturnCode (*GetTimeMs)(uint32_t *ms)
  • Get the current system time (us): T_DjiReturnCode (*GetTimeUs)(uint64_t *us)

Memory management interface

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

Implement cross-platform porting

1. Cross-platform interface adaptation

Cross-platform
Interface Adaptation
Adaptation Plan
Hal layerRTOSLinuxPlease configure the corresponding serial device name according to the hardware connection, such as ttyUSB0, and implement the serial port initialization, serial port read data and serial port write data callback functions. For detailed implementation methods, please refer to: /samples/sample_c/platform/linux/manifold2/hal/hal_uart.c
RTOSPlease 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 methods, please refer to: samples/sample_c/platform/rtos_freertos/stm32f4_discovery/hal/hal_uart.c
Network portLinuxAfter connecting the third-party development platform to the DJI drone using the network port, you need to implement and register the callback function for configuring the network. When the system is initialized, the configuration of the load network parameters will be automatically completed. Function. For detailed implementation methods, please refer to: /samples/sample_c/platform/linux/manifold2/hal/hal_network.c
RTOSFor the RTOS system, you can obtain the network parameters that should be configured for the current load by registering the callback function for configuring network parameters and inform other subsystem modules according to actual needs to complete the functions related to the network port. For detailed implementation methods, please refer to: /samples/sample_c/platform/rtos_freertos/stm32f4_discovery/application/main.c
I2C DeviceLinuxAfter using I2C to connect the DJI SDK certified chip (DJI SDK CC) to a third-party development platform, you need to implement and register the callback function to configure I2C. When the system is initialized, the configuration of the I2C device will be automatically completed. After the configuration is completed, it can communicate normally with the SDK certified chip (DJI SDK CC). For detailed implementation methods, please refer to: /samples/sample_c/platform/linux/raspberry_pi/hal/hal_i2c.c
RTOSFor RTOS system, after using I2C to connect the SDK certified chip (DJI SDK CC) to the third-party development platform, you need to implement and register the callback function for configuring I2C. When the system is initialized, the configuration of the I2C device will be automatically completed. After the configuration is completed, it can communicate normally with the SDK certified chip (DJI SDK CC). For detailed implementation methods, please refer to: /samples/sample_c/platform/rtos_freertos/stm32f4_discovery/hal/hal_i2c.c
Osal layerLinuxUse the standard library pthread to encapsulate the thread functions, mutex locks, semaphores, and time interfaces in T_DjiOsalHandler. For detailed implementation methods, please refer to: samples/sample_c/platform/linux/common/osal/osal.c
RTOSUse the thread interface encapsulated by CMSIS to encapsulate the thread function, mutex, semaphore, and time interface in T_DjiOsalHandler. For detailed implementation methods, please refer to: samples/sample_c/platform/rtos_freertos/common/osal/osal.c

2. Register the cross-platform adaptation interface

Struct declaration

Please fill in the interface content in T_DjiHalUartHandler, T_DjiHalNetworkHandler, T_DjiHalUsbBulkHandler, and T_DjiOsalHandler completely to ensure that the registered interfaces can be used normally.

If the corresponding model uses the SDK certified chip (DJI SDK CC), it is necessary to additionally fill in the interface content in T_DjiHalI2cHandler to ensure that the registered interface can be used normally.

  • T_DjiHalUartHandler uartHandler
T_DjiHalUartHandler uartHandler = {
    .UartInit = HalUart_Init,
    .UartDeInit = HalUart_DeInit,
    .UartWriteData = HalUart_WriteData,
    .UartReadData = HalUart_ReadData,
    .UartGetStatus = HalUart_GetStatus,
};
  • T_DjiHalNetworkHandler networkHandler
 T_DjiHalNetworkHandler networkHandler = {
     .NetworkInit = HalNetWork_Init,
     .NetworkDeInit = HalNetWork_DeInit,
     .NetworkGetDeviceInfo = HalNetWork_GetDeviceInfo,
};
  • T_DjiOsalHandler osalHandler
T_DjiOsalHandler osalHandler = {
    .TaskCreate = Osal_TaskCreate,
    .TaskDestroy = Osal_TaskDestroy,
    .TaskSleepMs = Osal_TaskSleepMs,
    .MutexCreate= Osal_MutexCreate,
    .MutexDestroy = Osal_MutexDestroy,
    .MutexLock = Osal_MutexLock,
    .MutexUnlock = Osal_MutexUnlock,
    .SemaphoreCreate = Osal_SemaphoreCreate,
    .SemaphoreDestroy = Osal_SemaphoreDestroy,
    .SemaphoreWait = Osal_SemaphoreWait,
    .SemaphoreTimedWait = Osal_SemaphoreTimedWait,
    .SemaphorePost = Osal_SemaphorePost,
    .Malloc = Osal_Malloc,
    .Free = Osal_Free,
    .GetTimeMs = Osal_GetTimeMs,
    .GetTimeUs = Osal_GetTimeUs,
};
  • T_DjiHalI2cHandler i2CHandler
T_DjiHalI2cHandler i2CHandler = {
    .I2cInit = HalI2c_Init,
    .I2cDeInit = HalI2c_DeInit,
    .I2cWriteData = HalI2c_WriteData,
    .I2cReadData = HalI2c_ReadData,
};

Please call DjiPlatform_RegOsalHandler() and DjiPlatform_RegHalUartHandler()functions in turn to register the basic Hal layer and the Osal layer. If the interface registration fails, please check the error according to the return code and log information. If the USB or nework card depended function is used, the interface DjiPlatform_RegHalUsbBulkHandler should be called to register the related method of Usb Bulk device or the interface DjiPlatform_RegHalNetworkHandler should be called to register the related method of network card.

If the corresponding model uses the SDK certified chip (DJI SDK CC), it is necessary to additionally fill in the interface content in T_DjiHalI2cHandler to ensure that the registered interface can be used normally.

Note: The cross-platform porting module must be registered before other PSDK function modules. If the Platform module fails to register or is not registered, the developer will not be able to use the load device developed based on PSDK.

    returnCode = DjiPlatform_RegOsalHandler(&osalHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        printf("register osal handler error");
        return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
    }

    returnCode = DjiPlatform_RegHalUartHandler(&uartHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        printf("register hal uart handler error");
        return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
    }

#if (CONFIG_HARDWARE_CONNECTION == DJI_USE_UART_AND_USB_BULK_DEVICE)
    returnCode = DjiPlatform_RegHalUsbBulkHandler(&usbBulkHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        printf("register hal usb bulk handler error");
        return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
    }
#elif (CONFIG_HARDWARE_CONNECTION == DJI_USE_UART_AND_NETWORK_DEVICE)
    returnCode = DjiPlatform_RegHalNetworkHandler(&networkHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        printf("register hal network handler error");
        return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
    }

    //Attention: if you want to use camera stream view function, please uncomment it.
    returnCode = DjiPlatform_RegSocketHandler(&socketHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        printf("register osal socket handler error");
        return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
    }
#elif (CONFIG_HARDWARE_CONNECTION == DJI_USE_ONLY_UART)
    /*!< Attention: Only use uart hardware connection.
     */
#endif

    //Optional: it is necessary to call this interface when using the certified chip.
    returnCode = DjiPlatform_RegHalI2cHandler(&i2CHandler);
    if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
        printf("register hal i2c handler error");
        return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
    }
If you have any comments or confusion about our documentation, you can click here to give feedback and we will get back to you as soon as possible.