|
|
@ -485,7 +485,10 @@ static void scan_one_addr_rs485(uint8_t addr) |
|
|
|
|
|
|
|
|
RS485_FlushJunk(2, 100); |
|
|
RS485_FlushJunk(2, 100); |
|
|
|
|
|
|
|
|
for (try = 0; try < 2; try++) { |
|
|
for (try = 0; try < 1; try++) { /* 재시도도 우선 1회로 줄이기 */ |
|
|
|
|
|
uint32_t total_wait_us; |
|
|
|
|
|
char linebuf[32]; |
|
|
|
|
|
|
|
|
if (g_rs485_need_recover) { |
|
|
if (g_rs485_need_recover) { |
|
|
rs485_recover(); |
|
|
rs485_recover(); |
|
|
} |
|
|
} |
|
|
@ -502,25 +505,31 @@ static void scan_one_addr_rs485(uint8_t addr) |
|
|
g_uart0_tx_done = 0; |
|
|
g_uart0_tx_done = 0; |
|
|
RS485_PRINT(cmdline); |
|
|
RS485_PRINT(cmdline); |
|
|
|
|
|
|
|
|
UART0_WaitTxDone_Flag(5000); |
|
|
UART0_WaitTxDone_Flag(10000); |
|
|
rs485_set_tx(0); |
|
|
rs485_set_tx(0); |
|
|
delay_us(250); |
|
|
delay_us(500); |
|
|
|
|
|
|
|
|
{ |
|
|
total_wait_us = 10000U; |
|
|
uint32_t total_wait_us = 8000; |
|
|
|
|
|
char linebuf[32]; |
|
|
while (total_wait_us >= 500U) { |
|
|
|
|
|
int got = RS485_Bridge_ReadLine(linebuf, sizeof(linebuf), 500); |
|
|
|
|
|
|
|
|
|
|
|
if (got) { |
|
|
|
|
|
/* echo 라인은 무시 */ |
|
|
|
|
|
if (linebuf[0] == 'x' || linebuf[0] == 'X') { |
|
|
|
|
|
total_wait_us -= 500U; |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
while (total_wait_us > 0) { |
|
|
if (Is_V_Response_For(linebuf, addr)) { |
|
|
int got = RS485_Bridge_ReadLine(linebuf, sizeof(linebuf), 1000); |
|
|
|
|
|
if (got && Is_V_Response_For(linebuf, addr)) { |
|
|
|
|
|
PC_PrintLine_CRLF(linebuf); |
|
|
PC_PrintLine_CRLF(linebuf); |
|
|
g_rs485_bridge_active = 0; |
|
|
g_rs485_bridge_active = 0; |
|
|
|
|
|
delay_us(500); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (total_wait_us >= 1000) total_wait_us -= 1000; |
|
|
|
|
|
else total_wait_us = 0; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
total_wait_us -= 500U; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
g_rs485_bridge_active = 0; |
|
|
g_rs485_bridge_active = 0; |
|
|
@ -588,7 +597,21 @@ static void cmd_unknown(const unsigned char *d, unsigned int len) |
|
|
|
|
|
|
|
|
static void print_owi_write_result(CmdSource src, const app_owi_result_t *r) |
|
|
static void print_owi_write_result(CmdSource src, const app_owi_result_t *r) |
|
|
{ |
|
|
{ |
|
|
(void)r; |
|
|
char msg[64]; |
|
|
|
|
|
|
|
|
|
|
|
if (!r) { |
|
|
|
|
|
OUT_PRINT(src, "Err:owi_null\r\n"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!r->ok || r->timeout) { |
|
|
|
|
|
sprintf(msg, "51 !TO(B%u b%u)\r\n", |
|
|
|
|
|
(unsigned)r->timeout_byte_index, |
|
|
|
|
|
(unsigned)r->timeout_bit_index); |
|
|
|
|
|
OUT_PRINT(src, msg); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
OUT_PRINT(src, "51\r\n"); |
|
|
OUT_PRINT(src, "51\r\n"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -627,6 +650,109 @@ static void print_owi_read_result(CmdSource src, const app_owi_result_t *r) |
|
|
OUT_PRINT(src, out); |
|
|
OUT_PRINT(src, out); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int execute_owi_service_from_job(CmdSource src, const app_job_t *job) |
|
|
|
|
|
{ |
|
|
|
|
|
app_owi_result_t r; |
|
|
|
|
|
|
|
|
|
|
|
if (!job) 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; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
if (job->type == APP_JOB_PROTO_OW) { |
|
|
|
|
|
if (job->proto == APP_PROTO_OWIT) { |
|
|
|
|
|
r = app_owi_write_t_basic(job->id, job->payload, (uint8_t)job->len); |
|
|
|
|
|
} else { |
|
|
|
|
|
r = app_owi_write_basic(job->id, job->payload, (uint8_t)job->len); |
|
|
|
|
|
} |
|
|
|
|
|
print_owi_write_result(src, &r); |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (job->type == APP_JOB_PROTO_OR) { |
|
|
|
|
|
r = app_owi_read_basic(job->id, (int)job->len); |
|
|
|
|
|
print_owi_read_result(src, &r); |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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]; |
|
|
|
|
|
int n; |
|
|
|
|
|
uint8_t got_any_line = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (!line) return; |
|
|
|
|
|
|
|
|
|
|
|
g_rs485_bridge_active = 1; |
|
|
|
|
|
g_rs485_bridge_done = 0; |
|
|
|
|
|
RS485_Bridge_ResetFifo(); |
|
|
|
|
|
|
|
|
|
|
|
rs485_rx_done = 0; |
|
|
|
|
|
rs485_rx_index = 0; |
|
|
|
|
|
rs485_rx_length = 0; |
|
|
|
|
|
R_UART0_Receive((uint8_t*)&rs485_rx_buffer[0], 1); |
|
|
|
|
|
|
|
|
|
|
|
n = (int)strlen(line); |
|
|
|
|
|
if (n > (int)sizeof(txbuf) - 3) n = (int)sizeof(txbuf) - 3; |
|
|
|
|
|
|
|
|
|
|
|
memcpy(txbuf, line, (size_t)n); |
|
|
|
|
|
txbuf[n++] = '\r'; |
|
|
|
|
|
txbuf[n++] = '\n'; |
|
|
|
|
|
txbuf[n] = '\0'; |
|
|
|
|
|
|
|
|
|
|
|
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 */ |
|
|
|
|
|
|
|
|
|
|
|
while (total_us >= 1000U) { |
|
|
|
|
|
int got = RS485_Bridge_ReadLine(linebuf, sizeof(linebuf), 1000); |
|
|
|
|
|
|
|
|
|
|
|
if (got) { |
|
|
|
|
|
/* 자기 echo 무시 */ |
|
|
|
|
|
if (linebuf[0] == 'x' || linebuf[0] == 'X') { |
|
|
|
|
|
total_us -= 1000U; |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PC_PrintLine_CRLF(linebuf); |
|
|
|
|
|
got_any_line = 1; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
total_us -= 1000U; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!got_any_line) { |
|
|
|
|
|
OUT_PRINT(CMD_SRC_PC, "Err:rs485_no_response\r\n"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
g_rs485_bridge_active = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static int execute_owi_service_from_line(CmdSource src, const char *line) |
|
|
static int execute_owi_service_from_line(CmdSource src, const char *line) |
|
|
{ |
|
|
{ |
|
|
uint8_t addr = 0, ch = 0; |
|
|
uint8_t addr = 0, ch = 0; |
|
|
@ -1186,6 +1312,18 @@ static void process_one_line(CmdSource src, const volatile uint8_t *rx_buf, uint |
|
|
idx = build_line_from_rx(rx_buf, (int)rx_len, line, (int)sizeof(line)); |
|
|
idx = build_line_from_rx(rx_buf, (int)rx_len, line, (int)sizeof(line)); |
|
|
if (idx <= 0) return; |
|
|
if (idx <= 0) return; |
|
|
|
|
|
|
|
|
|
|
|
/* RS485 xNNv는 큐를 타지 말고 즉시 응답 */ |
|
|
|
|
|
if (src == CMD_SRC_RS485) { |
|
|
|
|
|
uint8_t vaddr = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (parse_x_v_cmd(line, idx, &vaddr)) { |
|
|
|
|
|
if (vaddr == g_fixed_addr) { |
|
|
|
|
|
send_v_response(CMD_SRC_RS485, g_fixed_addr); |
|
|
|
|
|
} |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (src == CMD_SRC_RS485) { |
|
|
if (src == CMD_SRC_RS485) { |
|
|
if (!(line[0] == 'x' || line[0] == 'X')) return; |
|
|
if (!(line[0] == 'x' || line[0] == 'X')) return; |
|
|
} |
|
|
} |
|
|
@ -1239,38 +1377,58 @@ static void app_job_tick(void) |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* 기존 x00v on master(0) from PC 만 분할 실행 */ |
|
|
/* 마스터 x00v */ |
|
|
if (g_fixed_addr == 0 && src == CMD_SRC_PC && scan_addr == 0) { |
|
|
if (g_fixed_addr == 0 && src == CMD_SRC_PC && scan_addr == 0) { |
|
|
if (!g_app_runtime_job.scan_started) { |
|
|
if (!g_app_runtime_job.scan_started) { |
|
|
send_v_response(CMD_SRC_PC, 0); |
|
|
send_v_response(CMD_SRC_PC, 0); |
|
|
g_app_runtime_job.scan_started = 1; |
|
|
g_app_runtime_job.scan_started = 1; |
|
|
g_app_runtime_job.current_scan_addr = 1; |
|
|
g_app_runtime_job.current_scan_addr = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (g_app_runtime_job.current_scan_addr <= 31) { |
|
|
if (g_app_runtime_job.current_scan_addr <= 31) { |
|
|
scan_one_addr_rs485(g_app_runtime_job.current_scan_addr); |
|
|
scan_one_addr_rs485(g_app_runtime_job.current_scan_addr); |
|
|
g_app_runtime_job.current_scan_addr++; |
|
|
g_app_runtime_job.current_scan_addr++; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
app_runtime_reset(); |
|
|
app_runtime_reset(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 슬레이브 xNNv 직접 처리 */ |
|
|
|
|
|
if (scan_addr == g_fixed_addr) { |
|
|
|
|
|
send_v_response(src, g_fixed_addr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
app_runtime_reset(); |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
/* 나머지는 기존 실행 경로 그대로 */ |
|
|
/* 나머지는 기존 실행 경로 그대로 */ |
|
|
process_one_line_now(src, g_app_runtime_job.job.line); |
|
|
process_one_line_now(src, g_app_runtime_job.job.line); |
|
|
app_runtime_reset(); |
|
|
app_runtime_reset(); |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
case APP_JOB_PROTO_OW: |
|
|
case APP_JOB_PROTO_OW: |
|
|
case APP_JOB_PROTO_OR: |
|
|
case APP_JOB_PROTO_OR: |
|
|
if (!execute_owi_service_from_line(src, g_app_runtime_job.job.line)) { |
|
|
if (g_app_runtime_job.job.addr == g_fixed_addr) { |
|
|
/* service로 못 처리하면 기존 경로로 fallback */ |
|
|
if (!execute_owi_service_from_job(src, &g_app_runtime_job.job)) { |
|
|
process_one_line_now(src, g_app_runtime_job.job.line); |
|
|
OUT_PRINT(src, "Err:job_exec\r\n"); |
|
|
|
|
|
} |
|
|
|
|
|
app_runtime_reset(); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
app_runtime_reset(); |
|
|
|
|
|
return; |
|
|
/* 마스터가 PC 명령을 원격 보드로 forwarding */ |
|
|
|
|
|
if (g_fixed_addr == 0 && src == CMD_SRC_PC && g_app_runtime_job.job.addr != 0) { |
|
|
|
|
|
forward_line_rs485_and_bridge(g_app_runtime_job.job.line); |
|
|
|
|
|
app_runtime_reset(); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
OUT_PRINT(src, "Err:job_exec\r\n"); |
|
|
|
|
|
app_runtime_reset(); |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
case APP_JOB_FORWARD_LINE: |
|
|
case APP_JOB_FORWARD_LINE: |
|
|
case APP_JOB_LOCAL_EXEC: |
|
|
case APP_JOB_LOCAL_EXEC: |
|
|
|