#include #include #include /* low-level i/o */ #include /* getopt_long() */ #include #include #include #include #include #include #include #include #include #include "common/mediactl/mediactl.h" #include "rk_aiq_user_api_sysctl.h" #include "../utils/log.h" #include "config.h" #define CLEAR(x) memset(&(x), 0, sizeof(x)) #define DBG(...) \ do { \ if (!silent) printf("DBG: " __VA_ARGS__); \ } while (0) #define ERR(...) \ do { \ fprintf(stderr, "ERR: " __VA_ARGS__); \ } while (0) /* Private v4l2 event */ #define CIFISP_V4L2_EVENT_STREAM_START (V4L2_EVENT_PRIVATE_START + 1) #define CIFISP_V4L2_EVENT_STREAM_STOP (V4L2_EVENT_PRIVATE_START + 2) #define RKAIQ_FILE_PATH_LEN 64 #define RKAIQ_FLASH_NUM_MAX 2 /* 1 vicap + 2 mipi + 1 bridge + 1 redundance */ #define MAX_MEDIA_NODES 5 #if SYS_START #define IQ_PATH "/etc/iqfiles" #elif CONFIG_OEM #define IQ_PATH "/oem/etc/iqfiles" #else #define IQ_PATH "/etc/iqfiles" #endif #if CONFIG_DBUS #if CONFIG_CALLFUNC #include "call_fun_ipc.h" #include "fun_map.h" #endif #include #endif #if CONFIG_DBSERVER #include "db_monitor.h" #include "isp_func.h" #include "isp_n2d_ctl.h" #include "manage.h" #endif enum { LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG }; int enable_minilog = 0; #define LOG_TAG "ispserver" int ispserver_log_level = LOG_INFO; #define CLEAR(x) memset(&(x), 0, sizeof(x)) rk_aiq_sys_ctx_t *db_aiq_ctx = NULL; rk_aiq_working_mode_t mode[MAX_MEDIA_NODES] = { RK_AIQ_WORKING_MODE_ISP_HDR2, RK_AIQ_WORKING_MODE_ISP_HDR2, RK_AIQ_WORKING_MODE_ISP_HDR2, RK_AIQ_WORKING_MODE_ISP_HDR2, RK_AIQ_WORKING_MODE_ISP_HDR2}; static int silent = 0; static int width = 2688; static int height = 1520; static int has_mul_cam = 0; static int fixfps = -1; static bool need_sync_db = true; #if SYS_START static bool is_quick_start = true; #else static bool is_quick_start = false; #endif struct rkaiq_media_info { char sd_isp_path[RKAIQ_FILE_PATH_LEN]; char vd_params_path[RKAIQ_FILE_PATH_LEN]; char vd_stats_path[RKAIQ_FILE_PATH_LEN]; char mainpath[RKAIQ_FILE_PATH_LEN]; char sensor_entity_name[32]; char mdev_path[32]; int available; rk_aiq_sys_ctx_t *aiq_ctx; pthread_t pid; int camIndex; }; static struct rkaiq_media_info media_infos[MAX_MEDIA_NODES]; static void errno_exit(const char *s) { ERR("%s error %d, %s\n", s, errno, strerror(errno)); exit(EXIT_FAILURE); } static int xioctl(int fh, int request, void *arg) { int r; do { r = ioctl(fh, request, arg); } while (-1 == r && EINTR == errno); return r; } static int save_prepare_status(int cam_id, int status) { char pipe_name[128]; char data[32]; sprintf(pipe_name, "/tmp/.ispserver_cam%d", cam_id); int fd = open(pipe_name, O_RDWR | O_CREAT | O_TRUNC | O_SYNC); if (fd > 0) { snprintf(data, sizeof(data), "%d", status); write(fd, data, strlen(data)); close(fd); sync(); } else { printf("save_prepare_status open err\n"); } } static int rkaiq_get_devname(struct media_device *device, const char *name, char *dev_name) { const char *devname; struct media_entity *entity = NULL; entity = media_get_entity_by_name(device, name, strlen(name)); if (!entity) return -1; devname = media_entity_get_devname(entity); if (!devname) { fprintf(stderr, "can't find %s device path!", name); return -1; } strncpy(dev_name, devname, RKAIQ_FILE_PATH_LEN); DBG("get %s devname: %s\n", name, dev_name); return 0; } int rkaiq_get_media_info(struct rkaiq_media_info *media_info) { struct media_device *device = NULL; const char *sensor_name; int ret; device = media_device_new(media_info->mdev_path); if (!device) return -ENOMEM; /* Enumerate entities, pads and links. */ ret = media_device_enumerate(device); if (ret) return ret; if (!ret) { /* Try rkisp */ ret = rkaiq_get_devname(device, "rkisp-isp-subdev", media_info->sd_isp_path); ret |= rkaiq_get_devname(device, "rkisp-input-params", media_info->vd_params_path); ret |= rkaiq_get_devname(device, "rkisp-statistics", media_info->vd_stats_path); ret |= rkaiq_get_devname(device, "rkisp_mainpath", media_info->mainpath); } if (ret) { fprintf(stderr, "Cound not find rkisp dev names, skipped %s\n", media_info->mdev_path); media_device_unref(device); return ret; } printf("=======mainpath=%s\n", media_info->mainpath); sensor_name = rk_aiq_uapi_sysctl_getBindedSnsEntNmByVd(media_info->mainpath); if (sensor_name == NULL || strlen(sensor_name) == 0) { fprintf(stderr, "ERR: No sensor attached to %s\n", media_info->mdev_path); media_device_unref(device); return -EINVAL; } printf("get sensor name=%s\n", sensor_name); strcpy(media_info->sensor_entity_name, sensor_name); media_device_unref(device); return ret; } static void db_config_sync(char *hdr_mode) { #if CONFIG_DBSERVER if (need_sync_db && !is_quick_start) { /* IMAGE_ADJUSTMENT */ int brightness = 50; int contrast = 50; int saturation = 50; int sharpness = 50; int hue = 50; hash_image_adjustment_get(&brightness, &contrast, &saturation, &sharpness, &hue); LOG_INFO( "brightness:%d, contrast:%d, saturation:%d, sharpness:%d, hue:%d\n\n", brightness, contrast, saturation, sharpness, hue); brightness_set(brightness); contrast_set(contrast); saturation_set(saturation); sharpness_set(sharpness); hue_set(hue); /* EXPOSURE */ exposure_para_set_by_hash(); /* BLC */ if (0 != atoi(hdr_mode)) { int hdr_level = 0; hash_image_blc_get(NULL, &hdr_level, NULL, NULL, NULL); blc_hdr_level_enum_set(hdr_level); } else { blc_normal_mode_para_set_by_hash(); } /* IMAGE_ENHANCEMENT */ nr_mode_t hash_nr_mode; dc_mode_t hash_dc_mode; work_mode_2_t dehaze_mode; int spatial_level = 0; int temporal_level = 0; int fec_level = 0; int dehaze_level = 0; int ldch_level = 0; int rotation_angle = 0; hash_image_enhancement_get(&hash_nr_mode, &hash_dc_mode, &dehaze_mode, &spatial_level, &temporal_level, &dehaze_level, &ldch_level, &fec_level, &rotation_angle); LOG_INFO( "nr_mode:%d, distortion_correction_mode:%d, dehaze_mode:%d, " "spatial_level:%d, temporal_level:%d, dehaze_level:%d, " "ldch_level:%d, fec_level:%d, rotation_angle: %d\n\n", hash_nr_mode, hash_dc_mode, dehaze_mode, spatial_level, temporal_level, dehaze_level, ldch_level, fec_level, rotation_angle); nr_para_set(hash_nr_mode, spatial_level, temporal_level); /* IMAGE_ADJUSTMENT */ expPwrLineFreq_t frequency_mode; flip_mode_t mirror_mode; hash_image_video_adjustment_get(&frequency_mode, &mirror_mode); LOG_INFO("frequency_mode is %d, mirror_mode is %d\n\n", frequency_mode, mirror_mode); frequency_mode_set(frequency_mode); dehaze_para_set(dehaze_mode, dehaze_level); dc_para_set(hash_dc_mode, ldch_level, fec_level); /* WHITE_BALANCE */ white_balance_set_by_hash_table(); mirror_mode_set(mirror_mode); /* only for fbc*/ bypass_stream_rotation_set(rotation_angle); /* NIGHT_TO_DAY*/ night_to_day_para_cap_set_db(); night2day_loop_run(); } #endif } static void init_engine(struct rkaiq_media_info *media_info) { int index; #if CONFIG_DBSERVER if (need_sync_db && !is_quick_start) { rk_aiq_working_mode_t hdr_mode_db = RK_AIQ_WORKING_MODE_NORMAL; while (hash_image_hdr_mode_get4init(&hdr_mode_db)) { LOG_INFO("Get data is empty, please start dbserver\n"); sleep(1); } LOG_INFO("hdr_mode_db: %d \n", hdr_mode_db); switch (hdr_mode_db) { case RK_AIQ_WORKING_MODE_NORMAL: { setenv("HDR_MODE", "0", 1); LOG_DEBUG("set hdr normal\n"); break; } case RK_AIQ_WORKING_MODE_ISP_HDR2: { setenv("HDR_MODE", "1", 1); break; } case RK_AIQ_WORKING_MODE_ISP_HDR3: { setenv("HDR_MODE", "2", 1); break; } } } #endif char *hdr_mode = getenv("HDR_MODE"); if (hdr_mode) { LOG_INFO("hdr mode: %s\n", hdr_mode); if (0 == atoi(hdr_mode)) mode[media_info->camIndex] = RK_AIQ_WORKING_MODE_NORMAL; else if (1 == atoi(hdr_mode)) mode[media_info->camIndex] = RK_AIQ_WORKING_MODE_ISP_HDR2; else if (2 == atoi(hdr_mode)) mode[media_info->camIndex] = RK_AIQ_WORKING_MODE_ISP_HDR3; } else { mode[media_info->camIndex] = RK_AIQ_WORKING_MODE_NORMAL; } /* if (media_info[media_info->camIndex].fix_nohdr_mode) mode[media_info->camIndex] = RK_AIQ_WORKING_MODE_NORMAL; for (index = 0; index < RKAIQ_CAMS_NUM_MAX; index++) if (media_info[cam_id].cams[index].link_enabled) break; */ media_info->aiq_ctx = rk_aiq_uapi_sysctl_init(media_info->sensor_entity_name, IQ_PATH, NULL, NULL); if (has_mul_cam) rk_aiq_uapi_sysctl_setMulCamConc(media_info->aiq_ctx, 1); #if CONFIG_DBSERVER /* sync fec from db*/ if (need_sync_db && !is_quick_start) { int fec_en; hash_image_fec_enable_get4init(&fec_en, NULL); int fec_ret = rk_aiq_uapi_setFecEn(media_info->aiq_ctx, fec_en); LOG_INFO("set fec_en: %d, ret is %d\n", fec_en, fec_ret); } /* sync hdr mode for quick_start */ if (!need_sync_db || is_quick_start) { hdr_global_value_set(mode[media_info->camIndex]); } #endif if (rk_aiq_uapi_sysctl_prepare(media_info->aiq_ctx, width, height, RK_AIQ_WORKING_MODE_NORMAL)) { ERR("rkaiq engine prepare failed !\n"); exit(-1); } db_aiq_ctx = media_info->aiq_ctx; save_prepare_status(media_info->camIndex, 1); #if CONFIG_DBSERVER set_stream_on(); #endif if (fixfps > 0) { #if CONFIG_DBSERVER isp_fix_fps_set(fixfps); #else frameRateInfo_t fps_info; memset(&fps_info, 0, sizeof(fps_info)); fps_info.fps = fixfps; fps_info.mode = OP_MANUAL; rk_aiq_uapi_setFrameRate(media_info->aiq_ctx, fps_info); #endif } db_config_sync(hdr_mode); } static void start_engine(struct rkaiq_media_info *media_info) { DBG("device manager start\n"); rk_aiq_uapi_sysctl_start(media_info->aiq_ctx); if (media_info->aiq_ctx == NULL) { ERR("rkisp_init engine failed\n"); exit(-1); } else { #if CONFIG_DBSERVER #if SYS_START send_stream_on_signal(); #endif #endif DBG("rkisp_init engine succeed\n"); } } static void stop_engine(struct rkaiq_media_info *media_info) { rk_aiq_uapi_sysctl_stop(media_info->aiq_ctx, false); } static void deinit_engine(struct rkaiq_media_info *media_info) { #if CONFIG_DBSERVER if (need_sync_db) { set_stream_off(); night2day_loop_stop(); } #endif save_prepare_status(media_info->camIndex, 0); rk_aiq_uapi_sysctl_deinit(media_info->aiq_ctx); } // blocked func static int wait_stream_event(int fd, unsigned int event_type, int time_out_ms) { int ret; struct v4l2_event event; CLEAR(event); do { /* * xioctl instead of poll. * Since poll() cannot wait for input before stream on, * it will return an error directly. So, use ioctl to * dequeue event and block until sucess. */ ret = xioctl(fd, VIDIOC_DQEVENT, &event); if (ret == 0 && event.type == event_type) return 0; } while (true); return -1; } static int subscrible_stream_event(struct rkaiq_media_info *media_info, int fd, bool subs) { struct v4l2_event_subscription sub; int ret = 0; CLEAR(sub); sub.type = CIFISP_V4L2_EVENT_STREAM_START; ret = xioctl(fd, subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT, &sub); if (ret) { ERR("can't subscribe %s start event!\n", media_info->vd_params_path); exit(EXIT_FAILURE); } CLEAR(sub); sub.type = CIFISP_V4L2_EVENT_STREAM_STOP; ret = xioctl(fd, subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT, &sub); if (ret) { ERR("can't subscribe %s stop event!\n", media_info->vd_params_path); } DBG("subscribe events from %s success !\n", media_info->vd_params_path); return 0; } void *wait_thread_func() { LOG_INFO("wait_thread_func...q: %d, db: %d\n", is_quick_start, need_sync_db); #if CONFIG_DBSERVER database_hash_init(); while (!wait_dbus_init_func()) { if (dbus_warn_log_status_get()) { dbus_warn_log_close(); } LOG_INFO("wait for dbus init\n"); usleep(100000); } if (need_sync_db) { dbus_warn_log_open(); } database_init(); manage_init(); rk_aiq_working_mode_t hdr_mode_db = RK_AIQ_WORKING_MODE_NORMAL; hash_image_hdr_mode_get4init(&hdr_mode_db); hdr_mode_set4db(hdr_mode_db); switch (hdr_mode_db) { case RK_AIQ_WORKING_MODE_NORMAL: is_quick_start = false; db_config_sync("0"); break; case RK_AIQ_WORKING_MODE_ISP_HDR2: is_quick_start = false; db_config_sync("1"); break; case RK_AIQ_WORKING_MODE_ISP_HDR3: is_quick_start = false; db_config_sync("2"); break; default: LOG_ERROR("undefine hdr mode: %d, fail to sync db config\n", hdr_mode_db); break; } #endif } static void main_exit(void) { LOG_INFO("server %s\n", __func__); for (int id = 0; id < MAX_MEDIA_NODES; id++) { if (media_infos[id].available) { LOG_INFO("stop engine camera index %d...\n", id); stop_engine(&media_infos[id]); LOG_INFO("deinit engine camera index %d...\n", id); deinit_engine(&media_infos[id]); media_infos[id].available = 0; } } #if CONFIG_DBUS #if CONFIG_CALLFUNC LOG_INFO("deinit call_fun_ipc_server...\n"); call_fun_ipc_server_deinit(); #endif #endif } void signal_crash_handler(int sig) { #if CONFIG_DBUS #if CONFIG_CALLFUNC call_fun_ipc_server_deinit(); #endif #endif exit(-1); } void signal_exit_handler(int sig) { #if CONFIG_DBUS #if CONFIG_CALLFUNC call_fun_ipc_server_deinit(); #endif #endif exit(0); } void parse_args(int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"silent", no_argument, 0, 's'}, {"help", no_argument, 0, 'h'}, {"nsd", no_argument, NULL, 'n'}, {"fps", required_argument, NULL, 'f'}, {0, 0, 0, 0}}; c = getopt_long(argc, argv, "shnf", long_options, &option_index); if (c == -1) break; switch (c) { case 'w': width = atoi(optarg); break; case 'h': height = atoi(optarg); break; case 's': silent = 1; break; case 'f': fixfps = atoi(optarg); LOG_INFO("## fixfps: %d\n", fixfps); break; case 'n': need_sync_db = false; LOG_INFO("## need_sync_db: %d\n", need_sync_db); break; case '?': ERR("Usage: %s to start 3A engine\n" " --silent, optional, subpress debug log\n", argv[0]); exit(-1); default: ERR("?? getopt returned character code %c ??\n", c); } } } void *engine_thread(void *arg) { int ret = 0; int isp_fd; unsigned int stream_event = -1; struct rkaiq_media_info *media_info; media_info = (struct rkaiq_media_info *)arg; isp_fd = open(media_info->vd_params_path, O_RDWR); if (isp_fd < 0) { ERR("open %s failed %s\n", media_info->vd_params_path, strerror(errno)); return NULL; } subscrible_stream_event(media_info, isp_fd, true); init_engine(media_info); for (;;) { DBG("%s: wait stream start event...\n", media_info->mdev_path); wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_START, -1); DBG("%s: wait stream start event success ...\n", media_info->mdev_path); start_engine(media_info); DBG("%s: wait stream stop event...\n", media_info->mdev_path); wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_STOP, -1); DBG("%s: wait stream stop event success ...\n", media_info->mdev_path); stop_engine(media_info); #if CONFIG_DBSERVER if (!check_stream_status()) break; #endif } deinit_engine(media_info); subscrible_stream_event(media_info, isp_fd, false); close(isp_fd); return NULL; } int main(int argc, char **argv) { #ifdef ENABLE_MINILOGGER enable_minilog = 1; __minilog_log_init(argv[0], NULL, false, false, "ispserver", "1.0.0"); #endif int ret, i; int threads = 0; /* Line buffered so that printf can flash every line if redirected to * no-interactive device. */ setlinebuf(stdout); parse_args(argc, argv); for (i = 0; i < MAX_MEDIA_NODES; i++) { sprintf(media_infos[i].mdev_path, "/dev/media%d", i); if (rkaiq_get_media_info(&media_infos[i])) { ERR("Bad media topology for: %s\n", media_infos[i].mdev_path); media_infos[i].available = 0; continue; } media_infos[i].available = 1; media_infos[i].camIndex = i; threads++; } if (threads > 1) has_mul_cam = 1; #if CONFIG_DBSERVER if (!need_sync_db) dbus_warn_log_close(); if (wait_dbus_init_func()) { LOG_INFO("dbus init complete, alter quick start false\n"); is_quick_start = false; } if (!is_quick_start && (need_sync_db || wait_dbus_init_func())) { LOG_INFO("init for db\n"); database_hash_init(); database_init(); manage_init(); } LOG_INFO("before enter wait thread q: %d, db: %d\n", is_quick_start, need_sync_db); if (is_quick_start || !need_sync_db) { pthread_t wait_db_p; if (pthread_create(&wait_db_p, NULL, wait_thread_func, NULL) != 0) { LOG_INFO("enter wait thread for db error\n"); } } #endif for (i = 0; i < MAX_MEDIA_NODES; i++) { if (!media_infos[i].available) continue; ret = pthread_create(&media_infos[i].pid, NULL, engine_thread, &media_infos[i]); if (ret) { media_infos[i].pid = 0; ERR("Failed to create camera engine thread for: %s\n", media_infos[i].mdev_path); errno_exit("Create thread failed"); } } #if CONFIG_DBUS pthread_detach(pthread_self()); GMainLoop *main_loop; atexit(main_exit); signal(SIGTERM, signal_exit_handler); signal(SIGINT, signal_exit_handler); signal(SIGPIPE, SIG_IGN); signal(SIGBUS, signal_crash_handler); signal(SIGSEGV, signal_crash_handler); signal(SIGFPE, signal_crash_handler); signal(SIGABRT, signal_crash_handler); #if CONFIG_CALLFUNC call_fun_ipc_server_init(map, sizeof(map) / sizeof(struct FunMap), DBUS_NAME, DBUS_IF, DBUS_PATH, 0); LOG_INFO("call_fun_ipc_demo_server init\n"); #endif main_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(main_loop); if (main_loop) g_main_loop_unref(main_loop); #endif for (i = 0; i < MAX_MEDIA_NODES; i++) { if (!media_infos[i].available || media_infos[i].pid == 0) continue; pthread_join(media_infos[i].pid, NULL); } return 0; }