概述
当系统上电启动后,会执行应用层的逻辑,应用层的代码入口是
appvideouicvrcamera_ui.c :MiniGUIMain
MiniGUIMain
api_poweron_init(ui_msg_manager_cb);
应用层的初始化,主要是在函数api_poweron_init(ui_msg_manager_cb);中,实现的功能主要是系统参数的初始化,注册回调函数,以及wifi的的初始化。
下面分析具体过程:
api_poweron_init(ui_msg_manager_cb);
android_usb_init();//开启adb功能
parameter_init();//初始化flash参数
video_record_init_lock(); //must before uevent init ,the function is to get camera info,and include the number of the chip camera 。directly use camerahal member function
thermal_init();//this function is used for realize the related fun of temperature
usb_reg_event_callback(usb_event_callback);//this function implements a callback function for registering usb-related events。
uevent_monitor_run();//Event monitoring thread,will involve some socket netlink
REC_RegEventCallback(record_event_callback);//register the callback function as in file video.cpp rec_event_call
set_video_init_complete_cb(notify_videos_inited);//register the callback function as in video.cpp video_rec_state
sd_reg_event_callback(sd_event_callback);//register the callback function as file usb_sd_ctrl.c sdcard_evnet_call
USER_RegEventCallback(user_event_callback);//the file user.cpp user_event_call
VIDEOPLAY_RegEventCallback(videoplay_event_callback);//videoplay.c videoplay_event_call
fs_msg_file_reg_callback(fsfile_event_callbak);//fs_msg.c fs_msg_file_call
wifi_management_start();//wifi init
storage_setting_reg_event_callback(storage_setting_callback);public_interface.c storage_filesize_event_call
storage_setting_event_callback(0, NULL, NULL);
video_record_init_lock();
video_record_init_lock();
memset(&g_test_cam_infos, 0, sizeof(g_test_cam_infos));
CamHwItf::getCameraInfos(&g_test_cam_infos);//CamHwItf.cpp the class of CamHwItf member function getCameraInfo
这里面调用的是libcamerahal库代码中的externallibcamerahalCameraHal10_ReleaseCameraHalHALsourceCamHwItf.cpp函数:CamHwItf::getCameraInfos(struct rk_cams_dev_info* cam_infos)。
这个函数实现方式是论寻dev/video%d,目录下的video设备节点,并依次打开这些设备节点,打开成功后通过ioctl系统调用的VIDIOC_QUERYCAP命令获取v4l2_capability数据内容,并通过strstr查看capability.driver中的设备类型:rkisp,cif,UVC。然后在各个设备类型下面使用ioctl的VIDIOC_ENUMINPUT获取v4l2_input的数据内容。
snprintf(video_dev_path, sizeof(video_dev_path), "/dev/video%d", i);
fd = open(video_dev_path, O_RDONLY);
ioctl(fd, VIDIOC_QUERYCAP, &capability)
if (strstr((char*)(capability.driver), "rkisp"))
ioctl(fd, VIDIOC_ENUMINPUT, &input)
else if (strstr((char*)(capability.driver), "cif"))
ioctl(fd, VIDIOC_ENUMINPUT, &input)
else if (strstr((char*)(capability.driver), "UVC"))
ioctl(fd, VIDIOC_ENUMINPUT, &input)
只有通过上上面的调用CamHwItf::getCameraInfos(struct rk_cams_dev_info* cam_infos),以及之后调用的initrec函数的api_video_init接口初始化摄像头在飞机的的空中端口接受到拍照指令后执行的 video_record_takephoto(unsigned int num)中video_cur = getfastvideo();才会有相应的video设备节点返回。
其中api_video_init进有一次调用就是在初始化的时候,并且此时是设置为VIDEO_MODE_REC模式的,如果在初始化的时候这个地方被设置成VIDEO_MODE_PHOTO模式,拍摄的图片就会偏暗。如下图所示:
/home/highgreat-xyw2018/Documents/share-2018xyw/aa/20160121_090346_picture124A00.jpg
获取支持的camera的类型,cif isp usb,支持的个数
thermal_init();
soc的温度检测功能的初始化
usb_reg_event_callback(usb_event_callback);
这里注册的回调函数是执行在链表msg_list_manager.c中的g_listHead上的回调函数。
uevent_monitor_run();
建立监控线程,主要监控内核发送到应用层的消息,设计到netlink的使用。
REC_RegEventCallback(record_event_callback);
void record_event_callback(int cmd, void *msg0, void *msg1)
{
switch (cmd) {
case CMD_UPDATETIME:
api_send_msg(MSG_VIDEO_UPDATETIME, TYPE_BROADCAST, msg0, NULL);
break;
break;
case CMD_PHOTOEND:
api_send_msg(MSG_VIDEO_PHOTO_END, TYPE_BROADCAST, msg0, msg1);
break;
}
}
api_send_msg:执行在链表msg_list_manager.c中的g_listHead上的回调函数。
set_video_init_complete_cb(notify_videos_inited);
static void notify_videos_inited(int is_record_mode)
{
int mode = is_record_mode ? MODE_RECORDING : MODE_PHOTO;
assert(mode == cur_mode);
api_send_msg(MSG_MODE_CHANGE_NOTIFY, TYPE_WIFI, (void *)pre_mode, (void *)mode);
}
sd_reg_event_callback(sd_event_callback);
sd卡改变的时候,需要做的一些sd卡的挂载,初始化等操作。
USER_RegEventCallback(user_event_callback);
user_event_callback回调函数的作用处理用户事件的回调。
VIDEOPLAY_RegEventCallback(videoplay_event_callback);
videoplay_event_callback回调函数的视频播放的推出和更新。
fs_msg_file_reg_callback(fsfile_event_callbak);
fsfile_event_callbak:处理文件系统的事件
storage_setting_reg_event_callback(storage_setting_callback);
storage_setting_callback:设置文件的大小和路径。
wifi_management_start:
代码流程:
wifi_management_start
Set_CPUSerial_forSSID()//obtain ssid from cpu
Set_system_Version_param();//set version param
reg_msg_manager_cb();//register the function of callback wifi_msg_manager_cb in the file wifi_setting_interface.c -------msg_list_manager.c g_listHead
wifi_driver_reboot_thread();//
parameter_getwifiinfo(SSID, PASSWD);//get wifi ssid and passwd
socket_thread_create();
这里比较重要的是socket_thread_create(void),主要是建立了几个线程。
下面主要分析此函数:
建立的线程:udp_server_thread,hg_cgi_request_thread,hg_cgi_response_thread,daemon_thread。
下面依次分析:
udp_server_thread:创建端口号为8888的udp服务端用于接收手机app发送的消息,并且解析消息中的数据数据帧,根据消息的数据帧的id调用对应的命令执行函数。
1.建立udp服务器端口号8888---创建socket udp_server_fd,bind udp sockaddr
2.创建线程UdpSend_Thread---调用hg_api_send_udp_response向app发送心跳包(1s的频率)和温度信息(10s的频率)
hg_api_send_udp_response
SendResultMessage(messageID, messageFlag, messageLength);//the function organizes the information to be sent
sendto(udp_server_fd, GetMessageBuff(), 31*sizeof(char), 0, (struct sockaddr *)&server_add, sizeof(server_add));//send info to app
memset(GetMessageBuff(), 0, sizeof(char)*1024);
3.recvMsg(udp_server_fd, data, recbytes);----从接收到的数据消息中解析出具体的完整的信息帧以0x7e 0x7e开头的,并解析出信息帧中的命令参数等信息。
recvMsg(int nfp, char *data, int recbytes)
hg_parameter_resolve(buffer);
cmd_resolve(nfp, buffer);
hg_parameter_resolve(buffer);
解析出接受到的消息帧buffer中的messageBodyID,根据messageBodyID的不同作出不同的判断,如:录像的打开关闭,实时视频的开始结束,拍照模式的设置,,曝光,白平衡以及adb msc模式的切换的命令等等。完成后再将相对应的命令的字符串copy到buffer中。
cmd_resolve(nfp, buffer);
将上面的函数hg_parameter_resolve(buffer);解析出来的命令字符串
cmd_resolve(nfp, buffer);
具体代码如下所示,主要是根据参数cmdstr命令字符串和命令执行函数的对照表cmd_tab作出对比,并调用相应的命令函数执行。
static int cmd_resolve(int fd, char *cmdstr)
{
size_t i = 0;
for (i = 0; i < sizeof(cmd_tab) / sizeof(cmd_tab[1]); i++) {
char *result = strstr(cmdstr, CMD_PREFIX);
if (result != NULL) {
size_t cmdlen = strlen(cmd_tab[i].cmd);
if (strncmp(result, cmd_tab[i].cmd, cmdlen) == 0) {
if (cmd_tab[i].func != NULL)
cmd_tab[i].func(fd, result);
cmdstr = result + cmdlen;
if (*cmdstr == '