5.1 APP窗口功能组件(widget)
5.1.1 基本功能介绍
widget控件是UI概念,在PSDK中对应的是Pilot APP端的UI界面控件。PSDK/OSDK作为在机载端开发的负载设备,在通常情况下,用户无法直接与负载设备进行交互和控制,当然开发人员可能还可以通过ssh等远程手段进入机载设备查看或调试,但更多的终端用户是在遥控器APP进行可视化操控。widget窗口组件功能,就可以将O/PSDK中一些用户交互感知的功能在APP上的UI界面呈现出来,这样用户在使用遥控器和DJI Pilot APP时,也可以像操作DJI相机负载(比如H20T)一样,对集成的第三方负载进行控制或设置。
widget作为UI概念,在O/PSDK端应如何理解?前面提到了通过widget可以实现APP端与负载设备交互,或许可以换个说法,widget提供了一个Pilot APP与负载设备通信的通道,并且这个通道基于DJI无线链路(遥控器到无人机图传链路)。显然,这个通道不是简单的数据透传,因为Pilot APP是独立完整的产品,原则上是不可以二次开发去读取飞机端发送过来的裸数据。APP要可视化这部分数据,就需要与O/PSDK端进行一个约定,也就是O/PSDK按照约定的数据和格式传给APP,APP也按照约定将控件可视化呈现出来。所以O/PSDK端的widget功能,我们就可以理解成与APP端界面的一个协议约定,widget功能支持自定义,但是自定义也只能在约定的控件中去自定义。
Widget功能定义了按钮、开关、滑动条、列表、输入框等控件,以及主界面浮窗、设置界面文本框。不同的控件对应着不同的状态值,比如按钮对应按下和释放,滑动条对应可变范围值。Pilot端和PSDK端分别对上述几个控件和状态值进行了抽象,即已经约定好了这几个类别。APP操作这几种控件,对应控件的定义状态会发生变化,PSDK通过捕获控件状态的变更就可以感知APP的操作。具体PSDK端与Pilot APP是怎么传输数据,开发者不需要关注,实际在Pilot APP上开发者也无法访问到底层的数据传输。只需要关注的是这几个控件分别对应什么状态,然后将要需求功能按照这几类控件的状态进行封装处理,通过PSDK注册就完成了负载端的widget实现。
控件类型及其状态是重点,先将其列出说明:
BUTTON:按钮
-
按下(Press)/释放(Release)
SWITCH:开关
-
开(ON)/关(OFF)
SCALE:滑动条
-
0~100%的可变值,滑动条状态的是一个范围的百分比(0~100),例:负载端需要实现一个范围的拖动滑条,比如音量。将负载可以支持的音量通过百分比映射,0对应实际可以支持的最小值,100对应实际可以支持的最大值。
LIST:选择列表
-
包含了一系列预设定可选项的选择列表,通过整数值对应到选择项,取值范围0~N-1,N表示设置的列表项的个数。
INT_INPUT_BOX:整数输入框
-
控件是一个输入框,整数输入框中只能输入整数。
区别于文本输入框,文本输入框不需要在PSDK中定义和注册,与主界面浮窗文本一样,直接对应到API。
PSDK 3.0版本中的widget功能基本与旧版本保持一致,新增了支持OSDK端口。PSDK功能通常用于集成第三方负载,widget可以支持很方便的对负载进行一些特定操作,甚至比如相机拍照、云台控制等比较固定的功能,了解上述原理后使用widget功能也可以进行开发实现。举例,定义一个按钮控件用来控制拍照,APP按下按钮检测将会产生一个按钮按下的状态值,发送给飞机端并触发负载的按钮状态回调,PSDK端在此回调中注册硬件拍照功能。但通常情况下,对于相机、云台组件这类已经比较固化和通用的功能,且遥控器上还有特定的物理按键,用widget开发可行但不推荐。可以通过PSDK的特定的相机、云台组件接口进行注册,通过遥控器触发拍照、拨轮控制云台,可以更好好的控制云台相机功能,具体将在对应的相机云台专题里再详细的介绍如何通过相机云台功能接口注册和开发。
使用旧版OSDK开发的开发者对于这部分可能不太熟悉,考虑到widget功能的实用性,PSDK3.0已经适配M300飞机OSDK接口。简单谈谈OSDK端口可以用来做什么?使用旧版开发过程中,有不少开发者有困惑,不想在机载计算机上电时就启动OSDK程序或相关功能,如何在飞行过程中可以随时能接受遥控器下发的指令?旧的方案可以考虑,通过OSDK遥测订阅读取遥控的按键状态,或者通过MSDK开发与OSDK进行数据传输。但都有其限制,遥测订阅机型适配不太完善,MSDK开发工作量太大等。OSDK端口支持widget功能后,此问题将会变得很简单。通过官方Pilot的控件直接与OSDK端口程序就可以直接通信,官方提供的sample(dji_sdk_demo_linux)中,OSDK的各个功能示例就是通过widget界面选择来启动。当然如果想与之前一样不使用widget功能来启动功能,改一下代码实作即可。
5.1.2 主要代码文件及功能API
sample代码文件tree
./widget
├── file_binary_array_list_en.c
├── file_binary_array_list_en.h
├── test_widget.c
├── test_widget.h
├── widget_file
│ ├── cn_big_screen
│ │ ├── icon_button1.png
│ │ ├── icon_button2.png
│ │ ├── icon_list_item1.png
│ │ ├── icon_list_item2.png
│ │ ├── icon_scale.png
│ │ ├── icon_switch_select.png
│ │ ├── icon_switch_unselect.png
│ │ └── widget_config.json
│ └── en_big_screen
│ ├── icon_button1.png
│ ├── icon_button2.png
│ ├── icon_list_item1.png
│ ├── icon_list_item2.png
│ ├── icon_scale.png
│ ├── icon_switch_select.png
│ ├── icon_switch_unselect.png
│ └── widget_config.json
└── widget_file_c
└── en_big_screen
├── icon_button1_png.h
├── icon_button2_png.h
├── icon_list_item1_png.h
├── icon_list_item2_png.h
├── icon_scale_png.h
├── icon_switch_select_png.h
├── icon_switch_unselect_png.h
└── widget_config_json.h
./widget_interaction_test/
├── file_binary_array_list_en.c
├── file_binary_array_list_en.h
├── test_widget_interaction.c
├── test_widget_interaction.h
├── widget_file
│ ├── cn_big_screen
│ │ ├── icon_button1.png
│ │ ├── icon_button2.png
│ │ ├── icon_list_item1.png
│ │ ├── icon_list_item2.png
│ │ ├── icon_scale.png
│ │ ├── icon_switch_select.png
│ │ ├── icon_switch_unselect.png
│ │ └── widget_config.json
│ └── en_big_screen
│ ├── icon_button1.png
│ ├── icon_button2.png
│ ├── icon_list_item1.png
│ ├── icon_list_item2.png
│ ├── icon_scale.png
│ ├── icon_switch_select.png
│ ├── icon_switch_unselect.png
│ └── widget_config.json
└── widget_file_c
└── en_big_screen
├── icon_button1_png.h
├── icon_button2_png.h
├── icon_list_item1_png.h
├── icon_list_item2_png.h
├── icon_scale_png.h
├── icon_switch_select_png.h
├── icon_switch_unselect_png.h
└── widget_config_json.h
功能对应的lib头文件:
dji_widget.h
./widget ,sample未使用
./widget_interaction_test, sample 使用的配置和代码
说明:
-
在前面连接部分有提到,PSDK接口与飞机通过串口和网口通信,OSDK接口与飞机通过串口和USB接口通信。如果只使用串口的情况下,当前版本(Linux)是不支持widget的,如果需求仅使用Linux版串口通信支持widget,可给官方SDK team提需求。
-
widget与widget_interaction_test是同级的,两者对应的控件功能不一样,但其使用是完全一致的,可以看做是两种需求的widget实现方式。
-
widget_file_c是FreeRTOS版本,需要将图片和json配置文件通过file2c转换成.h代码文件。
5.1.3 sample代码实现
开始阅读代码,如开篇所述,先将sample运行起来。(sample运行即环境配置,这里不再详述,可以参考第三、四篇)。widget为遥控器APP的界面,打开遥控器并启动DJI Pilot APP。当看到Pilot主界面呈现PSDK负载名称时(sample默认:PSDK_APPALIAS),即表示PSDK程序已经成功启动。
说明:
考虑widget_interaction_test中控件更多更完善,此篇将结合widget_interaction_test介绍widget,widget 可以作为熟悉案例自主学习。
进入main.c文件查看代码,通过代码也可以看到不管是OSDK接口功能还是PSDK接口功能都有启动widget服务,API使用无差别。
widget服务入口
returnCode = DjiTest_WidgetInteractionStartService();
初始化
//Step 1 : Init DJI Widget
djiStat = DjiWidget_Init();
API:
/**
* @brief Initialise widget module, and user should call this function before using widget features.
* @return Execution result.
*/
T_DjiReturnCode DjiWidget_Init(void);
API简述:
初始化widget模块,使用widget前必须先调用这个API。
注册配置文件
Linux平台有文件系统,但FreeRTOS没有文件系统。所以Linux与RTOS的配置文件注册对文件格式有一定的区分,注册API也有差别。功能完全一样,Linux可以直接处理json文件,FreeRTOS要将文件转换(file2c)成.h代码文件格式。不同语言、不同窗口大小的配置文件不完全一样,需要分别对应注册。sample分别注册了中英文配置文件路径,可以适配中英文APP切换,当APP切换语言时将自动切换到对应语言的配置文件。
//Step 2 : Set UI Config (Linux environment)
char curFileDirPath[WIDGET_DIR_PATH_LEN_MAX];
char tempPath[WIDGET_DIR_PATH_LEN_MAX];
djiStat = DjiUserUtil_GetCurrentFileDirPath(__FILE__, WIDGET_DIR_PATH_LEN_MAX, curFileDirPath);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Get file current path error, stat = 0x%08llX", djiStat);
return djiStat;
}
snprintf(tempPath, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/en_big_screen", curFileDirPath);
//set default ui config path
djiStat = DjiWidget_RegDefaultUiConfigByDirPath(tempPath);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Add default widget ui config error, stat = 0x%08llX", djiStat);
return djiStat;
}
//set ui config for English language
djiStat = DjiWidget_RegUiConfigByDirPath(DJI_MOBILE_APP_LANGUAGE_ENGLISH,
DJI_MOBILE_APP_SCREEN_TYPE_BIG_SCREEN,
tempPath);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Add widget ui config error, stat = 0x%08llX", djiStat);
return djiStat;
}
//set ui config for Chinese language
snprintf(tempPath, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/cn_big_screen", curFileDirPath);
djiStat = DjiWidget_RegUiConfigByDirPath(DJI_MOBILE_APP_LANGUAGE_CHINESE,
DJI_MOBILE_APP_SCREEN_TYPE_BIG_SCREEN,
tempPath);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Add widget ui config error, stat = 0x%08llX", djiStat);
return djiStat;
}
//Step 2 : Set UI Config (RTOS environment)
T_DjiWidgetBinaryArrayConfig enWidgetBinaryArrayConfig = {
.binaryArrayCount = g_testEnBinaryArrayCount,
.fileBinaryArrayList = g_testEnFileBinaryArrayList
};
//set default ui config
djiStat = DjiWidget_RegDefaultUiConfigByBinaryArray(&enWidgetBinaryArrayConfig);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Add default widget ui config error, stat = 0x%08llX", djiStat);
return djiStat;
}
Linux相关API:
/**
* @brief Register default widget UI configuration file directory path.
* @note Under Linux system, there are two functions to set the custom widget configuration directory path, function
* DjiWidget_RegDefaultConfigByDirPath and DjiWidget_RegUiConfigByDirPath. When you don't need multi-language
* and multi-screen size support, you can just use DjiWidget_RegDefaultUiConfigByDirPath function set widget UI
* Config directory path. If you need support multi-language and multi-screen size support, you can use function
* DjiWidget_RegUiConfigByDirPath to specify widget configuration. When the language and screen size is not
* cover in your setting by DjiWidget_RegUiConfigByDirPath, the widget UI configuration uses setting by
* DjiWiget_RegDefaultUiConfigByDirPath function.
* @param widgetConfigDirPath: the widget UI configuration directory path.
* @return Execution result.
*/
T_DjiReturnCode DjiWidget_RegDefaultUiConfigByDirPath(const char *widgetConfigDirPath);
/**
* @brief Register widget UI configuration file directory path.
* @note Different widget UI configurations for several language and screen size require the same widget type, index and
* count.
* @param appLanguage: mobile app language type.
* @param appScreenType: mobile app screen type.
* @param widgetConfigDirPath: the widget UI configuration directory path.
* @return Execution result.
*/
T_DjiReturnCode DjiWidget_RegUiConfigByDirPath(E_DjiMobileAppLanguage appLanguage,
E_DjiMobileAppScreenType appScreenType,
const char *widgetConfigDirPath);
API简述:
-
注册默认UI配置文件,当不需要设置多种语言或支持多个屏幕大小的时,只需注册默认的UI配置文件就好。如果需要支持多种语言可以使用DjiWidget_RegUiConfigByDirPath来指定适配语言和屏幕大小。当使用的语言或屏幕与注册的配置文件不匹配时,就会使用默认的UI配置。
-
注册widget UI配置文件,不同语言的配置文件widget type、index和count要相同。简单描述,除了语言,其他都要相同。具体解释参考API:DjiWidget_RegDefaultUiConfigByDirPath
-
参数:appLanguage,APP支持的语言
appScreenType,APP端支持的屏幕大小
参数枚举定义
/**
* @brief Mobile APP system language.
*/
typedef enum {
DJI_MOBILE_APP_LANGUAGE_UNKNOWN = 255, /*!< The system language of the mobile app is unknown */
DJI_MOBILE_APP_LANGUAGE_ENGLISH = 0, /*!< The system language of the mobile app is English */
DJI_MOBILE_APP_LANGUAGE_CHINESE = 1, /*!< The system language of the mobile app is Chinese */
DJI_MOBILE_APP_LANGUAGE_JAPANESE = 2, /*!< The system language of the mobile app is Japanese */
DJI_MOBILE_APP_LANGUAGE_FRENCH = 3, /*!< The system language of the mobile app is French */
} E_DjiMobileAppLanguage;
/**
* @brief Mobile APP screen size type.
*/
typedef enum {
DJI_MOBILE_APP_SCREEN_TYPE_UNKNOWN = 255, /*!< Mobile APP screen type is unknown. */
DJI_MOBILE_APP_SCREEN_TYPE_BIG_SCREEN = 0, /*!< The big screen of mobile device refers to a screen
* size greater than or equal to 6 inches. */
DJI_MOBILE_APP_SCREEN_TYPE_LITTLE_SCREEN = 1, /*!< The little screen of mobile device refers to a
* screen size less than 6 inches. */
} E_DjiMobileAppScreenType;
FreeRTOS API:
/**
* @brief Register default widget UI config by binary array configuration.
* @note In RTOS, most likely there is no file system. The widget config file content can use C array express. Use this
* function and DjiWidget_RegDefaultUiConfigBinaryArray set widget UI configuration. When the language and screen size
* is not cover in your setting by DjiWidget_RegUiConfigByBinaryArray, the widget UI configuration uses setting by this
* function.
* @param binaryArrayConfig: the binary array config for widget UI configuration.
* @return Execution result.
*/
T_DjiReturnCode DjiWidget_RegDefaultUiConfigByBinaryArray(const T_DjiWidgetBinaryArrayConfig *binaryArrayConfig);
/**
* @brief Register widget UI config by binary array configuration.
* @note Different widget UI configurations for several language and screen size require the same widget type, index and
* count.
* @param appLanguage: mobile app language type.
* @param screenType: mobile app screen type.
* @param binaryArrayConfig: the binary array config for widget UI configuration.
* @return Execution result.
*/
T_DjiReturnCode DjiWidget_RegUiConfigByBinaryArray(E_DjiMobileAppLanguage appLanguage,
E_DjiMobileAppScreenType screenType,
const T_DjiWidgetBinaryArrayConfig *binaryArrayConfig);
API 简述:
将配置文件以及相关控件图片等转换成的二进制文件注册。语言,APP屏大小与Linux 使用完全一致。
注册widget状态回调句柄
//Step 3 : Set widget handler list
djiStat = DjiWidget_RegHandlerList(s_widgetHandlerList, s_widgetHandlerListCount);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Set widget handler list error, stat = 0x%08llX", djiStat);
return djiStat;
}
API简述:
注册widget状态回调,每个控件都对应一个状态回调,与配置文件中的控件个数及类型均对应一致。
参数:
s_widgetHandlerList:与配置文件的控件一一对应,包括状态值的读写函数实现。
s_widgetHandlerListCount:widget控件个数,与配置文件中widget_index总数一致,也对应着s_widgetHandlerList中widget的个数
static const T_DjiWidgetHandlerListItem s_widgetHandlerList[] = {
{0, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{1, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{2, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{3, DJI_WIDGET_TYPE_SWITCH, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{4, DJI_WIDGET_TYPE_SCALE, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{5, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{6, DJI_WIDGET_TYPE_SCALE, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{7, DJI_WIDGET_TYPE_INT_INPUT_BOX, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{8, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{9, DJI_WIDGET_TYPE_SWITCH, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{10, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{11, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{12, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{13, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{14, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{15, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{16, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{17, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
};
启动widget task
step1~3都是在做widget的配置动作,在程序运行过程中,要做到PSDK端与APP端widget实时联动,一般不能受其他功能影响。要开启一个线程(任务)来使widget工作。
这里起了两个线程:
DjiTest_WidgetTask,这个是对应浮窗显示,一个是会将PSDK端的log发送到浮窗进行显示。
//Step 4 : Run widget api sample task
if (osalHandler->TaskCreate("user_widget_task", DjiTest_WidgetTask, WIDGET_TASK_STACK_SIZE, NULL,
&s_widgetTestThread) != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Dji widget test task create error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
if (osalHandler->TaskCreate("user_widget_task", DjiTest_WidgetInteractionTask, WIDGET_TASK_STACK_SIZE, NULL,
&s_widgetInteractionTestThread) != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Dji widget test task create error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
相关API:
/**
* @brief Send message to mobile app floating window.
* @note the message length can't more than DJI_WIDGET_FLOATING_WINDOW_MSG_MAX_LEN. The max data bandwidth of floating
* windows message is 2KB/s.
* @param str: pointer to message string.
* @return Execution result.
*/
T_DjiReturnCode DjiWidgetFloatingWindow_ShowMessage(const char *str);
/**
* @brief Get data transmission state of floating window channel. User can use the state as base for controlling
* floating windows message send.
* @param state: pointer to floating window channel state.
* @return Execution result.
*/
T_DjiReturnCode DjiWidgetFloatingWindow_GetChannelState(T_DjiDataChannelState *state);
API简述:
-
发送数据给APP浮窗显示。最大数据#define DJI_WIDGET_FLOATING_WINDOW_MSG_MAX_LEN 255
-
数据占用最大带宽2KB/s
-
DjiWidgetFloatingWindow_GetChannelState可获取数据通道的状态,状态定义与数据传输通道一样,将在数据传输通道专题中贴出。
另外一个线程将各个功能的入口通过widget区分开,这样就可以通过APP上选择对应的功能来启动。不做具体介绍,后续每个功能篇章都会进入到这里。相当于是一个功能入口线程。
5.1.4 开发注意事项
通过以上代码和API的跟读,可以了解到此功能中最重要的应用部分是widget配置,然而代码中仅提供了一个配置文件注册,我们将其中配置文件拿出来结合APP界面进行分析。json配置文件主要分为三部分:
-
"version": 版本部分,开发者不要修改。
"version": {
"major": 1,
"minor": 0
},
-
"main_interface":主界面控件,此部分设置对应的是相机主界面的功能控件。再分为浮窗和功能控件列表两部分:
-
"floating_window" 浮窗,
一个配置参数。参数true表示配置浮窗,false表示不配置浮窗功能。
注:
浮窗功能可以在APP上开启或关闭,当此处配置false后,APP上的浮窗开关将无效。一般建议这里配置true,然后通过APP来开关是否显示浮窗。
"floating_window": {
"is_enable": true
},-
"widget_list" 功能控件列表
此列表用于在主界面配置多个带ICON的功能控件,主界面会显示ICON图标的控件。此部分配置也将ICON图标与功能控件链接。
"widget_list": [
{
"widget_index": 0,
"widget_type": "button",
"widget_name": "Button_1",
"icon_file_set": {
"icon_file_name_selected": "icon_button1.png",
"icon_file_name_unselected": "icon_button1.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 0
}
},
{
"widget_index": 1,
"widget_type": "button",
"widget_name": "Button_2",
"icon_file_set": {
"icon_file_name_selected": "icon_button2.png",
"icon_file_name_unselected": "icon_button2.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 1
}
},
{
"widget_index": 2,
"widget_type": "list",
"widget_name": "List",
"list_item": [
{
"item_name": "Item_1",
"icon_file_set": {
"icon_file_name_selected": "icon_list_item1.png",
"icon_file_name_unselected": "icon_list_item1.png"
}
},
{
"item_name": "Item_2",
"icon_file_set": {
"icon_file_name_selected": "icon_list_item2.png",
"icon_file_name_unselected": "icon_list_item2.png"
}
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 2
}
},
{
"widget_index": 3,
"widget_type": "switch",
"widget_name": "Switch",
"icon_file_set": {
"icon_file_name_selected": "icon_switch_select.png",
"icon_file_name_unselected": "icon_switch_unselect.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 3
}
},
{
"widget_index": 4,
"widget_type": "scale",
"widget_name": "Scale",
"icon_file_set": {
"icon_file_name_selected": "icon_scale.png",
"icon_file_name_unselected": "icon_scale.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 4,
"button_value_step_length": 5
}
}
]APP界面:
-
控件展开
-
"config_interface":设置界面控件
此部分配置对应设置界面,分为文本输入框和控件列表两部分。
-
"text_input_box" 文本输入框
"text_input_box": {
"widget_name": "TextInputBox",
"placeholder_text": "Please input message",
"is_enable": true
},此文本输入框非PSDK定义控件,与浮窗类似。PSDK接收此文本输入数据的接口函数是数据传输data transition中的低速通道,文本输入框发送数据,将会触发通过此接口注册的回调来上抛接收到的文本数据。
DjiLowSpeedDataChannel_RegRecvDataCallback
-
"widget_list":设置界面功能控件列表
"widget_list": [
{
"widget_index": 5,
"widget_type": "button",
"widget_name": "Button 5",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 5
}
},
{
"widget_index": 6,
"widget_type": "scale",
"widget_name": "Scale 6",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 6,
"button_value_step_length": 5
}
},
{
"widget_index": 7,
"widget_type": "int_input_box",
"widget_name": "Integer Input Box 7",
"int_input_box_hint": "unit:s"
},
{
"widget_index": 8,
"widget_type": "button",
"widget_name": "=========>> [Extension Port Test] <<=========",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 7
}
},
{
"widget_index": 9,
"widget_type": "switch",
"widget_name": "Unlock flight control restrictions (Special attention)",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 8
}
},
{
"widget_index": 10,
"widget_type": "list",
"widget_name": "Please Select Payload Index",
"list_item": [
{
"item_name": "payload_index1"
},
{
"item_name": "payload_index2"
},
{
"item_name": "payload_index3"
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 9
}
},
{
"widget_index": 11,
"widget_type": "list",
"widget_name": "Please Select Perception Camera Index",
"list_item": [
{
"item_name": "Down"
},
{
"item_name": "Front"
},
{
"item_name": "Rear"
},
{
"item_name": "Up"
},
{
"item_name": "Left"
},
{
"item_name": "Right"
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 10
}
},
{
"widget_index": 12,
"widget_type": "list",
"widget_name": "Please Select Camera Function",
"list_item": [
{
"item_name": "set camera shutter speed"
},
{
"item_name": "set camera aperture"
},
{
"item_name": "set camera exposure compensation"
},
{
"item_name": "set camera ISO"
},
{
"item_name": "set camera focus point"
},
{
"item_name": "camera tap zoom"
},
{
"item_name": "camera optical zoom"
},
{
"item_name": "shoot single photo"
},
{
"item_name": "shoot AEB photo"
},
{
"item_name": "shoot burst photo"
},
{
"item_name": "shoot interval photo"
},
{
"item_name": "record video"
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 11
}
},
{
"widget_index": 13,
"widget_type": "list",
"widget_name": "Please Select Sample",
"list_item": [
{
"item_name": "fc_subscription"
},
{
"item_name": "waypoint_v2"
},
{
"item_name": "flight_ctrl_takeoff_landing"
},
{
"item_name": "flight_ctrl_position_ctrl"
},
{
"item_name": "flight_ctrl_force_landing"
},
{
"item_name": "flight_ctrl_velocity_ctrl"
},
{
"item_name": "flight_ctrl_arrest_flying"
},
{
"item_name": "flight_ctrl_set_get_param"
},
{
"item_name": "hms_info"
},
{
"item_name": "camera_manager"
},
{
"item_name": "gimbal_manager_free_mode"
},
{
"item_name": "gimbal_manager_yaw_follow_mode"
},
{
"item_name": "liveview"
},
{
"item_name": "perception"
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 12
}
},
{
"widget_index": 14,
"widget_type": "button",
"widget_name": "Run",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 13
}
},
{
"widget_index": 15,
"widget_type": "button",
"widget_name": "=========>> [Payload Port Test] <<=========",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 14
}
},
{
"widget_index": 16,
"widget_type": "list",
"widget_name": "Please Select Sample",
"list_item": [
{
"item_name": "change_alias"
},
{
"item_name": "fc_subscription_log_on/off"
},
{
"item_name": "collaboration_log_on/off"
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 15
}
},
{
"widget_index": 17,
"widget_type": "button",
"widget_name": "Run",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 16
}
}
]APP界面
-
说明:
-
显示实时数据为主界面浮窗开关
-
s_widgetHandlerList中的Item 0 ~ 17分别对应配置文件中的widget 0 ~17。Item中的回调函数实现在sample中使用同一个DjiTestWidget_SetWidgetValue和DjiTestWidget_GetWidgetValue,实际上此部分与应用端是强相关的,也就是各个Item可以根据需要编写自己的功能逻辑。APP上控件状态变化对应此回调函数的触发。
- 文本输入框的数据与数据传输通道,data transmition是复用的。
-
-
评论
0 条评论
请登录写评论。