diff --git a/src/camera.c b/src/camera.c index 0535a0d..da011ab 100644 --- a/src/camera.c +++ b/src/camera.c @@ -33,13 +33,18 @@ extern uint8_t g_camera_switch; void camera_type_detect(void) { camera_type = CAMERA_TYPE_UNKNOWN; - runcam_type_detect(); - if (camera_type == CAMERA_TYPE_RUNCAM_MICRO_V1 || - camera_type == CAMERA_TYPE_RUNCAM_MICRO_V2 || - camera_type == CAMERA_TYPE_RUNCAM_NANO_90 || - camera_type == CAMERA_TYPE_RUNCAM_MICRO_V3) { - camera_mfr = CAMERA_MFR_RUNCAM; - return; + if (g_camera_switch == SWITCH_TYPE_HDZCS && g_camera_id == 3) { + camera_type = CAMERA_TYPE_HDZCS_CVBS; + camera_mfr = CAMERA_MFR_HDZERO; + } else { + runcam_type_detect(); + if (camera_type == CAMERA_TYPE_RUNCAM_MICRO_V1 || + camera_type == CAMERA_TYPE_RUNCAM_MICRO_V2 || + camera_type == CAMERA_TYPE_RUNCAM_NANO_90 || + camera_type == CAMERA_TYPE_RUNCAM_MICRO_V3) { + camera_mfr = CAMERA_MFR_RUNCAM; + return; + } } } @@ -62,6 +67,9 @@ void camera_ratio_detect(void) { camRatio = 1; break; #endif + case CAMERA_TYPE_HDZCS_CVBS: + camRatio = 1; + break; default: camRatio = 0; break; @@ -169,8 +177,12 @@ void camera_mode_detect(uint8_t init) { // init tc3587 and detect fps WriteReg(0, 0x8F, 0x91); - - if (camera_type == CAMERA_TYPE_RUNCAM_NANO_90) { + if (camera_type == CAMERA_TYPE_HDZCS_CVBS) { + Init_TC3587(0); + Set_720P60(IS_RX); + video_format = VDO_FMT_720P60; + I2C_Write16(ADDR_TC3587, 0x0058, 0x00e0); + } else if (camera_type == CAMERA_TYPE_RUNCAM_NANO_90) { Init_TC3587(1); if (camera_setting_reg_set[11] == 0) { Set_540P90(0); @@ -305,7 +317,7 @@ void camera_setting_profile_check(uint8_t profile) { } void camera_profile_read(void) { if (g_camera_switch) { - camera_profile_eep = g_camera_id-1; + camera_profile_eep = g_camera_id - 1; } else { camera_profile_eep = camera_reg_read_eep(EEP_ADDR_CAM_PROFILE); } @@ -331,7 +343,8 @@ void camera_setting_read(void) { if (camera_type == CAMERA_TYPE_UNKNOWN || camera_type == CAMERA_TYPE_OUTDATED || - camera_type == CAMERA_TYPE_RESERVED) + camera_type == CAMERA_TYPE_RESERVED || + camera_type == CAMERA_TYPE_HDZCS_CVBS) return; camera_type_last = camera_reg_read_eep(EEP_ADDR_CAM_TYPE); @@ -365,7 +378,7 @@ void camera_setting_reg_menu_update(void) { void camera_setting_reg_eep_update(void) { uint8_t i; for (i = 0; i < CAMERA_SETTING_NUM; i++) { - if (g_camera_switch && i == (CAM_STATUS_VDO_FMT-1)) { + if (g_camera_switch && i == (CAM_STATUS_VDO_FMT - 1)) { // Sync all cameras on the camera switch to the same video setting if changed uint8_t value = camera_setting_reg_menu[i]; camera_setting_reg_eep[0][i] = value; @@ -416,6 +429,13 @@ void camera_init(void) { camera_button_init(); } +void camera_reinit(void) { + camera_type_detect(); + camera_setting_read(); + camera_setting_reg_menu_update(); + camera_mode_detect(1); +} + void camera_button_op(uint8_t op) { switch (op) { case BTN_UP: diff --git a/src/camera.h b/src/camera.h index b1a5d85..a6a4d88 100644 --- a/src/camera.h +++ b/src/camera.h @@ -28,6 +28,7 @@ typedef enum { CAMERA_MFR_UNKNOW, CAMERA_MFR_FOXEER, CAMERA_MFR_RUNCAM, + CAMERA_MFR_HDZERO, } camera_manufacture_e; typedef enum { @@ -38,6 +39,8 @@ typedef enum { CAMERA_TYPE_RUNCAM_MICRO_V2, // include hzd nano v2 / hdz nano lite CAMERA_TYPE_RUNCAM_NANO_90, CAMERA_TYPE_RUNCAM_MICRO_V3, + CAMERA_TYPE_HDZCS_CVBS, + CAMERA_TYPE_NUM, } camera_type_e; typedef enum { @@ -92,6 +95,7 @@ typedef enum { } camera_select_e; void camera_init(void); +void camera_reinit(void); void camera_switch_profile(void); uint8_t camera_status_update(uint8_t op); void camera_menu_init(void); diff --git a/src/hardware.c b/src/hardware.c index a648a81..b925a13 100644 --- a/src/hardware.c +++ b/src/hardware.c @@ -1029,10 +1029,14 @@ void video_detect(void) { return; } #endif + if (camera_type == CAMERA_TYPE_HDZCS_CVBS) { + return; + } - if (sec == 3) { - sec = 0; - if (cameraLost) { // video loss + if (cameraLost) { + sec++; + if (sec == 3) { // video loss + sec = 0; if (video_format == VDO_FMT_720P50) { Set_720P60(IS_RX); video_format = VDO_FMT_720P60; @@ -1041,6 +1045,8 @@ void video_detect(void) { video_format = VDO_FMT_720P50; } } + } else { + sec = 0; } } } diff --git a/src/i2c_device.c b/src/i2c_device.c index 6a6a46b..fda4b43 100644 --- a/src/i2c_device.c +++ b/src/i2c_device.c @@ -5,12 +5,14 @@ #include "global.h" #include "hardware.h" #include "i2c.h" +#include "msp_displayport.h" #include "print.h" uint8_t g_camera_switch = SWITCH_TYPE_NONE; uint8_t g_camera_id = 0; uint8_t g_max_camera = 0; uint8_t g_manual_camera_sel = 0; +static uint8_t camera_list[3] = {255, 254, 253}; ///////////////////////////////////////////////////////////////// // MAX7315 @@ -140,6 +142,16 @@ void pca9557_set(uint8_t reg, uint8_t val) { I2C_Write8(ADDR_PCA9557, reg, val); } +// Read from 3 camera switch +uint8_t hdzcs_get(uint8_t reg) { + return I2C_Read8(ADDR_HDZCS, reg); +} + +// Write to 3 camera switch +void hdzcs_set(uint8_t reg, uint8_t val) { + I2C_Write8_Wait(10, ADDR_HDZCS, reg, val); +} + uint8_t get_camera_switch_type(void) { uint8_t camera_switch = SWITCH_TYPE_NONE; @@ -147,14 +159,16 @@ uint8_t get_camera_switch_type(void) { camera_switch = SWITCH_TYPE_PI4IO; } else if (pca9557_get(0x02) == 0xF0) { // polarity inversion register defaults to 0xF0 camera_switch = SWITCH_TYPE_PCA9557; + } else if (hdzcs_get(0xff) == 0x01) { + camera_switch = SWITCH_TYPE_HDZCS; } return camera_switch; } void select_camera(uint8_t camera_id) { - if (g_camera_switch) - { + static uint8_t camera_last = 0x00; + if (g_camera_switch) { // Check camera id is within range, else default to 1 uint8_t camera = (camera_id == 0 || camera_id > g_max_camera) ? 1 : camera_id; if (g_camera_id != camera) { @@ -162,26 +176,38 @@ void select_camera(uint8_t camera_id) { uint8_t command; switch (g_camera_id) { - case 1: - default: - command = (g_camera_switch == SWITCH_TYPE_PI4IO) ? 0x11 : 0x1B; - break; - case 2: - command = (g_camera_switch == SWITCH_TYPE_PI4IO) ? 0x64 : 0x16; - break; - case 3: - command = (g_camera_switch == SWITCH_TYPE_PI4IO) ? 0x11 : 0x0D; - break; + case 1: + default: + command = (g_camera_switch == SWITCH_TYPE_PI4IO) ? 0x11 : 0x1B; + break; + case 2: + command = (g_camera_switch == SWITCH_TYPE_PI4IO) ? 0x64 : 0x16; + break; + case 3: + command = (g_camera_switch == SWITCH_TYPE_PI4IO) ? 0x11 : 0x0D; + break; } if (g_camera_switch == SWITCH_TYPE_PI4IO) { pi4io_set(0x05, command); - } - else { // SWITCH_TYPE_PCA9557 + } else if (g_camera_switch == SWITCH_TYPE_PCA9557) { // SWITCH_TYPE_PCA9557 pca9557_set(0x01, command); - WAIT(200); // wait for camera power up + WAIT(200); // wait for camera power up + } else if (g_camera_switch == SWITCH_TYPE_HDZCS) { + hdzcs_set(0x00, g_camera_id); } - camera_switch_profile(); + + if (camera_last != camera_list[g_camera_id - 1]) { + if (camera_list[g_camera_id - 1] < CAMERA_TYPE_NUM) { // camera has inited + camera_reinit(); + } else { + camera_init(); + camera_list[g_camera_id - 1] = camera_type; + } + camera_last = camera_type; + } + + resync_vrx_vtmg(); } } } @@ -189,21 +215,22 @@ void select_camera(uint8_t camera_id) { void camera_switch_init() { g_camera_switch = get_camera_switch_type(); if (g_camera_switch == SWITCH_TYPE_PI4IO) { - //pi4io_set(0x01, 0xFF); // reset - pi4io_set(0x0B, 0xFF); // Disable pullup/pulldown resistors - pi4io_set(0x11, 0xFF); // Disable interrupts on inputs - pi4io_get(0x13); // De-assert the interrrupt - pi4io_set(0x03, 0x77); // Set P3 and P7 as inputs - pi4io_set(0x07, 0x00); // Set outputs to follow the output port register - pi4io_set(0x05, 0x11); // camera 1 default + // pi4io_set(0x01, 0xFF); // reset + pi4io_set(0x0B, 0xFF); // Disable pullup/pulldown resistors + pi4io_set(0x11, 0xFF); // Disable interrupts on inputs + pi4io_get(0x13); // De-assert the interrrupt + pi4io_set(0x03, 0x77); // Set P3 and P7 as inputs + pi4io_set(0x07, 0x00); // Set outputs to follow the output port register + pi4io_set(0x05, 0x11); // camera 1 default g_max_camera = PI4IO_CAMS; } else if (g_camera_switch == SWITCH_TYPE_PCA9557) { g_max_camera = PCA9557_CAMS; - pca9557_set(0x03, 0x00); // all outputs - pca9557_set(0x01, 0x1B); // camera 1 default - WAIT(200); // wait for camera power up - } else { - g_camera_id = 1; + pca9557_set(0x03, 0x00); // all outputs + pca9557_set(0x01, 0x1B); // camera 1 default + WAIT(200); // wait for camera power up + } else if (g_camera_switch == SWITCH_TYPE_HDZCS) { + g_max_camera = HDZCS_CAMS; + hdzcs_set(0x00, 0x01); // camera 1 default } } @@ -217,5 +244,28 @@ void manual_select_camera(void) { uint8_t camera_id = ((command & 0x80) >> 7) + 1; select_camera(camera_id); } + } else if (g_camera_switch == SWITCH_TYPE_HDZCS) { + uint8_t command = hdzcs_get(0x01); + switch (command) { + case 0: + g_manual_camera_sel = 3; // manual analog camera + break; + case 1: + g_manual_camera_sel = 2; // manual mipi camera 2 + break; + case 2: + g_manual_camera_sel = 1; // manual mipi camera 1 + break; + case 3: + g_manual_camera_sel = 0; + break; // assign by FC + default: + g_manual_camera_sel = 0; + break; + } + + if (g_manual_camera_sel) { + select_camera(g_manual_camera_sel); + } } } diff --git a/src/i2c_device.h b/src/i2c_device.h index 87a273d..f631d3c 100644 --- a/src/i2c_device.h +++ b/src/i2c_device.h @@ -13,16 +13,19 @@ #define ADDR_RUNCAM 0x21 #define ADDR_PI4IO 0x43 // 2 camera switch #define ADDR_PCA9557 0x18 // 3 camera switch +#define ADDR_HDZCS 0x60 typedef enum { SWITCH_TYPE_NONE, SWITCH_TYPE_PI4IO, - SWITCH_TYPE_PCA9557 + SWITCH_TYPE_PCA9557, + SWITCH_TYPE_HDZCS, } switch_type_e; typedef enum { PI4IO_CAMS = 2, - PCA9557_CAMS = 3 + PCA9557_CAMS = 3, + HDZCS_CAMS = 3, } switch_cams_e; void set_segment(uint32_t val); @@ -33,6 +36,7 @@ void Init_TC3587(uint8_t fmt); uint8_t pi4io_get(uint8_t reg); void pi4io_set(uint8_t reg, uint8_t val); +uint8_t hdzcs_get(uint8_t reg); void camera_switch_init(void); void select_camera(uint8_t camera_id); void manual_select_camera(void); diff --git a/src/msp_displayport.c b/src/msp_displayport.c index 9cf4afe..4cde4d9 100644 --- a/src/msp_displayport.c +++ b/src/msp_displayport.c @@ -568,13 +568,13 @@ uint8_t get_tx_data_5680() // prepare data to VRX tx_buf[12] = 0x00; // deprecated - tx_buf[13] = VTX_ID; + tx_buf[13] = g_camera_id; // Send g_camera_id in the future to allow the VRX to resync on a camera change tx_buf[14] = fc_lock & 0x03; tx_buf[15] = (camRatio == 0) ? 0x55 : 0xaa; - tx_buf[16] = VTX_VERSION_MAJOR; // Send g_camera_id in the future to allow the VRX to resync on a camera change + tx_buf[16] = VTX_VERSION_MAJOR; tx_buf[17] = VTX_VERSION_MINOR; tx_buf[18] = VTX_VERSION_PATCH_LEVEL; @@ -1047,7 +1047,7 @@ void parse_status() { if (!camSelected && g_boxCamera2_mask) { offset = (isBTFL && g_boxCamera2_page > 3) ? 12 : 6; if (msp_rx_buf[offset + g_boxCamera2_page] & g_boxCamera2_mask) { - if (g_camera_switch == SWITCH_TYPE_PCA9557) { + if (g_camera_switch == SWITCH_TYPE_PCA9557 || g_camera_switch == SWITCH_TYPE_HDZCS) { camSelected = camera_switch(3); } } @@ -1991,8 +1991,8 @@ void update_vtx_menu_param(uint8_t state) { const char *pitString[] = {" OFF", " P1MW", " 0MW"}; const char *treamRaceString[] = {" OFF", "MODE1", "MODE2"}; const char *shortcutString[] = {"OPT_A", "OPT_B"}; - const char *cameraTypeString[] = {"UNKNOWN", "RESERVED", "OUTDATED", "MICRO_V1", "MICRO_V2", "NANO_90", "MICRO_V3"}; - const char *cameraSwitchString[] = {"NONE", "DUAL", "TREBLE"}; + const char *cameraTypeString[] = {"UNKNOWN ", "RESERVED", "OUTDATED", "MICRO_V1", "MICRO_V2", "NANO_90 ", "MICRO_V3", "CVBS "}; + const char *cameraSwitchString[] = {"NONE", "DUAL", "TRIPLE"}; // cursor state += 2; @@ -2043,7 +2043,12 @@ void update_vtx_menu_param(uint8_t state) { strcpy(osd_buf[8] + osd_menu_offset + 20, shortcutString[vtx_shortcut]); // camera switch info - strcpy(osd_buf[12] + osd_menu_offset + 13, cameraSwitchString[g_camera_switch]); + if (g_camera_switch == SWITCH_TYPE_NONE) + strcpy(osd_buf[12] + osd_menu_offset + 13, cameraSwitchString[0]); + else if (g_camera_switch == SWITCH_TYPE_PI4IO) + strcpy(osd_buf[12] + osd_menu_offset + 13, cameraSwitchString[1]); + else if (g_camera_switch == SWITCH_TYPE_PCA9557 || g_camera_switch == SWITCH_TYPE_HDZCS) + strcpy(osd_buf[12] + osd_menu_offset + 13, cameraSwitchString[2]); // camera selection osd_buf[13][osd_menu_offset + 10] = '0' + g_camera_id; @@ -2224,6 +2229,15 @@ uint8_t bfChannel_to_channel(uint8_t const channel) { return INVALID_CHANNEL; } +void resync_vrx_vtmg() { + uint8_t i, len; + len = get_tx_data_5680(); + for (i = 0; i < 8; i++) { + insert_tx_buf(len); + WAIT(50); + } +} + #ifdef INIT_VTX_TABLE #define FACTORY_BAND 0 // BF requires band to be CUSTOM with VTX_MSP @@ -2365,4 +2379,5 @@ uint8_t bfChannel_to_channel(uint8_t const channel) { return INVALID_CHANNEL; } +void resync_vrx_vtmg() {} #endif diff --git a/src/msp_displayport.h b/src/msp_displayport.h index 1e2eeb2..7d2660b 100644 --- a/src/msp_displayport.h +++ b/src/msp_displayport.h @@ -34,7 +34,7 @@ typedef enum { } vtxPtiType_e; typedef enum { - BOXARM_BTFL = 0, // for completeness + BOXARM_BTFL = 0, // for completeness BOXCAMERA1_BTFL = 32, // 0x20 BOXCAMERA2_BTFL = 33, // 0x21 @@ -126,12 +126,12 @@ typedef enum { typedef enum { VTXDEV_UNSUPPORTED = 0, // reserved for MSP - VTXDEV_RTC6705 = 1, + VTXDEV_RTC6705 = 1, // 2 reserved - VTXDEV_SMARTAUDIO = 3, - VTXDEV_TRAMP = 4, - VTXDEV_MSP = 5, - VTXDEV_UNKNOWN = 0xFF, + VTXDEV_SMARTAUDIO = 3, + VTXDEV_TRAMP = 4, + VTXDEV_MSP = 5, + VTXDEV_UNKNOWN = 0xFF, } vtxDevType_e; typedef enum { @@ -174,6 +174,8 @@ void msp_set_vtx_config(uint8_t power, uint8_t save); void set_vtx_param(); uint8_t channel_to_bfChannel(uint8_t const channel); uint8_t bfChannel_to_channel(uint8_t const channel); +void resync_vrx_vtmg(); + #ifdef INIT_VTX_TABLE void InitVtxTable(); #endif