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