在操作级别的服务函数之上,需要定义功能级服务函数,
这些功能级服务函数,需要调用大部分类对象提供的服务函数。
为了增强可读性,也设计了大量的操作级别的服务函数,用来为功能级服务函数提供调用。
1)自检功能
void SystemManager::selftest()
{
xmotor_.set_motor_selftest();
}
通过调用MotorMCU这个class提供的服务函数,完成自检功能。
2)系统配置打印功能
void SystemManager::system_state(int value)
{
syslog("system_state=%d\r\n", value);
debug_mode_ = value;
if (debug_mode_ == 0)
return;
syslog("ts=%u, host_irq=%u, mcu_irq=%u, sensor_irq=%u, sensor_frame_count=%u, focus_motor_reach_=%d\r\n", get_timestamp(), host_uart_.irq_count, mcu_uart_.irq_count, cam_uart_.irq_count, sensor_frame_count_, focus_motor_reach_);
syslog("video_lock=%d, photo_lock=%d\r\n", xin_.get_video_lock(), xin_.get_photo_lock());
u32 clarity = xaf_accl_.get_clarity_value();
syslog("clarity=%d, zoom_motor=%d, focus_motor: %d\r\n", clarity, xmotor_.zoom_motor_value_, xmotor_.focus_motor_value_);
syslog("focus: min=%d, max=%d, best=%d, focus_direct_mode=%d, focus_radio=%d\r\n", xaf_.af_min_focus_, xaf_.af_max_focus_, xaf_.af_init_focus_, xmotor_.focus_direct_mode_, focus_radio_);
syslog("dehazing_mode=%d, hdr_mode=%d, enhance_mode=%d, awb_mode=%d, flip_mode=%d\r\n", dehazing_mode_, hdr_mode_, enhance_mode_, awb_mode_, flip_mode_);
u32 current_hsize = 0, current_vsize = 0, max_hsize = 0, max_vsize = 0;
xcmos_.get_current_hsize(¤t_hsize);
xcmos_.get_current_vsize(¤t_vsize);
xcmos_.get_max_hsize(&max_hsize);
xcmos_.get_max_vsize(&max_vsize);
syslog("C5180 size: (%d %d) (%d %d)\r\n", current_hsize, current_vsize, max_hsize, max_vsize);
syslog("sensor crop: (%d %d %d %d)\r\n", xbayer_video_.crop_x_, xbayer_video_.crop_y_, xbayer_video_.crop_width_, xbayer_video_.crop_height_);
syslog("sensor_uart=%d, mcu_uart=%d, host_uart=%d\r\n", ring_buffer_valid_len(&cam_uart_.recv_buff), ring_buffer_valid_len(&mcu_uart_.recv_buff), ring_buffer_valid_len(&host_uart_.recv_buff));
...
}
在board_common.h这个H文件中定义了
#define syslog(...) xil_printf(__VA_ARGS__)
使得syslog可以作为xil_printf的别名使用。
3)加载默认配置参数功能。
void SystemManager::load_default_config()
{
//C5180
xcmos_.set_aoi_hsize(sensor_width_);
xcmos_.set_aoi_vsize(sensor_height_);
xcmos_.set_aoi_hoff(0);
xcmos_.set_aoi_voff(480);
xcmos_.set_pixel_clock_rate(110);
xcmos_.set_fixed_frame_period(33333);
xcmos_.set_fixed_frame_period_en(1);
xcmos_.set_digital_gain(1024);
xcmos_.set_anglog_gain(0);
#if SENSOR_TRIGGER_ENABLE
xcmos_.set_ignore_next_trigger(1);
xcmos_.set_trigger_edge_selector(0);
xcmos_.set_trigger_input(2);
xcmos_.set_trigger_enable(1);
xcmos_.set_exposure_mode(1);
xout_.set_exposure_time(15000);
#else
xcmos_.set_trigger_enable(0);
xcmos_.set_exposure_mode(2);
xcmos_.set_exposure_time(15000);
#endif
//system
set_dehazing_mode(0);
set_color_mode(0);
set_rgbyuv_mode(0);
set_brightness_mode(0);
set_brightness_value(0);
set_contrast_mode(0);
set_contrast_value(0);
set_saturation_mode(1);
set_saturation_value(22000);
set_flip_mode(0);
set_cursor_mode(0);
set_cursor_x(video_width_ / 2);
set_cursor_y(video_height_ / 2);
set_sharpness_mode(0);
set_hdr_mode(0);
set_enhance_mode(0);
// set_sync_mode(0);
set_auto_exposure_on(0, 0);
}
注意这个函数中的几个技术点。
首先是宏开关,用于代码裁剪和代码选择。针对不同的系统配置需求,来选择不同的代码块,进入不同的处理流程。
然后是成员对象的服务函数的调用。通过在成员对象的类中,设计对应的服务函数,然后分别调用这些服务函数,可以增加程序的可读性。
然后是本类的服务函数的调用。通过在本类中,设计对应的服务函数,然后分别调用这些服务函数,可以增加程序的可读性。
4)加载配置参数功能
int SystemManager::load_config()
{
int ret;
union PageConfig cfg;
int bytes = sizeof(cfg.param);
syslog("load_config: bytes=%d\r\n", bytes);
if (bytes > 255) {
syslog("/-------------------------------------------------------------------------------------/\r\n");
syslog("error: config bytes too large!\r\n");
syslog("/-------------------------------------------------------------------------------------/\r\n");
}
ret = spi_flash_read_page(&sys_flash_, 0);
if (ret < 0)
{
syslog("spi_flash_read_page error!\r\n");
return -1;
}
memcpy(cfg.data, &sys_flash_.ReadBuffer[4], PAGE_SIZE);
ret = check_sum_crc(cfg.data, PAGE_SIZE - 1, cfg.data[PAGE_SIZE - 1]);
if (ret < 0)
{
syslog("load config crc error\r\n");
return -1;
}
set_dehazing_mode(cfg.param.dehazing_mode);
set_color_mode(cfg.param.color_mode);
set_rgbyuv_mode(cfg.param.rgbyuv_mode);
set_brightness_mode(cfg.param.brightness_mode);
set_brightness_value(cfg.param.brightness_value);
set_contrast_mode(cfg.param.contrast_mode);
set_contrast_value(cfg.param.contrast_value);
set_saturation_mode(cfg.param.saturation_mode);
set_saturation_value(cfg.param.saturation_value);
set_flip_mode(cfg.param.flip_mode);
set_cursor_mode(cfg.param.cursor_mode);
set_cursor_x(cfg.param.cursor_x);
set_cursor_y(cfg.param.cursor_y);
set_awb_mode(cfg.param.awb_mode);
set_focus_radio(cfg.param.focus_radio);
set_sharpness_mode(cfg.param.sharpness_mode);
set_hdr_mode(cfg.param.hdr_mode);
set_enhance_mode(cfg.param.enhance_mode);
set_focus_direct_mode(cfg.param.focus_direct_mode);
if (cfg.param.exposure_mode)
set_auto_exposure_on(0, 0);
else
set_auto_exposure_off(cfg.param.exposure_time);
set_auto_focus_param(cfg.param.af_min_focus, cfg.param.af_max_focus, cfg.param.af_init_focus);
syslog("load config ok!\r\n");
return 0;
}
注意这个函数中的几个技术点。
首先是union的使用,可以进行便捷的内存块截取并强制类型转换。
union实际上用简洁的代码,完成了几个步骤的操作,首先将当前选取的member,解析成pointer和length,然后用pointer和length,截取出一个内存块,然后将这个内存块中的值,强制类型转换成当前选取的member的类型,返回给调用者。
最常见的就是这种structure和BYTE ARRAY的联合体。
union PageConfig
{
struct ConfigParam
{
int dehazing_mode;
int color_mode;
int rgbyuv_mode;
int brightness_mode;
int brightness_value;
int contrast_mode;
int contrast_value;
int flip_mode;
int cursor_mode;
int cursor_x;
int cursor_y;
int awb_mode;
int focus_radio;
int sharpness_mode;
int hdr_mode;
int enhance_mode;
int focus_direct_mode;
int exposure_mode;
int exposure_time;
int saturation_mode;
int saturation_value;
int af_min_focus;
int af_max_focus;
int af_init_focus;
} param;
u8 data[256];
};
由于数组名即指针,这个特性可以用于memcpy。
在本例中,先以数组的视角,将数据拷贝,然后再切换视角,以struct的视角,来解析数据格式,分别选取结构体的成员,传给对应的成员变量。
然后是返回值检查,对函数返回值进行错误判别。
5)存储配置参数功能
int SystemManager::save_config()
{
int ret;
union PageConfig cfg;
//C5180
xcmos_.boot_from(1);
xcmos_.save_to_user1();
//qspi flash
int bytes = sizeof(cfg.param);
syslog("save_config: bytes=%d\r\n", bytes);
if (bytes > 255) {
syslog("/-------------------------------------------------------------------------------------/\r\n");
syslog("error: config bytes too large!\r\n");
syslog("/-------------------------------------------------------------------------------------/\r\n");
}
cfg.param.dehazing_mode = dehazing_mode_;
cfg.param.color_mode = color_mode_;
cfg.param.rgbyuv_mode = rgbyuv_mode_;
cfg.param.brightness_mode = brightness_mode_;
cfg.param.brightness_value = brightness_value_;
cfg.param.contrast_mode = contrast_mode_;
cfg.param.contrast_value = contrast_value_;
cfg.param.flip_mode = flip_mode_;
cfg.param.cursor_mode = cursor_mode_;
cfg.param.cursor_x = cursor_x_;
cfg.param.cursor_y = cursor_y_;
cfg.param.awb_mode = awb_mode_;
cfg.param.focus_radio = focus_radio_;
cfg.param.sharpness_mode = sharpness_mode_;
cfg.param.hdr_mode = hdr_mode_;
cfg.param.enhance_mode = enhance_mode_;
cfg.param.focus_direct_mode = xmotor_.focus_direct_mode_;
cfg.param.exposure_mode = exposure_mode_;
cfg.param.exposure_time = exposure_time_;
cfg.param.saturation_mode = saturation_mode_;
cfg.param.saturation_value = saturation_value_;
cfg.param.af_min_focus = xaf_.af_min_focus_;
cfg.param.af_max_focus = xaf_.af_max_focus_;
cfg.param.af_init_focus = xaf_.af_init_focus_;
cfg.data[PAGE_SIZE - 1] = calc_sum_crc(cfg.data, PAGE_SIZE - 1);
memcpy(&sys_flash_.WriteBuffer[4], cfg.data, PAGE_SIZE);
ret = spi_flash_write_enable(&sys_flash_);
if (ret < 0)
{
syslog("spi_flash_write_enable error!\r\n");
return -1;
}
ret = spi_flash_sector_erase(&sys_flash_, 0);
if (ret < 0)
{
syslog("spi_flash_sector_erase error!\r\n");
return -1;
}
ret = spi_flash_write_enable(&sys_flash_);
if (ret < 0)
{
syslog("spi_flash_write_enable error!\r\n");
return -1;
}
ret = spi_flash_write_page(&sys_flash_, 0);
if (ret < 0)
{
syslog("spi_flash_write_page error!\r\n");
return -1;
}
syslog("save config ok!\r\n");
return 0;
}
注意这个函数中的几个技术点。
首先是union的使用,可以通过切换数据视角的方式,解析同一个内存块,将内存块解析成不同的数据格式。
在本例中,首先以结构体的视角,用成员变量的值,填充结构体中的各成员,
然后,再切换到byte array的视角,整体拷贝给buffer。
然后是返回值检查,对函数返回值进行错误判别。
4)设备启动功能
int SystemManager::open_device()
{
//硬件初始化
isp_gpio_init(&isp_gpio_, ISP_GPIO_DEV_ID);
watchdog_init(&xwdt_, WATCHDOG_DEV_ID);
stamp_timer_init(&sys_timer_, SYS_TIMER_DEV_ID);
uart_lite_init(&host_uart_, HOST_UART_REGS_ADDR);
uart_lite_init(&mcu_uart_, MCU_UART_REGS_ADDR);
uart_lite_init(&cam_uart_, CAM_UART_REGS_ADDR);
spi_flash_init(&sys_flash_, SYS_FLASH_DEV_ID);
// 中断初始化
intc_init();
// 启动硬件
stamp_timer_start(&sys_timer_);
uart_lite_start(&host_uart_);
uart_lite_start(&mcu_uart_);
uart_lite_start(&cam_uart_);
spi_flash_start(&sys_flash_);
print("camera boot...\r\n");
//等待逻辑启动和相机启动
sleep(8);
// fpga isp 参数初始化
fpga_isp_init();
//复位逻辑电路
fpga_reset();
// hls isp 参数初始化
hls_isp_init();
// 相机初始化
sensor_init();
//等待相机配置生效
sleep(1);
// 启动hls IP
hls_isp_start();
set_auto_exposure_on(0, 0);
// set_auto_exposure_off(0);
//加载配置
if (load_config() < 0) {
load_default_config();
}
//开机默认最大视场
xmotor_.set_filter_light(9);
xmotor_.set_focus_value(9, xaf_.af_init_focus_);
//启动vtc
vtc_start();
return 0;
}