|
|
|
@ -58,8 +58,8 @@ Includes |
|
|
|
#define UART_RX_BUF_SIZE 1024 |
|
|
|
#define RS485_BRIDGE_FIFO_SZ 2048 |
|
|
|
|
|
|
|
#define BRIDGE_IDLE_DONE_US 20000U // ? 3ms ? ?
|
|
|
|
#define BRIDGE_TOTAL_WAIT_US 3000000U |
|
|
|
#define BRIDGE_IDLE_DONE_US 2000000U // ? 3ms ? ?
|
|
|
|
#define BRIDGE_TOTAL_WAIT_US 6000000U |
|
|
|
|
|
|
|
/* =========================
|
|
|
|
* UART RX Buffers |
|
|
|
@ -705,6 +705,7 @@ static int execute_connect_verify_sequence(CmdSource src, const app_job_t *job) |
|
|
|
uint8_t write1_data[3]; |
|
|
|
uint8_t expected_tail[3]; |
|
|
|
uint8_t cmd_7c = 0x7C; |
|
|
|
uint8_t attempt; |
|
|
|
|
|
|
|
if (!job) return 0; |
|
|
|
|
|
|
|
@ -727,7 +728,86 @@ static int execute_connect_verify_sequence(CmdSource src, const app_job_t *job) |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* prefix / gate */ |
|
|
|
memcpy(write1_data, &job->payload[0], 3); |
|
|
|
memcpy(expected_tail, &job->payload[3], 3); |
|
|
|
|
|
|
|
for (attempt = 0; attempt < 2; attempt++) { |
|
|
|
|
|
|
|
/* 재시도 전 OFF 처리 */ |
|
|
|
if (attempt > 0) { |
|
|
|
Cal_Init(); |
|
|
|
delay_us(30000); |
|
|
|
} |
|
|
|
|
|
|
|
/* 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); |
|
|
|
|
|
|
|
delay_us(30000); |
|
|
|
|
|
|
|
/* 1) OWT 28 003 + first3 */ |
|
|
|
r_write1 = app_owi_write_t_basic(0x28u, write1_data, 3); |
|
|
|
if (!r_write1.ok || r_write1.timeout) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
/* 2) OR 28 002 */ |
|
|
|
r_read2 = app_owi_read_basic(0x28u, 2); |
|
|
|
if (!r_read2.ok || r_read2.timeout || r_read2.read_len < 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
/* 3) OWT 28 001 + 7C */ |
|
|
|
r_write3 = app_owi_write_t_basic(0x28u, &cmd_7c, 1); |
|
|
|
if (!r_write3.ok || r_write3.timeout) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
/* 4) OR 28 003 -> 실제 칩 결과 읽기 */ |
|
|
|
r_read3 = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read3.ok || r_read3.timeout || r_read3.read_len < 3) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
/* 실제 읽은 3바이트와 기대값 비교 */ |
|
|
|
if (memcmp(r_read3.data, expected_tail, 3) == 0) { |
|
|
|
OUT_PRINT(src, "Success\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int execute_direct_read_sequence(CmdSource src, const app_job_t *job) |
|
|
|
{ |
|
|
|
app_owi_result_t r_write; |
|
|
|
app_owi_result_t r_read; |
|
|
|
uint8_t read_len = 0; |
|
|
|
|
|
|
|
if (!job) return 0; |
|
|
|
|
|
|
|
/* 일반 OW 패턴만 처리 */ |
|
|
|
if (job->type != APP_JOB_PROTO_OW) return 0; |
|
|
|
if (job->proto != APP_PROTO_OWIW) return 0; |
|
|
|
if (job->id != 0x28u) return 0; |
|
|
|
if (job->len != 3u) return 0; |
|
|
|
if (job->addr != g_fixed_addr) return 0; |
|
|
|
|
|
|
|
if (job->channel < 1 || job->channel > 20) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (job->mode == 'C') { |
|
|
|
s_prefix_mode = PREFIX_CAL; |
|
|
|
Cal_Init(); |
|
|
|
@ -739,43 +819,156 @@ static int execute_connect_verify_sequence(CmdSource src, const app_job_t *job) |
|
|
|
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); |
|
|
|
/* payload 3바이트 패턴으로 read 길이 결정 */ |
|
|
|
if (job->payload[0] == 0x2E && job->payload[1] == 0x00 && job->payload[2] == 0x1F) { |
|
|
|
read_len = 65; /* outmem */ |
|
|
|
} |
|
|
|
else if (job->payload[0] == 0x22 && job->payload[1] == 0x00 && job->payload[2] == 0x3A) { |
|
|
|
read_len = 119; /* shadow */ |
|
|
|
} |
|
|
|
else if (job->payload[0] == 0x26 && job->payload[1] == 0x00 && job->payload[2] == 0x3E) { |
|
|
|
read_len = 127; /* nvm */ |
|
|
|
} |
|
|
|
else if (job->payload[0] == 0x0B && job->payload[1] == 0x04 && job->payload[2] == 0x06) { |
|
|
|
read_len = 23; /* acquiredata */ |
|
|
|
} |
|
|
|
else { |
|
|
|
return 0; /* 일반 ow는 기존 처리로 넘김 */ |
|
|
|
} |
|
|
|
|
|
|
|
/* 1) GUI에서 보낸 ow 명령 그대로 write */ |
|
|
|
r_write = app_owi_write_basic(0x28u, job->payload, 3); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 2) 대응되는 read 수행 */ |
|
|
|
r_read = app_owi_read_basic(0x28u, read_len); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < read_len) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 3) 읽은 값만 출력 */ |
|
|
|
print_owi_read_result(src, &r_read); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int execute_write_coeff_sequence(CmdSource src, const app_job_t *job) |
|
|
|
{ |
|
|
|
app_owi_result_t r_write1; |
|
|
|
app_owi_result_t r_read1; |
|
|
|
app_owi_result_t r_write2; |
|
|
|
app_owi_result_t r_read2; |
|
|
|
|
|
|
|
/* 1) OWT 28 003 + first3 */ |
|
|
|
r_write1 = app_owi_write_t_basic(0x28u, write1_data, 3); |
|
|
|
print_owi_write_result(src, &r_write1); |
|
|
|
static const uint8_t nvm_read_cmd[3] = { 0x26, 0x00, 0x3E }; |
|
|
|
|
|
|
|
/* coefficient data:
|
|
|
|
payload[0] = 0x23 (write coeff cmd) |
|
|
|
payload[1] = 0x0D (start addr) |
|
|
|
payload[2] = 0x0E (length info -> 15 words) |
|
|
|
payload[3..32] = coefficient 15 words = 30 bytes |
|
|
|
*/ |
|
|
|
const uint8_t *coeff_data; |
|
|
|
const uint8_t *nvm_coeff_data; |
|
|
|
|
|
|
|
uint16_t coeff_len_bytes = 30u; |
|
|
|
|
|
|
|
/* NVM read result format:
|
|
|
|
data[0] = 0x26 header |
|
|
|
data[1..126] = 63 words = 126 bytes |
|
|
|
coefficient word range = 0x0D ~ 0x1B (15 words) |
|
|
|
byte start index = 1 + (0x0D * 2) = 27 |
|
|
|
*/ |
|
|
|
uint16_t nvm_coeff_start = 1u + (0x0Du * 2u); |
|
|
|
|
|
|
|
if (!job) return 0; |
|
|
|
|
|
|
|
/* write coefficients 전용 패턴 */ |
|
|
|
if (job->type != APP_JOB_PROTO_OW) return 0; |
|
|
|
if (job->proto != APP_PROTO_OWIW) return 0; |
|
|
|
if (job->id != 0x28u) return 0; |
|
|
|
if (job->addr != g_fixed_addr) return 0; |
|
|
|
|
|
|
|
/* prefix 후보 확인 */ |
|
|
|
if (!(job->len >= 3u && |
|
|
|
job->payload[0] == 0x23u && |
|
|
|
job->payload[1] == 0x0Du && |
|
|
|
job->payload[2] == 0x0Eu)) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* 길이는 정확히 33바이트여야 함 */ |
|
|
|
if (job->len != 33u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (job->channel < 1 || job->channel > 20) { |
|
|
|
OUT_PRINT(src, "Fail\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); |
|
|
|
|
|
|
|
coeff_data = &job->payload[3]; |
|
|
|
|
|
|
|
/* 1) GUI가 보낸 coefficient write 전체 수행 */ |
|
|
|
r_write1 = app_owi_write_basic(0x28u, job->payload, (uint8_t)job->len); |
|
|
|
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) { |
|
|
|
/* 2) or28001 -> 23 확인 */ |
|
|
|
r_read1 = app_owi_read_basic(0x28u, 1); |
|
|
|
if (!r_read1.ok || r_read1.timeout || r_read1.read_len < 1) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (r_read1.data[0] != 0x23u) { |
|
|
|
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) { |
|
|
|
/* 3) NVM read command: ow2800326003e */ |
|
|
|
r_write2 = app_owi_write_basic(0x28u, nvm_read_cmd, 3); |
|
|
|
if (!r_write2.ok || r_write2.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) { |
|
|
|
/* 4) or28127 */ |
|
|
|
r_read2 = app_owi_read_basic(0x28u, 127); |
|
|
|
if (!r_read2.ok || r_read2.timeout || r_read2.read_len < 127) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 실제 읽은 3바이트와 기대값 비교 */ |
|
|
|
if (memcmp(r_read3.data, expected_tail, 3) == 0) { |
|
|
|
/* NVM read 응답 첫 바이트는 0x26 이어야 정상 */ |
|
|
|
if (r_read2.data[0] != 0x26u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 5) coefficient 영역 readback 비교
|
|
|
|
- coeff_data: payload[3..32] (30 bytes) |
|
|
|
- nvm_coeff_data: r_read2.data[27..56] (30 bytes) |
|
|
|
*/ |
|
|
|
nvm_coeff_data = &r_read2.data[nvm_coeff_start]; |
|
|
|
|
|
|
|
if (memcmp(nvm_coeff_data, coeff_data, coeff_len_bytes) == 0) { |
|
|
|
OUT_PRINT(src, "Success\r\n"); |
|
|
|
} else { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
@ -784,14 +977,285 @@ static int execute_connect_verify_sequence(CmdSource src, const app_job_t *job) |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int execute_shadow_write_copy_nvm_sequence(CmdSource src, const app_job_t *job) |
|
|
|
{ |
|
|
|
app_owi_result_t r_write; |
|
|
|
app_owi_result_t r_read; |
|
|
|
|
|
|
|
|
|
|
|
static const uint8_t cmd_crc_44[3] = { 0x44, 0x00, 0x39 }; |
|
|
|
static const uint8_t cmd_15_3c5b[3] = { 0x15, 0x3C, 0x5B }; |
|
|
|
static const uint8_t cmd_14[1] = { 0x14 }; |
|
|
|
static const uint8_t cmd_1a[1] = { 0x1A }; |
|
|
|
static const uint8_t cmd_crc_40[3] = { 0x40, 0x00, 0x39 }; |
|
|
|
static const uint8_t cmd_crc_42[3] = { 0x42, 0x00, 0x39 }; |
|
|
|
static const uint8_t cmd_15_0000[3] = { 0x15, 0x00, 0x00 }; |
|
|
|
static const uint8_t cmd_nvm_read[3] = { 0x26, 0x00, 0x3E }; |
|
|
|
|
|
|
|
const uint8_t *gui_crc; |
|
|
|
uint16_t poll_count = 0; |
|
|
|
|
|
|
|
if (!job) return 0; |
|
|
|
|
|
|
|
/* shadow write + shadow to nvm 전용 패턴
|
|
|
|
payload = 230039 + data(116바이트) + crc(2바이트) |
|
|
|
전체 len = 121바이트 |
|
|
|
*/ |
|
|
|
if (job->type != APP_JOB_PROTO_OW) return 0; |
|
|
|
if (job->proto != APP_PROTO_OWIW) return 0; |
|
|
|
if (job->id != 0x28u) return 0; |
|
|
|
if (job->addr != g_fixed_addr) return 0; |
|
|
|
|
|
|
|
/* payload 시작 패턴: 23 00 39 */ |
|
|
|
if (!(job->len >= 3u && |
|
|
|
job->payload[0] == 0x23u && |
|
|
|
job->payload[1] == 0x00u && |
|
|
|
job->payload[2] == 0x39u)) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* 전체 길이는 정확히 121바이트 */ |
|
|
|
if (job->len != 121u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (job->channel < 1 || job->channel > 20) { |
|
|
|
OUT_PRINT(src, "Fail\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); |
|
|
|
|
|
|
|
/* 마지막 2바이트를 GUI CRC로 사용 */ |
|
|
|
gui_crc = &job->payload[119]; |
|
|
|
|
|
|
|
/* 1) ow28119230039 + data + crc */ |
|
|
|
r_write = app_owi_write_basic(0x28u, job->payload, 119u); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 2) or28001 -> 23 */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 1); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 1) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (r_read.data[0] != 0x23u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 3) ow28003440039 */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_crc_44, 3); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 4) or28003 -> 44 + CRC */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (r_read.data[0] != 0x44u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (memcmp(&r_read.data[1], gui_crc, 2) != 0) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 5) ow28003153c5b */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_15_3c5b, 3); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 6) or28003 -> 150001 */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (!(r_read.data[0] == 0x15u && r_read.data[1] == 0x00u && r_read.data[2] == 0x01u)) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 7) ow2800114 */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_14, 1); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 8) or28003 -> 140001 */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (!(r_read.data[0] == 0x14u && r_read.data[1] == 0x00u && r_read.data[2] == 0x01u)) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 9) ow280011a 한 번만 보냄 */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_1a, 1); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
for (poll_count = 0; poll_count < 50u; poll_count++) { |
|
|
|
char dbg[40]; |
|
|
|
|
|
|
|
r_read = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (r_read.data[0] == 0x1Au && |
|
|
|
r_read.data[1] == 0x00u && |
|
|
|
r_read.data[2] == 0x00u) { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
delay_us(5000); |
|
|
|
} |
|
|
|
|
|
|
|
if (poll_count >= 50u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 10) ow28003400039 */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_crc_40, 3); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 11) or28003 -> 40 + CRC */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (r_read.data[0] != 0x40u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (memcmp(&r_read.data[1], gui_crc, 2) != 0) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 12) ow28003420039 */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_crc_42, 3); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 13) or28003 -> 42 + CRC */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (r_read.data[0] != 0x42u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (memcmp(&r_read.data[1], gui_crc, 2) != 0) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 14) ow28003150000 */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_15_0000, 3); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 15) or28003 -> 150000 */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 3); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 3) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (!(r_read.data[0] == 0x15u && r_read.data[1] == 0x00u && r_read.data[2] == 0x00u)) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 16) ow2800326003e */ |
|
|
|
r_write = app_owi_write_basic(0x28u, cmd_nvm_read, 3); |
|
|
|
if (!r_write.ok || r_write.timeout) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 17) or28127 */ |
|
|
|
r_read = app_owi_read_basic(0x28u, 127); |
|
|
|
if (!r_read.ok || r_read.timeout || r_read.read_len < 127) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
if (r_read.data[0] != 0x26u) { |
|
|
|
OUT_PRINT(src, "Fail\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
print_owi_read_result(src, &r_read); |
|
|
|
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; |
|
|
|
|
|
|
|
// connect
|
|
|
|
if (execute_connect_verify_sequence(src, job)) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
// nvm, shadow, outmem
|
|
|
|
if (execute_direct_read_sequence(src, job)) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
// write_coefficient
|
|
|
|
if (execute_write_coeff_sequence(src, job)) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
// shadow_write to copy nvm
|
|
|
|
if (execute_shadow_write_copy_nvm_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"); |
|
|
|
@ -1142,8 +1606,6 @@ static void process_one_line_now(CmdSource src, const char *input_line) |
|
|
|
char orig_line[UART_RX_BUF_SIZE]; |
|
|
|
int orig_len = 0; |
|
|
|
|
|
|
|
char msg[64]; |
|
|
|
|
|
|
|
s_prefix_mode = PREFIX_NONE; |
|
|
|
|
|
|
|
if (!input_line) return; |
|
|
|
@ -1185,98 +1647,37 @@ static void process_one_line_now(CmdSource src, const char *input_line) |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* =========================
|
|
|
|
* 1.5) xNNo(OFF) |
|
|
|
* ========================= */ |
|
|
|
{ |
|
|
|
uint8_t off_addr = 0; |
|
|
|
if (parse_x_o_cmd(line, idx, &off_addr)) { |
|
|
|
|
|
|
|
if (off_addr > 31) { OUT_PRINT(src, "Err:addr_range\r\n"); return; } |
|
|
|
|
|
|
|
/* 1) OFF */ |
|
|
|
if (off_addr == g_fixed_addr) { |
|
|
|
Cal_Init(); |
|
|
|
OUT_PRINT(src, "<ACK>OFF\r\n"); |
|
|
|
send_end_response(src); //? <end>
|
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* 2) 0(addr=0) + PC x01o RS485 */ |
|
|
|
if (g_fixed_addr == 0 && src == CMD_SRC_PC) { |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
/* ---- RS485 ---- */ |
|
|
|
{ |
|
|
|
static char txbuf[UART_RX_BUF_SIZE + 4]; |
|
|
|
int n = idx; // 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'; |
|
|
|
|
|
|
|
/* UART0 TX busy */ |
|
|
|
{ |
|
|
|
unsigned long g = 0; |
|
|
|
while (g_uart0_tx_count != 0U) { |
|
|
|
if (g++ > 3000000UL) break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
RS485_PRINT(txbuf); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
uint32_t total_us = BRIDGE_TOTAL_WAIT_US; |
|
|
|
uint32_t idle_us = 0; |
|
|
|
uint16_t last_seq = g_rs485_bridge_seq; |
|
|
|
uint8_t got_any = 0; |
|
|
|
|
|
|
|
while (total_us >= 50U) { |
|
|
|
RS485_Bridge_DrainToPC(); |
|
|
|
delay_us(50); |
|
|
|
total_us -= 50U; |
|
|
|
|
|
|
|
if (g_rs485_bridge_done) break; // <end>
|
|
|
|
|
|
|
|
if (g_rs485_bridge_seq != last_seq) { |
|
|
|
last_seq = g_rs485_bridge_seq; |
|
|
|
got_any = 1; |
|
|
|
idle_us = 0; |
|
|
|
} else if (got_any) { |
|
|
|
idle_us += 50U; |
|
|
|
if (idle_us >= BRIDGE_IDLE_DONE_US) break; // 3ms idle
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
RS485_Bridge_DrainToPC(); |
|
|
|
g_rs485_bridge_active = 0; |
|
|
|
|
|
|
|
if (total_us < 300U) { |
|
|
|
rs485_recover(); |
|
|
|
OUT_PRINT(CMD_SRC_PC, "Err:rs485_timeout\r\n"); |
|
|
|
sprintf(msg, "Err:rs485_timeout fef=%lu ovf=%lu pef=%lu\r\n", |
|
|
|
g_uart0_err_fef, g_uart0_err_ovf, g_uart0_err_pef); |
|
|
|
OUT_PRINT(CMD_SRC_PC, msg); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return; // mismatch
|
|
|
|
} |
|
|
|
} |
|
|
|
/* =========================
|
|
|
|
* 1.5) xNNo(OFF) |
|
|
|
* ========================= */ |
|
|
|
{ |
|
|
|
uint8_t off_addr = 0; |
|
|
|
|
|
|
|
if (parse_x_o_cmd(line, idx, &off_addr)) { |
|
|
|
|
|
|
|
if (off_addr > 31) { |
|
|
|
OUT_PRINT(src, "Err:addr_range\r\n"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* 자기 주소면 로컬 OFF 처리 */ |
|
|
|
if (off_addr == g_fixed_addr) { |
|
|
|
Cal_Init(); |
|
|
|
OUT_PRINT(src, "<ACK>OFF\r\n"); |
|
|
|
send_end_response(src); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* 마스터(addr 0)가 PC에서 받은 원격 OFF는
|
|
|
|
공통 RS485 포워딩 함수만 사용 */ |
|
|
|
if (g_fixed_addr == 0 && src == CMD_SRC_PC) { |
|
|
|
forward_line_rs485_and_bridge(line); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* RS485 */ |
|
|
|
orig_len = idx; |
|
|
|
@ -1313,85 +1714,16 @@ static void process_one_line_now(CmdSource src, const char *input_line) |
|
|
|
if (ch < 1 || ch > 20) { OUT_PRINT(src, "Err:ch_range\r\n"); return; } |
|
|
|
|
|
|
|
/* addr mismatch */ |
|
|
|
if (addr != g_fixed_addr) |
|
|
|
{ |
|
|
|
/* 0(addr=0) + PC RS485 */ |
|
|
|
if (g_fixed_addr == 0 && src == CMD_SRC_PC) |
|
|
|
{ |
|
|
|
uint32_t total_us; |
|
|
|
uint32_t idle_us; |
|
|
|
uint16_t last_seq; |
|
|
|
uint8_t got_any; |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
/* ---- RS485 ---- */ |
|
|
|
{ |
|
|
|
static char txbuf[UART_RX_BUF_SIZE + 4]; |
|
|
|
int n = orig_len; |
|
|
|
|
|
|
|
if (n > (int)sizeof(txbuf) - 3) n = (int)sizeof(txbuf) - 3; |
|
|
|
|
|
|
|
memcpy(txbuf, orig_line, (size_t)n); |
|
|
|
txbuf[n++] = '\r'; |
|
|
|
txbuf[n++] = '\n'; |
|
|
|
txbuf[n] = '\0'; |
|
|
|
|
|
|
|
/* UART0 TX busy ? */ |
|
|
|
{ |
|
|
|
unsigned long g = 0; |
|
|
|
while (g_uart0_tx_count != 0U) { |
|
|
|
if (g++ > 3000000UL) break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
RS485_PRINT(txbuf); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
total_us = BRIDGE_TOTAL_WAIT_US; |
|
|
|
idle_us = 0; |
|
|
|
last_seq = g_rs485_bridge_seq; |
|
|
|
got_any = 0; |
|
|
|
|
|
|
|
while (total_us >= 50U) { |
|
|
|
RS485_Bridge_DrainToPC(); |
|
|
|
delay_us(50); |
|
|
|
total_us -= 50U; |
|
|
|
|
|
|
|
if (g_rs485_bridge_done) break; |
|
|
|
|
|
|
|
if (g_rs485_bridge_seq != last_seq) { |
|
|
|
last_seq = g_rs485_bridge_seq; |
|
|
|
got_any = 1; |
|
|
|
idle_us = 0; |
|
|
|
} else if (got_any) { |
|
|
|
idle_us += 50U; |
|
|
|
if (idle_us >= BRIDGE_IDLE_DONE_US) break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
RS485_Bridge_DrainToPC(); |
|
|
|
g_rs485_bridge_active = 0; |
|
|
|
|
|
|
|
if (total_us < 300U) { |
|
|
|
rs485_recover(); |
|
|
|
OUT_PRINT(CMD_SRC_PC, "Err:rs485_timeout\r\n"); |
|
|
|
sprintf(msg, "Err:rs485_timeout fef=%lu ovf=%lu pef=%lu\r\n", |
|
|
|
g_uart0_err_fef, g_uart0_err_ovf, g_uart0_err_pef); |
|
|
|
OUT_PRINT(CMD_SRC_PC, msg); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return; /* addr mismatch */ |
|
|
|
} |
|
|
|
if (addr != g_fixed_addr) |
|
|
|
{ |
|
|
|
/* 0번 보드(PC 연결 마스터)면 그대로 RS485로 포워딩 */ |
|
|
|
if (g_fixed_addr == 0 && src == CMD_SRC_PC) |
|
|
|
{ |
|
|
|
forward_line_rs485_and_bridge(orig_line); |
|
|
|
} |
|
|
|
|
|
|
|
return; /* addr mismatch */ |
|
|
|
} |
|
|
|
|
|
|
|
/* addr == g_fixed_addr */ |
|
|
|
if (mode == 'C') { |
|
|
|
|