diff --git a/prj/TCPClient/Debug/mini212g2.c b/prj/TCPClient/Debug/mini212g2.c index b0432bb..903494e 100644 --- a/prj/TCPClient/Debug/mini212g2.c +++ b/prj/TCPClient/Debug/mini212g2.c @@ -48,6 +48,10 @@ static const uint8_t CMD_SHUTTER[] = static const uint8_t CMD_QUERY_DIGITAL[] = {0x55, 0xAA, 0x07, 0x02, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x84, 0xF0}; +/* Query: status page (simplest query, always works) */ +static const uint8_t CMD_QUERY_STATUS[] = + {0x55, 0xAA, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x87, 0xF0}; + /* ============================================================ * Low-level UART helpers * ============================================================ */ @@ -142,8 +146,9 @@ static void Sensor_FlushRx(void) * ============================================================ */ volatile uint8_t sensor_init_ok = 0; volatile uint8_t sensor_init_fail = 0; -volatile uint8_t sensor_last_resp[8] = {0}; +volatile uint8_t sensor_last_resp[32] = {0}; volatile uint8_t sensor_last_resp_len = 0; +volatile uint8_t sensor_comm_test = 0; int Mini212G2_SendCmd(const uint8_t *cmd, uint8_t len) { @@ -154,7 +159,7 @@ int Mini212G2_SendCmd(const uint8_t *cmd, uint8_t len) int n = Sensor_ReadResp(resp, sizeof(resp), 200); /* Save last response for debugger inspection */ sensor_last_resp_len = (uint8_t)n; - for (int j = 0; j < n && j < 8; j++) + for (int j = 0; j < n && j < 32; j++) sensor_last_resp[j] = resp[j]; if (n == ACK_LEN && memcmp(resp, ACK_PATTERN, ACK_LEN) == 0) @@ -185,6 +190,20 @@ int Mini212G2_Init(void) printf("[Sensor] Waiting 3s for sensor boot...\r\n"); Delay_Ms(3000); + /* === Communication test: send status query === */ + { + uint8_t test_resp[32]; + Sensor_FlushRx(); + Sensor_SendBytes(CMD_QUERY_STATUS, sizeof(CMD_QUERY_STATUS)); + int tn = Sensor_ReadResp(test_resp, sizeof(test_resp), 500); + sensor_last_resp_len = (uint8_t)tn; + for (int j = 0; j < tn && j < 32; j++) + sensor_last_resp[j] = test_resp[j]; + sensor_comm_test = (tn > 0) ? 1 : 0xFF; + /* Breakpoint here to check sensor_comm_test and sensor_last_resp */ + } + Delay_Ms(200); + printf("[Sensor] Configuring CMOS/DVP output...\r\n"); /* 1. Shutter compensation */ diff --git a/prj/TCPClient/Debug/mini212g2.h b/prj/TCPClient/Debug/mini212g2.h index 3f3e01f..0588c4f 100644 --- a/prj/TCPClient/Debug/mini212g2.h +++ b/prj/TCPClient/Debug/mini212g2.h @@ -35,8 +35,10 @@ int Mini212G2_Init(void); * sensor_last_resp_len: length of last response */ extern volatile uint8_t sensor_init_ok; extern volatile uint8_t sensor_init_fail; -extern volatile uint8_t sensor_last_resp[8]; +extern volatile uint8_t sensor_last_resp[32]; extern volatile uint8_t sensor_last_resp_len; +/* sensor_comm_test: 0=not run, 1=got response, 0xFF=no response (timeout) */ +extern volatile uint8_t sensor_comm_test; #if SENSOR_UART_ENABLE /** diff --git a/prj/TCPClient/User/main.c b/prj/TCPClient/User/main.c index dea78c0..4f5673c 100644 --- a/prj/TCPClient/User/main.c +++ b/prj/TCPClient/User/main.c @@ -10,6 +10,13 @@ #include "FreeRTOS.h" #include "task.h" +/* ============================================================ + * TEST MODE: Generate simulated sensor data without real hardware. + * Set to 1 to enable test pattern generation (no sensor/DVP needed). + * Set to 0 for normal operation with real Mini212G2 sensor. + * ============================================================ */ +#define TEST_PATTERN_MODE 1 + #define MAX_TCP_PAYLOAD_SIZE 10240 uint8_t g_TxNetBuffer_A_Mem[MAX_TCP_PAYLOAD_SIZE]; uint8_t g_TxNetBuffer_B_Mem[MAX_TCP_PAYLOAD_SIZE]; @@ -208,9 +215,15 @@ static void task_heartbeat_entry(void *pvParameters) uint32_t cnt = 0; while (1) { +#if TEST_PATTERN_MODE + printf("[HB] %d tick=%d TEST_MODE frm=%d\r\n", + (int)cnt++, (int)xTaskGetTickCount(), + (int)dvp_frame_count); +#else printf("[HB] %d tick=%d dvp_frm=%d row_irq=%d\r\n", (int)cnt++, (int)xTaskGetTickCount(), (int)dvp_frame_count, (int)dvp_row_irq_cnt); +#endif vTaskDelay(pdMS_TO_TICKS(2000)); } } @@ -240,6 +253,94 @@ static uint8_t burst_active = 0; /* 1 = currently in burst */ static uint8_t burst_remaining = 0; /* frames left to capture */ static uint32_t burst_next_time_ms = 0; /* next burst frame time */ +#if TEST_PATTERN_MODE +/* ============================================================ + * Test Pattern Generator + * Generates simulated 256x192 Y16 thermal images at ~10 FPS. + * Pattern cycles through several types so all pipeline paths + * can be exercised. + * + * Pattern 0: Gradient (25.00~45.00°C) — baseline, no trigger + * Pattern 1: Hot center spot (90.00°C) — should trigger alarm + * Pattern 2: Uniform warm (35.00°C) — no trigger + * Pattern 3: Checkerboard with hot cells — tests ROI search + * ============================================================ */ +#define TEST_FPS_DELAY_MS 100 /* ~10 FPS */ +#define TEMP_RAW(deg_c) ((uint16_t)((deg_c) * 100)) /* e.g. 35.00°C → 3500 */ + +static void test_fill_gradient(uint16_t *buf, uint16_t w, uint16_t h) +{ + /* Top-to-bottom gradient: 25°C at top → 45°C at bottom */ + for (uint16_t y = 0; y < h; y++) { + uint16_t temp = TEMP_RAW(25.0) + (uint16_t)((uint32_t)y * TEMP_RAW(20.0) / h); + for (uint16_t x = 0; x < w; x++) + buf[y * w + x] = temp; + } +} + +static void test_fill_hotspot(uint16_t *buf, uint16_t w, uint16_t h) +{ + /* Background 30°C, center 32x32 block at 90°C */ + for (uint16_t y = 0; y < h; y++) + for (uint16_t x = 0; x < w; x++) + buf[y * w + x] = TEMP_RAW(30.0); + uint16_t cx = w / 2, cy = h / 2; + for (uint16_t y = cy - 16; y < cy + 16; y++) + for (uint16_t x = cx - 16; x < cx + 16; x++) + buf[y * w + x] = TEMP_RAW(90.0); +} + +static void test_fill_uniform(uint16_t *buf, uint16_t w, uint16_t h) +{ + for (uint16_t y = 0; y < h; y++) + for (uint16_t x = 0; x < w; x++) + buf[y * w + x] = TEMP_RAW(35.0); +} + +static void test_fill_checker(uint16_t *buf, uint16_t w, uint16_t h) +{ + /* 32x32 checkerboard: alternating 30°C and 85°C blocks */ + for (uint16_t y = 0; y < h; y++) + for (uint16_t x = 0; x < w; x++) { + uint8_t cell = ((y / 32) + (x / 32)) & 1; + buf[y * w + x] = cell ? TEMP_RAW(85.0) : TEMP_RAW(30.0); + } +} + +static void task_test_pattern_entry(void *pvParameters) +{ + (void)pvParameters; + uint32_t frame_num = 0; + uint8_t pattern_idx = 0; + /* Cycle: gradient x20, hotspot x5, uniform x10, checker x5 */ + const uint8_t pattern_seq[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3}; + const uint8_t seq_len = sizeof(pattern_seq); + + while (1) + { + uint16_t *buf = (uint16_t *)FrameBuffer; + switch (pattern_seq[pattern_idx % seq_len]) { + case 0: test_fill_gradient(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break; + case 1: test_fill_hotspot(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break; + case 2: test_fill_uniform(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break; + case 3: test_fill_checker(buf, SENSOR_WIDTH, SENSOR_HEIGHT); break; + } + pattern_idx++; + if (pattern_idx >= seq_len) pattern_idx = 0; + + frame_num++; + dvp_frame_count = frame_num; + Ready_Frame_Count = frame_num; + Frame_Ready_Flag = 1; + + vTaskDelay(pdMS_TO_TICKS(TEST_FPS_DELAY_MS)); + } +} +#endif /* TEST_PATTERN_MODE */ + static void task_business_entry(void *pvParameters) { (void)pvParameters; @@ -253,7 +354,9 @@ static void task_business_entry(void *pvParameters) g_ng_off_time = 0; } +#if !TEST_PATTERN_MODE DVP_Task(); +#endif if (Frame_Ready_Flag) { @@ -348,8 +451,13 @@ int main(void) for (i = 0; i < 6; i++) printf("%x ", MACAddr[i]); printf("\n"); +#if TEST_PATTERN_MODE + printf("=== TEST PATTERN MODE === No sensor/DVP hardware needed\r\n"); + /* Skip Mini212G2_Init() and DVP_Init() */ +#else Mini212G2_Init(); /* Configure sensor for CMOS/DVP Y16 output */ DVP_Init(); +#endif TIM2_Init(); NG_GPIO_Init(); @@ -377,6 +485,9 @@ int main(void) xTaskCreate(task_wchnet_entry, "wchnet", 512, NULL, 6, NULL); xTaskCreate(task_business_entry, "business", 512, NULL, 5, NULL); xTaskCreate(task_heartbeat_entry, "hb", 256, NULL, 3, NULL); +#if TEST_PATTERN_MODE + xTaskCreate(task_test_pattern_entry, "testpat", 256, NULL, 4, NULL); +#endif DBG_APP("Starting scheduler\r\n"); vTaskStartScheduler();