External camera, external platform, and SerDes example

When you need to do platform specific tweaks to make existing camera and sensor drivers work, you need an external platform. For example, when connecting the imx708 sensor to a Raspberry Pi 4 board, you need to program the CSI2 on the board to receive camera data. Because CSI2 is platform dependent, you would create an external platform so that you can put the CSI2 code in the external platform.

Raspberry Pi's do not have deserializers, so you don't need a SerDes library. You only need an external camera library and external platform library. On platforms with deserializers, you need an external camera, external platform, and SerDes library. The following example uses external_camera_example, external platform_example, and serdes_example. The example also writes color bars to frames, similar to an external_camera_example. The example is platform independent. In a real scenario, the external platform library is platform dependent.

You can find an external platform example in the QNX Software Center:

  • Package: com.qnx.qnx800.target.sf.sensor_examples.source
  • Filepath: source_package_sf_sensor/lib/sensor_drivers/external_platforms/example/external_platform_example.cpp

You can find a SerDes example in the QNX Software Center:

  • Package: com.qnx.qnx800.target.sf.camera_examples.source
  • Filepath: source_package_sf_camera/lib/sensor_drivers/serdes/example/serdes_example_api.c

external_platform_defs implementation

The external platform library looks similar to the external camera library. The major difference is that the code is platform dependent.

/*
 * External platform library definitions
 */
platform_external_interface_t external_platform_defs = {
    group_flags : PLATFORM_GROUP_INIT | PLATFORM_GROUP_CAMERA_QUERY |
                  PLATFORM_GROUP_BUFFER | PLATFORM_GROUP_CAPTURE |
                  PLATFORM_GROUP_CONFIG,
    reserved : {},
    open : open_external_platform,
    close : close_external_platform,
    set_callback: set_callback,
    init : init_platform,
    finalize : finalize_platform,
    deinit : deinit_platform,
    get_camera_frametypes : get_frametypes,
    get_camera_resolutions : get_resolutions,
    get_camera_framerates : get_framerates,
    get_blit_support : NULL,
    is_encoder_supported : NULL,
    get_encoder_frametypes : NULL,
    get_encoder_param_values : NULL,
    get_num_buffers : get_number_of_buffers,
    get_buffer_size : NULL,
    get_buffer_geometry : NULL,
    stride_copy : NULL,
    set_capture_property : set_capture_prop,
    get_capture_property : get_capture_prop,
    start_capture : start_capture,
    stop_capture : stop_capture,
    get_capture_buffer : get_preview_frame,
    get_capture_metadata : NULL,
    get_board_property : get_board_prop,
    set_board_property : set_board_prop,
    set_procmgr_ability : NULL,
    parse_config : parse_config,
    handle_status : NULL,
    set_isp_config : NULL,
    get_ext_lib_path : NULL
};

When using an external camera with an external platform with use_hardware_capture set to true in the sensor config, get_preview_frame in the external platform would be called instead of the get_preview_frame in the external camera. This allows frames to be captured in the external platform instead of the external camera.

set_board_prop implementation

Another difference is that external platform lets you get and set board properties. This is useful when you need to let the sensor service get and set board properties. Following code is a snippet of set_board_prop, which handles setting board properties:

case PLATFORM_BOARD_PROP_CONFIG_DESERIALIZER:
{
    platform_serdes_inst_t* serdes = (platform_serdes_inst_t*) value;
    LOG_DEBUG1("Config serdes %d: func %p handle %d", serdes->index,
                serdes->func, serdes->handle);
    // Override a deserializer property
    err = serdes_set_deser_property(serdes->func, serdes->handle,
                                    DESER_PROP_I2C_ADDR, 0x20);
    if (err != EOK) {
        LOG_ERROR("Failed to set deser %d property: err = %d", serdes->index, err);
    }
    break;
}

The code handles PLATFORM_BOARD_PROP_CONFIG_DESERIALIZER by overriding the deserializer's I2C address.

get_board_prop implementation

The following code is a snippet code of get_board_prop, which gets the number of deserializers:

case PLATFORM_BOARD_PROP_NUM_DESERIALIZERS:
{
    uint8_t* numDeser = (uint8_t*) value;
    *numDeser = 1;
    break;
}

When the sensor service asks the external_platform_example about its PLATFORM_BOARD_PROP_NUM_DESERIALIZERS, it reports the number as 1 in the code.

There are many other properties you can get and set, so please take a look at example source code and experiment with them.

serdes_example and serdes_defs implementation

The serdes_example implements the following functionalities:

/*
 * Serdes library definitions
 */
camera_serdes_t serdes_defs = {
    open : openSerdes,
    close : closeSerdes,
    set_deser_property: setDeserProp,
    get_deser_property: getDeserProp,
    set_ser_property: setSerProp,
    get_ser_property: getSerProp,
    init : initSerdes,
    enable: enableSerdes,
    disable: disableSerdes,
    configure_gpio: configureGpio,
    set_gpio: setGpio,
    parse_config: parseConfig,
};

The serdes_example only permits the reading and writing of values. In a real SerDes library, it interacts with the hardware to program SerDes. Refer to the source code to see how read and write are performed.

Running external_camera_example, external_platform_example, and serdes_example on a QNX Target

Build the external_platform_example and serdes_example, and scp them to a QNX target:

# Navigate to the external camera example code
cd source_package_sf_sensor/lib/sensor_drivers/external_platforms/example

# Source SDP script
source ~/qnx800/qnxsdp-env.sh

# Build external_platform_example
make

# scp libexternal_platform_example.so over to /system/lib on your QNX target
scp ./nto/aarch64/so.le/libexternal_platform_example.so root@<ip-address>:/system/lib

# Navgiate to the serdes example code
cd ../../../../../source_package_sf_camera/lib/sensor_drivers/serdes/example

# Build serdes_example
make

# scp libserdes_example.so over to /system/lib on QNX Raspberry Pi
scp ./nto/aarch64/so.le/libserdes_example.so root@<ip-address>:/system/lib

For the sensor config, note that you need to set user_hardware_capture to true to use the capture functionality in external_platform_example.

Create the following file at /system/etc/system/config/external_platform_example.conf:

begin SENSOR_GLOBAL
    external_platform_library_path = libexternal_platform_example.so
end SENSOR_GLOBAL

begin SENSOR_UNIT_1
    type = external_camera
    name = external_platform_example
    address = /system/lib/libexternal_camera_example.so,1
    use_hardware_capture = true
end SENSOR_UNIT_1

 Start sensor service and run camera_example3_viewfinder to display color bars to screen. Make sure that you supply the -b external flag to sensor to indicate that you intend to use your external platform library.

# Start sensor service; note that you need to use the -b external option to indicate an external platform is used
sensor -U 521:521,1001 -b external -r /data/share/sensor -c  /system/etc/system/config/external_platform_example.conf

# Display color bars to screen
camera_example3_viewfinder
Page updated: