rk_isp_set_night_to_day函数
rkipc控制ircut主要通过rk_isp_set_night_to_day函数,例如在ser_rk_isp_set_night_to_day函数中
int ser_rk_isp_set_night_to_day(int fd) {int ret = 0;int id, len;char *value = NULL;if (sock_read(fd, &id, sizeof(id)) == SOCKERR_CLOSED)return -1;if (sock_read(fd, &len, sizeof(len)) == SOCKERR_CLOSED)return -1;if (len) {value = (char *)malloc(len);//读取前段发过来的值if (sock_read(fd, value, len) == SOCKERR_CLOSED) {free(value);return -1;}LOG_DEBUG("id is %d, value is %s\n", id, value);//设置日夜模式,会对ircut进行操作ret = rk_isp_set_night_to_day(id, value);free(value);if (sock_write(fd, &ret, sizeof(int)) == SOCKERR_CLOSED)return -1;}
rv1106的rk_isp_set_night_to_day函数在/luckfox-pico/project/app/rkipc/rkipc/common/isp/rv1106/isp.c中
int rk_isp_set_night_to_day(int cam_id, const char *value) {int ret;//检查传过来的cam_idRK_ISP_CHECK_CAMERA_ID(cam_id);aie_attrib_t attr;//获取isp的属性rk_aiq_user_api2_aie_GetAttrib(rkipc_aiq_get_ctx(cam_id), &attr);if (!strcmp(value, "night")) {//夜晚模式设置attr.mode 为 RK_AIQ_IE_EFFECT_BW;attr.mode = RK_AIQ_IE_EFFECT_BW;rk_aiq_user_api2_aie_SetAttrib(rkipc_aiq_get_ctx(cam_id), &attr);//ircut设置为假rk_isp_enable_ircut(false);} else {//白天模式ircut设置为真rk_isp_enable_ircut(true);//关灯if (light_state == 1)rk_isp_close_light(3);//夜晚模式设置attr.mode 为 RK_AIQ_IE_EFFECT_NONE;attr.mode = RK_AIQ_IE_EFFECT_NONE;rk_aiq_user_api2_aie_SetAttrib(rkipc_aiq_get_ctx(cam_id), &attr);}//改写ini文件char entry[128] = {'\0'};snprintf(entry, 127, "isp.%d.night_to_day:night_to_day", rkipc_get_scenario_id(cam_id));rk_param_set_string(entry, value);return ret;
}
对ircut的操作由rk_isp_enable_ircut函数完成
rk_isp_enable_ircut函数
int rk_isp_enable_ircut(bool on) {int ret, open_gpio, close_gpio;//ircut_open_gpio = 36//ircut_close_gpio = 35open_gpio = rk_param_get_int("isp:ircut_open_gpio", -1);close_gpio = rk_param_get_int("isp:ircut_close_gpio", -1);if ((open_gpio < 0) || (close_gpio < 0)) {LOG_ERROR("fail get gpio form ini file\n");return -1;}//设置gpio方向ret = rk_gpio_export_direction(open_gpio, false);ret |= rk_gpio_export_direction(close_gpio, false);//设置值if (on) {rk_gpio_set_value(open_gpio, 1);usleep(100 * 1000);rk_gpio_set_value(open_gpio, 0);} else {rk_gpio_set_value(close_gpio, 1);usleep(100 * 1000);rk_gpio_set_value(close_gpio, 0);}//关闭gpio控制rk_gpio_unexport(open_gpio);rk_gpio_unexport(close_gpio);return ret;
}
gpio的编号计算
rv1106 GPIO的命名是GPIO{bank}_{group}{X},比如GPIO0_A0到A7,然后计算公式是pin = bank * 32 + (group * 8 + X)。例如,GPIO1_C7_d的bank是1,group是C对应2,X是7,所以计算是132 + (28+7)=55。(夸克说的)
本电路板的ircut+ 接 mx2804的 OUTB,ircut- 接 mx2804的 OUTA
mx2804的 INB 接 rv1106的pin114 GPIO2_A5_d 232+08+5=69
mx2804的 INA 接 rv1106的pin113 GPIO2_A4_d 232+08+4=68
rk_gpio_export_direction函数
该函数在luckfox-pico/project/app/rkipc/rkipc/src/rv1126_ipc_rkmedia/rk_gpio.c中
int rk_gpio_export_direction(uint32_t gpio, enum gpio_direction input) {int ret;//取得控制权ret = rk_gpio_export(gpio);if (ret < 0)goto out;//设置方向,真为输入ret = rk_gpio_set_direction(gpio, input);if (ret < 0)rk_gpio_unexport(gpio);
out:return ret;
}
rk_gpio_export函数
#define GPIO_SYSFS_PATH "/sys/class/gpio"int rk_gpio_export(uint32_t gpio) {int ret;char file[64];//例如ircut+的GPIO为69, //file为"/sys/class/gpio/gpio69"ret = sprintf(file, "%s/gpio%d", GPIO_SYSFS_PATH, gpio);if (ret < 0)return ret;//如果gpio被占用if (!access(file, F_OK)) {printf("warning: gpio %d, file (%s) has exist\n", gpio, file);return 0;}return write_sysfs_int("export", GPIO_SYSFS_PATH, gpio);
}
int write_sysfs_int(const char *filename, const char *basedir, int val) {return _write_sysfs_int(filename, basedir, val, false);
}
//filename "export"
//basedir "/sys/class/gpio"
//val 69
//verify false
static int _write_sysfs_int(const char *filename, const char *basedir, int val, bool verify) {int ret = 0;FILE *sysfsfp;int test;char *temp = (char *)malloc(strlen(basedir) + strlen(filename) + 2);if (!temp)return -ENOMEM;//temp /sys/class/gpio/exportret = sprintf(temp, "%s/%s", basedir, filename);if (ret < 0)goto error_free;//写打开/sys/class/gpio/exportsysfsfp = fopen(temp, "w");if (!sysfsfp) {ret = -errno;fprintf(stderr, "failed to open %s\n", temp);goto error_free;}//写入要export的gpio编号ret = fprintf(sysfsfp, "%d", val);if (ret < 0) {if (fclose(sysfsfp))perror("_write_sysfs_int(): Failed to close dir");goto error_free;}//关闭if (fclose(sysfsfp)) {ret = -errno;goto error_free;}if (verify) {sysfsfp = fopen(temp, "r");if (!sysfsfp) {ret = -errno;fprintf(stderr, "failed to open %s\n", temp);goto error_free;}if (fscanf(sysfsfp, "%d", &test) != 1) {ret = errno ? -errno : -ENODATA;if (fclose(sysfsfp))perror("_write_sysfs_int(): Failed to close dir");goto error_free;}if (fclose(sysfsfp)) {ret = -errno;goto error_free;}if (test != val) {fprintf(stderr, "Possible failure in int write %d to %s/%s\n", val, basedir, filename);ret = -1;}}error_free:free(temp);return ret;
}
这样系统就取得了gpio的控制权。
rk_gpio_set_direction函数
int rk_gpio_set_direction(uint32_t gpio, enum gpio_direction input) {int ret;char path[64];const char *direction = input ? "in" : "out";ret = sprintf(path, "%s/gpio%d", GPIO_SYSFS_PATH, gpio);if (ret < 0)return ret;return write_sysfs_string_and_verify("direction", path, direction);
}
和上面一样,只是换成"direction"和gpio的路径
rk_gpio_set_value
和上面差不多,最终调用write_sysfs_string_and_verify进行gpio管脚设置
int rk_gpio_set_value(uint32_t gpio, int value) {int ret;char path[64] = {0};char direction[8] = {0};ret = sprintf(path, "%s/gpio%d", GPIO_SYSFS_PATH, gpio);if (ret < 0)return ret;ret = read_sysfs_string("direction", path, direction);if (ret < 0)return ret;if (strcmp(direction, "out") != 0)return -EINVAL;return write_sysfs_int_and_verify("value", path, value);
}
rk_gpio_unexport函数
和rk_gpio_export相反,原理也差不多,通过write_sysfs_int(“unexport”, GPIO_SYSFS_PATH, gpio);进行取消控制权限。