|
|
|
@ -58,8 +58,8 @@ Includes |
|
|
|
#define UART_RX_BUF_SIZE 1024 |
|
|
|
#define RS485_BRIDGE_FIFO_SZ 2048 |
|
|
|
|
|
|
|
#define BRIDGE_IDLE_DONE_US 5000U // ? 3ms ? ?
|
|
|
|
#define BRIDGE_TOTAL_WAIT_US 1290000U |
|
|
|
#define BRIDGE_IDLE_DONE_US 20000U // ? 3ms ? ?
|
|
|
|
#define BRIDGE_TOTAL_WAIT_US 3000000U |
|
|
|
|
|
|
|
/* =========================
|
|
|
|
* UART RX Buffers |
|
|
|
@ -445,7 +445,7 @@ static void RS485_FlushJunk(uint16_t loops, uint16_t step_us) |
|
|
|
|
|
|
|
static void PC_PrintLine_CRLF(const char *line) |
|
|
|
{ |
|
|
|
char tmp[40]; |
|
|
|
char tmp[320]; |
|
|
|
size_t n = strlen(line); |
|
|
|
size_t i; |
|
|
|
|
|
|
|
@ -487,7 +487,7 @@ static void scan_one_addr_rs485(uint8_t addr) |
|
|
|
|
|
|
|
for (try = 0; try < 1; try++) { /* 재시도도 우선 1회로 줄이기 */ |
|
|
|
uint32_t total_wait_us; |
|
|
|
char linebuf[32]; |
|
|
|
char linebuf[320]; |
|
|
|
|
|
|
|
if (g_rs485_need_recover) { |
|
|
|
rs485_recover(); |
|
|
|
@ -617,7 +617,7 @@ static void print_owi_write_result(CmdSource src, const app_owi_result_t *r) |
|
|
|
|
|
|
|
static void print_owi_read_result(CmdSource src, const app_owi_result_t *r) |
|
|
|
{ |
|
|
|
char out[(2 * OWI_IO_MAX_BYTES) + 40]; |
|
|
|
char out[(2 * OWI_IO_MAX_BYTES) + 64]; |
|
|
|
uint16_t p = 0; |
|
|
|
uint16_t i; |
|
|
|
|
|
|
|
@ -650,11 +650,148 @@ static void print_owi_read_result(CmdSource src, const app_owi_result_t *r) |
|
|
|
OUT_PRINT(src, out); |
|
|
|
} |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
uint8_t active; |
|
|
|
uint8_t addr; |
|
|
|
uint8_t channel; |
|
|
|
uint8_t mode; |
|
|
|
uint8_t hash_on; |
|
|
|
uint8_t anaout_on; |
|
|
|
uint8_t check_on; |
|
|
|
uint8_t id; |
|
|
|
|
|
|
|
uint8_t first_tx[3]; |
|
|
|
uint8_t expected_tail[3]; |
|
|
|
} connect_verify_ctx_t; |
|
|
|
|
|
|
|
static connect_verify_ctx_t g_connect_verify; |
|
|
|
|
|
|
|
static void connect_verify_reset(void) |
|
|
|
{ |
|
|
|
memset(&g_connect_verify, 0, sizeof(g_connect_verify)); |
|
|
|
} |
|
|
|
|
|
|
|
static void print_hex_line(CmdSource src, const uint8_t *data, uint16_t len) |
|
|
|
{ |
|
|
|
char out[(2 * OWI_IO_MAX_BYTES) + 64]; |
|
|
|
uint16_t p = 0; |
|
|
|
uint16_t i; |
|
|
|
|
|
|
|
if (!data || len == 0) { |
|
|
|
OUT_PRINT(src, "\r\n"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < len && i < OWI_IO_MAX_BYTES; i++) { |
|
|
|
uint8_t b = data[i]; |
|
|
|
out[p++] = "0123456789ABCDEF"[b >> 4]; |
|
|
|
out[p++] = "0123456789ABCDEF"[b & 0x0F]; |
|
|
|
} |
|
|
|
|
|
|
|
out[p++] = '\r'; |
|
|
|
out[p++] = '\n'; |
|
|
|
out[p] = '\0'; |
|
|
|
|
|
|
|
OUT_PRINT(src, out); |
|
|
|
} |
|
|
|
|
|
|
|
static int execute_connect_verify_sequence(CmdSource src, const app_job_t *job) |
|
|
|
{ |
|
|
|
app_owi_result_t r_write1; |
|
|
|
app_owi_result_t r_read2; |
|
|
|
app_owi_result_t r_write3; |
|
|
|
app_owi_result_t r_read3; |
|
|
|
|
|
|
|
uint8_t write1_data[3]; |
|
|
|
uint8_t expected_tail[3]; |
|
|
|
uint8_t cmd_7c = 0x7C; |
|
|
|
|
|
|
|
if (!job) return 0; |
|
|
|
|
|
|
|
/* connect 전용 패턴
|
|
|
|
xNNc_XXX...:owt28006 AABBCC DDEEFF |
|
|
|
- id = 0x28 |
|
|
|
- len = 6 |
|
|
|
- payload[0..2] = 첫 write 3바이트 |
|
|
|
- payload[3..5] = 최종 비교 기대값 3바이트 |
|
|
|
*/ |
|
|
|
if (job->type != APP_JOB_PROTO_OW) return 0; |
|
|
|
if (job->proto != APP_PROTO_OWIT) return 0; |
|
|
|
if (job->id != 0x28u) return 0; |
|
|
|
if (job->len != 6u) return 0; |
|
|
|
|
|
|
|
if (job->addr != g_fixed_addr) return 0; |
|
|
|
|
|
|
|
if (job->channel < 1 || job->channel > 20) { |
|
|
|
OUT_PRINT(src, "Err:ch_range\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* prefix / gate */ |
|
|
|
if (job->mode == 'C') { |
|
|
|
s_prefix_mode = PREFIX_CAL; |
|
|
|
Cal_Init(); |
|
|
|
} else { |
|
|
|
s_prefix_mode = PREFIX_EOL; |
|
|
|
Eol_Init(); |
|
|
|
} |
|
|
|
|
|
|
|
Gate_SetByNum(job->channel, job->hash_on, job->anaout_on, job->check_on); |
|
|
|
GateCtrl_SelectChannel(job->channel); |
|
|
|
|
|
|
|
memcpy(write1_data, &job->payload[0], 3); |
|
|
|
memcpy(expected_tail, &job->payload[3], 3); |
|
|
|
|
|
|
|
/* 1) OWT 28 003 + first3 */ |
|
|
|
r_write1 = app_owi_write_t_basic(0x28u, write1_data, 3); |
|
|
|
print_owi_write_result(src, &r_write1); |
|
|
|
if (!r_write1.ok || r_write1.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 2) OR 28 002 -> 예: 7272 */ |
|
|
|
r_read2 = app_owi_read_basic(0x28u, 2); |
|
|
|
print_owi_read_result(src, &r_read2); |
|
|
|
if (!r_read2.ok || r_read2.timeout || r_read2.read_len < 2) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 3) OWT 28 001 + 7C */ |
|
|
|
r_write3 = app_owi_write_t_basic(0x28u, &cmd_7c, 1); |
|
|
|
print_owi_write_result(src, &r_write3); |
|
|
|
if (!r_write3.ok || r_write3.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 4) OR 28 003 -> 실제 칩 결과 읽기 */ |
|
|
|
r_read3 = app_owi_read_basic(0x28u, 3); |
|
|
|
print_owi_read_result(src, &r_read3); |
|
|
|
if (!r_read3.ok || r_read3.timeout || r_read3.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 실제 읽은 3바이트와 기대값 비교 */ |
|
|
|
if (memcmp(r_read3.data, expected_tail, 3) == 0) { |
|
|
|
OUT_PRINT(src, "Success\r\n"); |
|
|
|
} else { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
} |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int execute_owi_service_from_job(CmdSource src, const app_job_t *job) |
|
|
|
{ |
|
|
|
app_owi_result_t r; |
|
|
|
|
|
|
|
if (!job) return 0; |
|
|
|
if (execute_connect_verify_sequence(src, job)) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (job->addr != g_fixed_addr) return 0; |
|
|
|
if (job->channel < 1 || job->channel > 20) { |
|
|
|
OUT_PRINT(src, "Err:ch_range\r\n"); |
|
|
|
@ -695,7 +832,9 @@ static void forward_line_rs485_and_bridge(const char *line) |
|
|
|
{ |
|
|
|
static char txbuf[UART_RX_BUF_SIZE + 4]; |
|
|
|
uint32_t total_us; |
|
|
|
char linebuf[128]; |
|
|
|
uint32_t idle_us = 0; |
|
|
|
char linebuf[320]; |
|
|
|
int line_len = 0; |
|
|
|
int n; |
|
|
|
uint8_t got_any_line = 0; |
|
|
|
|
|
|
|
@ -721,29 +860,81 @@ static void forward_line_rs485_and_bridge(const char *line) |
|
|
|
g_uart0_tx_done = 0; |
|
|
|
RS485_PRINT(txbuf); |
|
|
|
|
|
|
|
/* scan_one_addr_rs485()와 동일하게 TX -> RX 전환 */ |
|
|
|
UART0_WaitTxDone_Flag(10000); |
|
|
|
rs485_set_tx(0); |
|
|
|
delay_us(500); |
|
|
|
|
|
|
|
total_us = 100000U; /* 100 ms */ |
|
|
|
total_us = BRIDGE_TOTAL_WAIT_US; |
|
|
|
line_len = 0; |
|
|
|
linebuf[0] = '\0'; |
|
|
|
|
|
|
|
while (total_us >= 50U) { |
|
|
|
uint8_t had_byte = 0; |
|
|
|
|
|
|
|
while (total_us >= 1000U) { |
|
|
|
int got = RS485_Bridge_ReadLine(linebuf, sizeof(linebuf), 1000); |
|
|
|
/* FIFO에서 바이트를 하나씩 꺼내 누적 */ |
|
|
|
while (s_rb_tail != s_rb_head) { |
|
|
|
char c = (char)s_rb_fifo[s_rb_tail]; |
|
|
|
s_rb_tail++; |
|
|
|
if (s_rb_tail >= RS485_BRIDGE_FIFO_SZ) s_rb_tail = 0; |
|
|
|
|
|
|
|
if (got) { |
|
|
|
/* 자기 echo 무시 */ |
|
|
|
if (linebuf[0] == 'x' || linebuf[0] == 'X') { |
|
|
|
total_us -= 1000U; |
|
|
|
continue; |
|
|
|
had_byte = 1; |
|
|
|
|
|
|
|
/* CR 무시 */ |
|
|
|
if (c == '\r') continue; |
|
|
|
|
|
|
|
/* 버퍼에 누적 */ |
|
|
|
if (line_len < (int)sizeof(linebuf) - 1) { |
|
|
|
linebuf[line_len++] = c; |
|
|
|
linebuf[line_len] = '\0'; |
|
|
|
} else { |
|
|
|
/* overflow 보호: 강제로 한 줄 종료 처리 */ |
|
|
|
linebuf[line_len] = '\0'; |
|
|
|
if (!(linebuf[0] == 'x' || linebuf[0] == 'X')) { |
|
|
|
PC_PrintLine_CRLF(linebuf); |
|
|
|
got_any_line = 1; |
|
|
|
} |
|
|
|
line_len = 0; |
|
|
|
linebuf[0] = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
/* LF 도착 = 한 줄 완성 */ |
|
|
|
if (c == '\n') { |
|
|
|
if (!(linebuf[0] == 'x' || linebuf[0] == 'X')) { |
|
|
|
PC_PrintLine_CRLF(linebuf); |
|
|
|
got_any_line = 1; |
|
|
|
} |
|
|
|
|
|
|
|
line_len = 0; |
|
|
|
linebuf[0] = '\0'; |
|
|
|
|
|
|
|
/* OFF 응답처럼 <end>가 오면 종료 */ |
|
|
|
if (g_rs485_bridge_done) { |
|
|
|
g_rs485_bridge_active = 0; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (had_byte) { |
|
|
|
idle_us = 0; |
|
|
|
} else if (got_any_line) { |
|
|
|
idle_us += 50U; |
|
|
|
if (idle_us >= BRIDGE_IDLE_DONE_US) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
total_us -= 1000U; |
|
|
|
delay_us(50); |
|
|
|
total_us -= 50U; |
|
|
|
} |
|
|
|
|
|
|
|
/* 남은 partial line이 있으면 마지막으로 출력 */ |
|
|
|
if (line_len > 0) { |
|
|
|
linebuf[line_len] = '\0'; |
|
|
|
if (!(linebuf[0] == 'x' || linebuf[0] == 'X')) { |
|
|
|
PC_PrintLine_CRLF(linebuf); |
|
|
|
got_any_line = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!got_any_line) { |
|
|
|
@ -1404,13 +1595,9 @@ static void app_job_tick(void) |
|
|
|
app_runtime_reset(); |
|
|
|
return; |
|
|
|
|
|
|
|
/* 나머지는 기존 실행 경로 그대로 */ |
|
|
|
process_one_line_now(src, g_app_runtime_job.job.line); |
|
|
|
app_runtime_reset(); |
|
|
|
return; |
|
|
|
|
|
|
|
case APP_JOB_PROTO_OW: |
|
|
|
case APP_JOB_PROTO_OR: |
|
|
|
/* 자기 주소면 실행 */ |
|
|
|
if (g_app_runtime_job.job.addr == g_fixed_addr) { |
|
|
|
if (!execute_owi_service_from_job(src, &g_app_runtime_job.job)) { |
|
|
|
OUT_PRINT(src, "Err:job_exec\r\n"); |
|
|
|
@ -1426,6 +1613,12 @@ static void app_job_tick(void) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* 슬레이브가 RS485에서 받은 비대상 명령은 무시 */ |
|
|
|
if (src == CMD_SRC_RS485) { |
|
|
|
app_runtime_reset(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
OUT_PRINT(src, "Err:job_exec\r\n"); |
|
|
|
app_runtime_reset(); |
|
|
|
return; |
|
|
|
|