diff --git a/app/camera/camera.c b/app/camera/camera.c index 39a8a91..b268273 100644 --- a/app/camera/camera.c +++ b/app/camera/camera.c @@ -4,15 +4,23 @@ #include "FreeRTOS.h" #include "task.h" +#define _CAM_REG_NULL 0xFFFF +#define _CAM_REG_DELAY 0x0000 +#define CAMERA_SETTLE_MS 10 +#define CAMERA_FRAME_TIMEOUT 100 + +struct camera_regval { + uint16_t addr; + uint8_t val; +}; + #if _CAM_MODEL == SC031GS #include "sc031gs.h" #else #error _CAM_MODEL must be defined #endif -APP_NOCACHE(uint8_t g_camera_fb[CAMERA_FB_COUNT][CAMERA_FB_SIZE], CAMERA_BUFFER_ALIGN); -#define CAMERA_SETTLE_MS 10 -#define CAMERA_FRAME_TIMEOUT 100 +APP_NOCACHE(uint8_t g_camera_fb[CAMERA_FB_COUNT][CAMERA_FB_SIZE], CAMERA_BUFFER_ALIGN); hal_err_t _camera_reset() { hal_gpio_set(GPIO_CAMERA_PWR, GPIO_SET); @@ -36,19 +44,19 @@ hal_err_t _camera_load_reg(uint16_t addr, uint8_t val) { return hal_i2c_send(I2C_CAMERA, _CAM_I2C_ADDR, buf, 3); } -hal_err_t _camera_load_regs() { +hal_err_t _camera_load_regs(const struct camera_regval regs[]) { size_t i = 0; hal_err_t err = HAL_SUCCESS; while(1) { - switch(camera_regs[i].addr) { + switch(regs[i].addr) { case _CAM_REG_DELAY: - vTaskDelay(pdMS_TO_TICKS(camera_regs[i].val)); + vTaskDelay(pdMS_TO_TICKS(regs[i].val)); break; case _CAM_REG_NULL: goto finish; default: - err = _camera_load_reg(camera_regs[i].addr, camera_regs[i].val); + err = _camera_load_reg(regs[i].addr, regs[i].val); if (err != HAL_SUCCESS) { goto finish; } @@ -73,7 +81,7 @@ hal_err_t camera_start() { return err; } - if ((err = _camera_load_regs()) != HAL_SUCCESS) { + if ((err = _camera_load_regs(camera_regs)) != HAL_SUCCESS) { return err; } @@ -100,3 +108,21 @@ hal_err_t camera_next_frame(uint8_t** frame) { hal_err_t camera_submit(uint8_t* frame) { return hal_camera_submit(frame); } + +hal_err_t camera_set_exposure(camera_exposure_t exposure) { + struct camera_regval regs[3]; + _camera_exposure_regs(regs, exposure); + return _camera_load_regs(regs); +} + +hal_err_t camera_set_analog_gain(uint8_t gain) { + struct camera_regval regs[3]; + _camera_analog_gain_regs(regs, gain); + return _camera_load_regs(regs); +} + +hal_err_t camera_set_digital_gain(uint8_t gain) { + struct camera_regval regs[3]; + _camera_digital_gain_regs(regs, gain); + return _camera_load_regs(regs); +} diff --git a/app/camera/camera.h b/app/camera/camera.h index 110ccaf..4acf2b3 100644 --- a/app/camera/camera.h +++ b/app/camera/camera.h @@ -3,14 +3,17 @@ #include "hal.h" -#define _CAM_REG_NULL 0xFFFF -#define _CAM_REG_DELAY 0X0000 #define _CAM_MODEL SC031GS +#define CAMERA_MAX_ANALOG_GAIN 16 +#define CAMERA_MAX_DIGITAL_GAIN 8 -struct camera_regval { - uint16_t addr; - uint8_t val; -}; +typedef enum { + EXPOSURE_500, + EXPOSURE_400, + EXPOSURE_300, + EXPOSURE_250, + EXPOSURE_125, +} camera_exposure_t; hal_err_t camera_start(); hal_err_t camera_stop(); @@ -18,4 +21,8 @@ hal_err_t camera_stop(); hal_err_t camera_next_frame(uint8_t** frame); hal_err_t camera_submit(uint8_t* frame); +hal_err_t camera_set_exposure(camera_exposure_t exposure); +hal_err_t camera_set_analog_gain(uint8_t gain); +hal_err_t camera_set_digital_gain(uint8_t gain); + #endif /* __CAMERA_H__ */ diff --git a/app/camera/sc031gs.h b/app/camera/sc031gs.h index 580752f..4a5ef58 100644 --- a/app/camera/sc031gs.h +++ b/app/camera/sc031gs.h @@ -54,7 +54,7 @@ static const struct camera_regval camera_regs[] = { {0x0103, 0x01}, // soft reset. - {_CAM_REG_DELAY, 10}, // delay. + {_CAM_REG_DELAY, 10}, {0x0100,0x00}, {0x300f,0x0f}, {0x3018,0x1f}, @@ -125,12 +125,12 @@ static const struct camera_regval camera_regs[] = { {0x3908,0x91}, {0x3d08,0x01}, SC031GS_GAIN_CFG_TABLE, - {SC031GS_EXPOSURE_H_REG,0x0f}, - {SC031GS_EXPOSURE_L_REG,0xa0}, - {SC031GS_GAIN_ANALOG_H_REG,0x07}, - {SC031GS_GAIN_ANALOG_L_REG,0x1f}, - {SC031GS_GAIN_DIGITAL_H_REG,0x03}, - {SC031GS_GAIN_DIGITAL_L_REG,0x80}, + {SC031GS_EXPOSURE_H_REG,0x0e}, + {SC031GS_EXPOSURE_L_REG,0x13}, + {SC031GS_GAIN_ANALOG_H_REG,0x01}, + {SC031GS_GAIN_ANALOG_L_REG,0x10}, + {SC031GS_GAIN_DIGITAL_H_REG,0x01}, + {SC031GS_GAIN_DIGITAL_L_REG,0x10}, {0x4500,0x59}, {0x4501,0xc4}, {0x5011,0x00}, @@ -143,6 +143,47 @@ static const struct camera_regval camera_regs[] = { {0x3317,0x0f}, {_CAM_REG_NULL, 0x00}, }; + +const uint16_t _camera_exposure_table[] = { + 0x0e13, 0x1198, 0x1776, 0x1c27, 0x384e +}; + +const uint16_t _camera_analog_gain_table[] = { + 0x0010, 0x0110, 0x0118, 0x0310, 0x0314, 0x0318, 0x031c, 0x0710, + 0x0712, 0x0714, 0x0716, 0x0718, 0x071a, 0x071c, 0x071e, 0x071f +}; + +const uint16_t _camera_digital_gain_table[] = { + 0x0080, 0x0180, 0x01c0, 0x0380, 0x03a0, 0x03c0, 0x03e0, 0x03f8, +}; + +static inline void _camera_exposure_regs(struct camera_regval regs[3], camera_exposure_t exposure) { + uint16_t val = _camera_exposure_table[exposure]; + regs[0].addr = SC031GS_EXPOSURE_H_REG; + regs[0].val = val >> 8; + regs[1].addr = SC031GS_EXPOSURE_L_REG; + regs[1].val = val & 0xff; + regs[2].addr = _CAM_REG_NULL; +} + +static inline void _camera_analog_gain_regs(struct camera_regval regs[3], uint8_t gain) { + uint16_t val = _camera_analog_gain_table[gain - 1]; + regs[0].addr = SC031GS_GAIN_ANALOG_H_REG; + regs[0].val = val >> 8; + regs[1].addr = SC031GS_GAIN_ANALOG_L_REG; + regs[1].val = val & 0xff; + regs[2].addr = _CAM_REG_NULL; +} + +static inline void _camera_digital_gain_regs(struct camera_regval regs[3], uint8_t gain) { + uint16_t val = _camera_digital_gain_table[gain - 1]; + regs[0].addr = SC031GS_GAIN_DIGITAL_H_REG; + regs[0].val = val >> 8; + regs[1].addr = SC031GS_GAIN_DIGITAL_L_REG; + regs[1].val = val & 0xff; + regs[2].addr = _CAM_REG_NULL; +} + #else #error This file must be only imported once. #endif diff --git a/app/qrcode/qrcode.c b/app/qrcode/qrcode.c index 0628b74..bc05a7c 100644 --- a/app/qrcode/qrcode.c +++ b/app/qrcode/qrcode.c @@ -838,16 +838,7 @@ void quirc_threshold(struct quirc *q) quirc_pixel_t *row = q->pixels; int width = q->w; - /* - * Ensure a sane, non-zero value for threshold_s. - * - * threshold_s can be zero if the image width is small. We need to avoid - * SIGFPE as it will be used as divisor. - */ - if (threshold_s < THRESHOLD_S_MIN) - threshold_s = THRESHOLD_S_MIN; - - fracmul = (32768 * (threshold_s - 1)) / threshold_s; // to use multipy instead of divide (not too many bits or we'll overflow) + fracmul = (32768 * (threshold_s - 1)) / threshold_s; // to use multiply instead of divide (not too many bits or we'll overflow) // to get the effect used below (a fraction of threshold_s-1/threshold_s // The second constant is to reduce the averaged values to compare with the current pixel fracmul2 = (0x100000 * (100 - THRESHOLD_T)) / (200 * threshold_s); // use as many bits as possible without overflowing diff --git a/app/qrcode/qrscan.c b/app/qrcode/qrscan.c index d2de133..8ccdbac 100644 --- a/app/qrcode/qrscan.c +++ b/app/qrcode/qrscan.c @@ -83,6 +83,14 @@ app_err_t qrscan_scan() { uint16_t score = QR_SCORE_RED; uint16_t prev_color = 0; + camera_exposure_t exposure = EXPOSURE_500; + uint8_t again = 1; + uint8_t dgain = 1; + + camera_set_exposure(exposure); + camera_set_analog_gain(again); + camera_set_digital_gain(dgain); + while (1) { if (camera_next_frame(&fb) != HAL_SUCCESS) { continue; @@ -138,9 +146,46 @@ app_err_t qrscan_scan() { keypad_key_t k = ui_wait_keypress(0); - if ((k == KEYPAD_KEY_CANCEL) || (k == KEYPAD_KEY_BACK)) { - res = ERR_CANCEL; - goto end; + if (k != KEYPAD_KEY_INVALID) { + switch(k) { + case KEYPAD_KEY_1: + if (exposure < EXPOSURE_125) { + camera_set_exposure(++exposure); + } + break; + case KEYPAD_KEY_7: + if (exposure > EXPOSURE_500) { + camera_set_exposure(--exposure); + } + break; + case KEYPAD_KEY_2: + if (again < CAMERA_MAX_ANALOG_GAIN) { + camera_set_analog_gain(++again); + } + break; + case KEYPAD_KEY_8: + if (again > 1) { + camera_set_analog_gain(--again); + } + break; + case KEYPAD_KEY_3: + if (again < CAMERA_MAX_DIGITAL_GAIN) { + camera_set_digital_gain(++dgain); + } + break; + case KEYPAD_KEY_9: + if (dgain > 1) { + camera_set_digital_gain(--dgain); + } + break; + case KEYPAD_KEY_CANCEL: + case KEYPAD_KEY_BACK: + res = ERR_CANCEL; + goto end; + break; + default: + break; + } } }