/*********************************************************************************************************************** * DISCLAIMER * This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products. * No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all * applicable laws, including copyright laws. * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED * OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY * LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT, * INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR * ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability * of this software. By using this software, you agree to the additional terms and conditions found by accessing the * following link: * http://www.renesas.com/disclaimer * * Copyright (C) 2012, 2021 Renesas Electronics Corporation. All rights reserved. ***********************************************************************************************************************/ /*********************************************************************************************************************** * File Name : r_main.c * Version : CodeGenerator for RL78/F14 V2.03.07.02 [08 Nov 2021] * Device(s) : R5F10PPJ * Tool-Chain : CCRL * Description : main + UART protocol handler * Creation Date: 2026-01-29 ***********************************************************************************************************************/ /*********************************************************************************************************************** Includes ***********************************************************************************************************************/ #include "r_cg_macrodriver.h" #include "r_cg_cgc.h" #include "r_cg_port.h" #include "r_cg_serial.h" /* Start user code for include. Do not edit comment generated here */ #include "common.h" #include "dipSwitch.h" #include "gatectrl.h" #include #include #include #include #include #include "app_types.h" #include "app_cmd_parser.h" #include "app_scheduler.h" #include "app_owi_service.h" /* End user code. Do not edit comment generated here */ #include "r_cg_userdefine.h" /* Start user code for adding. Do not edit comment generated here */ /* ========================= * Config * ========================= */ #define CMD_MAX 529 #define UART_RX_BUF_SIZE 1024 #define RS485_BRIDGE_FIFO_SZ 2048 #define BRIDGE_IDLE_DONE_US 2500000U /* sweep Áß ¼º°ø ¶óÀÎ »çÀÌ ÃÖ´ë ¹«ÀÀ´ä Çã¿ë ½Ã°£ */ #define BRIDGE_TOTAL_WAIT_US 30000000U /* sweep Àüü ºê¸®Áö ÃÖ´ë ´ë±â ½Ã°£ */ #define OWI_LONG_READ_SETTLE_US 30000U #define OWI_LONG_READ_RETRY_US 10000U /* ========================= * UART RX Buffers * ========================= */ volatile uint8_t uart_rx_done = 0; volatile uint16_t uart_rx_index = 0; // uint8_t -> uint16_t volatile uint8_t uart_rx_buffer[UART_RX_BUF_SIZE] = {0}; volatile uint16_t uart_rx_length = 0; volatile uint8_t rs485_rx_done = 0; volatile uint16_t rs485_rx_index = 0; volatile uint8_t rs485_rx_buffer[UART_RX_BUF_SIZE] = {0}; volatile uint16_t rs485_rx_length = 0; volatile uint32_t g_uart0_err_fef = 0; volatile uint32_t g_uart0_err_ovf = 0; volatile uint32_t g_uart0_err_pef = 0; /* RS485 bridge flags */ volatile uint8_t g_rs485_bridge_active = 0; volatile uint8_t g_rs485_bridge_done = 0; volatile uint16_t g_rs485_bridge_seq = 0; static volatile uint8_t s_end_st = 0; static const char s_end_pat[] = ""; /* (0~31) */ uint8_t g_fixed_addr = 0; /* ========================= * Driver globals (Renesas) * ========================= */ extern volatile uint16_t g_uart1_tx_count; /* UART1 TX ?? */ extern volatile uint16_t g_uart0_tx_count; /* UART0 TX ?? */ extern volatile uint8_t g_uart0_tx_done; /* ========================= * RS485 Bridge FIFO * ========================= */ static volatile uint8_t s_rb_fifo[RS485_BRIDGE_FIFO_SZ]; static volatile uint16_t s_rb_head = 0; static volatile uint16_t s_rb_tail = 0; void RS485_Bridge_Push(uint8_t b) { uint16_t next = (uint16_t)(s_rb_head + 1); if (next >= RS485_BRIDGE_FIFO_SZ) next = 0; if (next == s_rb_tail) { uint16_t t = (uint16_t)(s_rb_tail + 1); if (t >= RS485_BRIDGE_FIFO_SZ) t = 0; s_rb_tail = t; } s_rb_fifo[s_rb_head] = b; s_rb_head = next; } static void RS485_Bridge_ResetFifo(void) { s_rb_head = 0; s_rb_tail = 0; s_end_st = 0; g_rs485_bridge_done = 0; } typedef struct { uint8_t active; uint8_t scan_started; uint8_t current_scan_addr; app_job_t job; } app_runtime_job_t; static app_runtime_job_t g_app_runtime_job; static void app_runtime_reset(void) { memset(&g_app_runtime_job, 0, sizeof(g_app_runtime_job)); } static void rs485_abort_and_reset_pipeline(void) { /* bridge Á¤¸® */ g_rs485_bridge_active = 0; g_rs485_bridge_done = 0; RS485_Bridge_ResetFifo(); /* RX »óÅ Á¤¸® */ rs485_rx_done = 0; rs485_rx_index = 0; rs485_rx_length = 0; memset((void*)rs485_rx_buffer, 0, sizeof(rs485_rx_buffer)); /* ÇöÀç job Áß´Ü */ app_runtime_reset(); /* ´ë±â queue ºñ¿ì±â */ app_scheduler_clear(); /* UART0 recover ¿äû */ g_rs485_need_recover = 1; } static int RS485_Bridge_ReadLine(char *out, int out_sz, uint32_t timeout_us) { int n = 0; while (timeout_us--) { // 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 (c == '\r') continue; if (n < out_sz - 1) out[n++] = c; if (c == '\n') { out[n] = '\0'; return 1; // line } } delay_us(1); } if (n > 0) { out[n] = '\0'; } return 0; // timeout } static int Is_V_Response_For(char *line, uint8_t addr) { uint8_t a; if (line[0] != 'V' && line[0] != 'v') return 0; if (!isdigit((unsigned char)line[1]) || !isdigit((unsigned char)line[2])) return 0; a = (uint8_t)((line[1]-'0')*10 + (line[2]-'0')); return (a == addr); } /* ========================= * PC(UART1) Safe TX * R_UART1_Send * ========================= */ static uint8_t g_uart1_txbuf[1024]; static void UART1_WaitTxIdle(void) { unsigned long guard = 0; while (g_uart1_tx_count != 0U) { if (guard++ > 3000000UL) break; /* ? */ } } static void UART1_SendBytes_Safe(const uint8_t *data, uint16_t len) { if (data == 0 || len == 0) return; UART1_WaitTxIdle(); if (len > (uint16_t)sizeof(g_uart1_txbuf)) len = (uint16_t)sizeof(g_uart1_txbuf); memcpy(g_uart1_txbuf, data, len); R_UART1_Send(g_uart1_txbuf, len); UART1_WaitTxIdle(); } static void UART1_SendString_Safe(const char *s) { uint16_t len; if (s == 0) return; UART1_WaitTxIdle(); // ? len = (uint16_t)strlen(s); if (len >= (uint16_t)sizeof(g_uart1_txbuf)) len = (uint16_t)(sizeof(g_uart1_txbuf) - 1); memcpy(g_uart1_txbuf, s, len); g_uart1_txbuf[len] = '\0'; R_UART1_Send(g_uart1_txbuf, len); UART1_WaitTxIdle(); // ? ?: ? ( ? ) } /* ========================= * RS485 Bridge Drain -> PC * - uart1_send_string(out) * - UART1_SendBytes_Safe * ========================= */ static void RS485_Bridge_DrainToPC(void) { uint16_t n = 0; /* UART1 TX */ if (g_uart1_tx_count != 0U) return; while (s_rb_tail != s_rb_head && n < 1024U) { g_uart1_txbuf[n++] = s_rb_fifo[s_rb_tail]; s_rb_tail++; if (s_rb_tail >= RS485_BRIDGE_FIFO_SZ) s_rb_tail = 0; } if (n > 0) { R_UART1_Send(g_uart1_txbuf, n); } } /* ========================= * Helpers * ========================= */ static unsigned char hex2byte(char h, char l) { unsigned char hi, lo; if (h >= 'a' && h <= 'f') h -= 32; if (l >= 'a' && l <= 'f') l -= 32; hi = (h >= 'A') ? (unsigned char)(h - 'A' + 10) : (unsigned char)(h - '0'); lo = (l >= 'A') ? (unsigned char)(l - 'A' + 10) : (unsigned char)(l - '0'); return (unsigned char)((hi << 4) | lo); } static uint8_t is_long_owi_read_len(uint8_t len) { return (len == 119u || len == 127u); } static app_owi_result_t do_stable_owi_read(uint8_t id, uint8_t read_len) { app_owi_result_t r; if (is_long_owi_read_len(read_len)) { delay_us(OWI_LONG_READ_SETTLE_US); } r = app_owi_read_basic(id, (int)read_len); if ((!r.ok || r.timeout || r.read_len < read_len) && is_long_owi_read_len(read_len)) { delay_us(OWI_LONG_READ_RETRY_US); r = app_owi_read_basic(id, (int)read_len); } return r; } /* ========================= * Prefix mode * ========================= */ typedef enum { PREFIX_NONE = 0, PREFIX_CAL, PREFIX_EOL } PrefixMode; static PrefixMode s_prefix_mode = PREFIX_NONE; /* ========================= * parse x-prefix: xNNc_001011:... * ========================= */ static int parse_x_prefix(const char *s, int len, uint8_t *addr, uint8_t *ch, char *mode, uint8_t *hash_on, uint8_t *anaout_on, uint8_t *check_on, int *payload_pos) { if (len < 8) return 0; if (!(s[0] == 'x' || s[0] == 'X')) return 0; if (!isdigit((unsigned char)s[1]) || !isdigit((unsigned char)s[2])) return -1; if (s[3] == 'c' || s[3] == 'C') *mode = 'C'; else if (s[3] == 'e' || s[3] == 'E') *mode = 'E'; else return -1; if (s[4] != '_') return -1; if (!isdigit((unsigned char)s[5]) || !isdigit((unsigned char)s[6]) || !isdigit((unsigned char)s[7])) return -1; *addr = (uint8_t)((s[1] - '0') * 10 + (s[2] - '0')); *ch = (uint8_t)((s[5] - '0') * 100 + (s[6] - '0') * 10 + (s[7] - '0')); /* prefix only: x01c_001 */ if (len == 8) { *payload_pos = len; return 1; } /* payload: x01c_001:... */ if (s[8] == ':') { *payload_pos = 9; return 1; } /* flags: x01c_001011 or x01c_001011:... */ if (len >= 11 && (s[8] == '0' || s[8] == '1') && (s[9] == '0' || s[9] == '1') && (s[10] == '0' || s[10] == '1')) { *hash_on = (uint8_t)(s[8] - '0'); *anaout_on = (uint8_t)(s[9] - '0'); *check_on = (uint8_t)(s[10] - '0'); if (len == 11) { *payload_pos = 11; return 1; } if (len >= 12 && s[11] == ':') { *payload_pos = 12; return 1; } return -1; } return -1; } static int bridge_wait_until_end(uint32_t total_us) { const char *pat = ""; uint8_t st = 0; while (total_us--) { // FIFO -> PC while (s_rb_tail != s_rb_head) { char c = (char)s_rb_fifo[s_rb_tail]; s_rb_tail = (s_rb_tail + 1) % RS485_BRIDGE_FIFO_SZ; if (c == pat[st]) { st++; if (pat[st] == 0) return 1; // found } else { st = (c == pat[0]) ? 1 : 0; } } delay_us(1); } return 0; } /* ========================= * Print routing * ========================= */ typedef enum { CMD_SRC_PC = 0, CMD_SRC_RS485 = 1 } CmdSource; static void OUT_PRINT(CmdSource src, const char *s) { if (src == CMD_SRC_PC) { UART1_SendString_Safe(s); } else { /* RS485_PRINT ? ?( UART0 TX) */ RS485_PRINT(s); } } static void send_end_response(CmdSource src) { OUT_PRINT(src, "\r\n"); } /* ========================= * xNNv command * ========================= */ static int parse_x_v_cmd(const char *s, int len, uint8_t *addr) { if (len != 4) return 0; if (!(s[0] == 'x' || s[0] == 'X')) return 0; if (!isdigit((unsigned char)s[1]) || !isdigit((unsigned char)s[2])) return 0; if (!(s[3] == 'v' || s[3] == 'V')) return 0; *addr = (uint8_t)((s[1] - '0') * 10 + (s[2] - '0')); return 1; } static void send_n_response(uint8_t addr) { char resp[8]; resp[0] = 'N'; resp[1] = (char)('0' + (addr / 10)); resp[2] = (char)('0' + (addr % 10)); resp[3] = '\r'; resp[4] = '\n'; resp[5] = '\0'; OUT_PRINT(CMD_SRC_PC, resp); } static int parse_x_o_cmd(const char *s, int len, uint8_t *addr) { if (len != 4) return 0; if (!(s[0] == 'x' || s[0] == 'X')) return 0; if (!isdigit((unsigned char)s[1]) || !isdigit((unsigned char)s[2])) return 0; if (!(s[3] == 'o' || s[3] == 'O')) return 0; *addr = (uint8_t)((s[1]-'0')*10 + (s[2]-'0')); return 1; } /* OUT_PRINT Safe */ static void send_v_response(CmdSource src, uint8_t addr) { char resp[8]; resp[0] = 'V'; resp[1] = (char)('0' + (addr / 10)); resp[2] = (char)('0' + (addr % 10)); resp[3] = '\r'; resp[4] = '\n'; resp[5] = '\0'; if (src == CMD_SRC_RS485) { delay_us(1200); // 200~500us } OUT_PRINT(src, resp); } static void UART0_WaitTxDone_Flag(uint32_t guard_us) { while (!g_uart0_tx_done && guard_us--) { delay_us(1); } } static void RS485_FlushJunk(uint16_t loops, uint16_t step_us) { while (loops--) { RS485_Bridge_DrainToPC(); delay_us(step_us); } } static void PC_PrintLine_CRLF(const char *line) { char tmp[320]; size_t n = strlen(line); size_t i; // line '\n' , "\r\n" if (n > 0 && line[n-1] == '\n') { size_t m = 0; for (i=0; i= 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; } if (Is_V_Response_For(linebuf, addr)) { PC_PrintLine_CRLF(linebuf); g_rs485_bridge_active = 0; delay_us(500); return; } } total_wait_us -= 500U; } g_rs485_bridge_active = 0; delay_us(500); } send_n_response(addr); rs485_rx_done = 0; rs485_rx_index = 0; rs485_rx_length = 0; R_UART0_Receive((uint8_t*)&rs485_rx_buffer[0], 1); } /* ========================= * Build line from rx buffer * ========================= */ static int build_line_from_rx(const volatile uint8_t *rx_buf, int rx_len, char *out, int out_sz) { int i, idx = 0; if (rx_len < 0) rx_len = 0; if (rx_len > out_sz - 1) rx_len = out_sz - 1; for (i = 0; i < rx_len && idx < out_sz - 1; i++) { char c = (char)rx_buf[i]; if (c == '\r') continue; if (c == '\n') break; out[idx++] = c; } out[idx] = '\0'; return idx; } /* ========================= * Protocol detect * ========================= */ typedef enum { PROTOCOL_I2CT, PROTOCOL_OWIT, PROTOCOL_I2CW, PROTOCOL_I2CR, PROTOCOL_OWIW, PROTOCOL_OWIR, PROTOCOL_UNKNOWN } ProtocolType; static ProtocolType detect_protocol(char header1, char header2) { if (header1 == 'I' && header2 == 'W') return PROTOCOL_I2CW; if (header1 == 'I' && header2 == 'R') return PROTOCOL_I2CR; if (header1 == 'O' && header2 == 'W') return PROTOCOL_OWIW; if (header1 == 'O' && header2 == 'R') return PROTOCOL_OWIR; return PROTOCOL_UNKNOWN; } static void cmd_unknown(const unsigned char *d, unsigned int len) { (void)d; (void)len; OUT_PRINT(CMD_SRC_PC, "Unknown cmd\r\n"); delay(100000); } static void print_owi_write_result(CmdSource src, const app_owi_result_t *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"); } static void print_owi_read_result(CmdSource src, const app_owi_result_t *r) { char out[(2 * OWI_IO_MAX_BYTES) + 64]; uint16_t p = 0; uint16_t i; if (!r) { OUT_PRINT(src, "Err:owi_null\r\n"); return; } if (r->read_len == 0) { OUT_PRINT(src, "Err:read_len_nonzero\r\n"); return; } for (i = 0; i < r->read_len && i < OWI_IO_MAX_BYTES; i++) { uint8_t b = r->data[i]; out[p++] = "0123456789ABCDEF"[b >> 4]; out[p++] = "0123456789ABCDEF"[b & 0x0F]; } if (r->timeout) { p += (uint16_t)sprintf(&out[p], " !TO(B%u b%u)", (unsigned)r->timeout_byte_index, (unsigned)r->timeout_bit_index); } out[p++] = '\r'; out[p++] = '\n'; out[p] = '\0'; 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 run_connect_verify_one_channel(const app_job_t *job, uint8_t ch) { 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; uint8_t attempt; if (!job) return 0; if (ch < 1 || ch > 20) return 0; 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(); } /* prefix / gate */ if (job -> mode == 'C') { s_prefix_mode = PREFIX_CAL; Cal_Init(); }else{ s_prefix_mode = PREFIX_EOL; Eol_Init(); } /* ÇöÀç ä³Î¸¸ ¼±Åà */ Gate_SetByNum(ch, job->hash_on, job->anaout_on, job->check_on); GateCtrl_SelectChannel(ch); /* 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; } if (memcmp(r_read3.data, expected_tail, 3) == 0) { return 1; } } return 0; } static void print_connect_sweep_result(CmdSource src, uint8_t ch, uint8_t ok) { char msg[32]; sprintf(msg, "ch%u: %s\r\n", (unsigned)ch, ok ? "Success" : "Fail"); OUT_PRINT(src, msg); } static int execute_connect_verify_sequence(CmdSource src, const app_job_t *job) { uint8_t ch; uint8_t success_count = 0; 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; /* 000 À̸é 1~20 sweep */ if (job->channel == 0u) { for (ch = 1; ch <= 20; ch++) { uint8_t ok = (uint8_t)run_connect_verify_one_channel(job, ch); if (ok) { print_connect_sweep_result(src, ch, 1); success_count++; } } if (success_count == 0u) { OUT_PRINT(src, "Fail\r\n"); } send_end_response(src); return 1; } /* ´ÜÀÏ Ã¤³Î */ if (job->channel < 1 || job->channel > 20) { OUT_PRINT(src, "Err:ch_range\r\n"); send_end_response(src); return 1; } if (run_connect_verify_one_channel(job, job->channel)) { OUT_PRINT(src, "Success\r\n"); } else { OUT_PRINT(src, "Fail\r\n"); } send_end_response(src); 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; 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"); send_end_response(src); 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); //delay_us(30000); if (job->payload[0] == 0x2E && job->payload[1] == 0x00 && job->payload[2] == 0x1F) { read_len = 65; } else if (job->payload[0] == 0x22 && job->payload[1] == 0x00 && job->payload[2] == 0x3A) { read_len = 119; } else if (job->payload[0] == 0x26 && job->payload[1] == 0x00 && job->payload[2] == 0x3E) { read_len = 127; } else if (job->payload[0] == 0x0B && job->payload[1] == 0x04 && job->payload[2] == 0x06) { read_len = 23; } else { return 0; } r_write = app_owi_write_basic(0x28u, job->payload, 3); if (!r_write.ok || r_write.timeout) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } r_read = do_stable_owi_read(0x28u, read_len); if (!r_read.ok || r_read.timeout || r_read.read_len < read_len) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } print_owi_read_result(src, &r_read); send_end_response(src); 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; 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"); send_end_response(src); return 1; } if (job->channel < 1 || job->channel > 20) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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); //delay_us(30000); 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"); send_end_response(src); return 1; } /* 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"); send_end_response(src); return 1; } if (r_read1.data[0] != 0x23u) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } /* 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"); send_end_response(src); return 1; } delay_us(30000); /* 4) or28127 */ r_read2 = do_stable_owi_read(0x28u, 127u); if (!r_read2.ok || r_read2.timeout || r_read2.read_len < 127) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } /* NVM read ÀÀ´ä ù ¹ÙÀÌÆ®´Â 0x26 À̾î¾ß Á¤»ó */ if (r_read2.data[0] != 0x26u) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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"); } send_end_response(src); 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"); send_end_response(src); return 1; } if (job->channel < 1 || job->channel > 20) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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); //delay_us(30000); /* ¸¶Áö¸· 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"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); return 1; } if (r_read.data[0] != 0x44u) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } if (memcmp(&r_read.data[1], gui_crc, 2) != 0) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); return 1; } if (!(r_read.data[0] == 0x15u && r_read.data[1] == 0x00u && r_read.data[2] == 0x01u)) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); return 1; } if (!(r_read.data[0] == 0x14u && r_read.data[1] == 0x00u && r_read.data[2] == 0x01u)) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); return 1; } if (r_read.data[0] != 0x40u) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } if (memcmp(&r_read.data[1], gui_crc, 2) != 0) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); return 1; } if (r_read.data[0] != 0x42u) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } if (memcmp(&r_read.data[1], gui_crc, 2) != 0) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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"); send_end_response(src); 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"); send_end_response(src); return 1; } if (!(r_read.data[0] == 0x15u && r_read.data[1] == 0x00u && r_read.data[2] == 0x00u)) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); 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"); send_end_response(src); return 1; } /* 17) or28127 */ r_read = do_stable_owi_read(0x28u, 127u); if (!r_read.ok || r_read.timeout || r_read.read_len < 127) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } if (r_read.data[0] != 0x26u) { OUT_PRINT(src, "Fail\r\n"); send_end_response(src); return 1; } print_owi_read_result(src, &r_read); send_end_response(src); 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 direct read */ if (execute_direct_read_sequence(src, job)) { return 1; } /* write coefficient */ if (execute_write_coeff_sequence(src, job)) { return 1; } /* shadow_write -> 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"); send_end_response(src); 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); send_end_response(src); 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); send_end_response(src); return 1; } OUT_PRINT(src, "Err:job_exec\r\n"); send_end_response(src); return 1; } static void forward_line_rs485_and_bridge(const char *line) { static char txbuf[UART_RX_BUF_SIZE + 4]; uint32_t total_us; char linebuf[320]; int line_len = 0; 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); UART0_WaitTxDone_Flag(10000); rs485_set_tx(0); delay_us(500); total_us = BRIDGE_TOTAL_WAIT_US; line_len = 0; linebuf[0] = '\0'; while (total_us >= 50U) { 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; /* CR ¹«½Ã */ if (c == '\r') continue; /* line buffer ´©Àû */ 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; if (strstr(linebuf, "") != 0) { g_rs485_bridge_active = 0; return; } } 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; if (strstr(linebuf, "") != 0) { g_rs485_bridge_active = 0; return; } } line_len = 0; linebuf[0] = '\0'; } } delay_us(50); total_us -= 50U; } /* timeout ½Ã 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 (strstr(linebuf, "") != 0) { g_rs485_bridge_active = 0; return; } } } if (!got_any_line) { OUT_PRINT(CMD_SRC_PC, "Err:rs485_no_response\r\n"); rs485_abort_and_reset_pipeline(); return; } else { char dbg[128]; if (line_len > 0) { sprintf(dbg, "Err:rs485_no_end partial=%s\r\n", linebuf); } else { sprintf(dbg, "Err:rs485_no_end partial=\r\n"); } OUT_PRINT(CMD_SRC_PC, dbg); rs485_abort_and_reset_pipeline(); return; } } static int execute_owi_service_from_line(CmdSource src, const char *line) { uint8_t addr = 0, ch = 0; char mode = 0; uint8_t hash_on = 0, anaout_on = 0, check_on = 1; int payload_pos = 0; int len; ProtocolType proto; uint8_t id = 0; unsigned int byte_len = 0; int pos; uint8_t cmd[CMD_MAX]; unsigned int k; app_owi_result_t r; if (!line) return 0; len = (int)strlen(line); /* x-prefix ÆÄ½Ì */ if (parse_x_prefix(line, len, &addr, &ch, &mode, &hash_on, &anaout_on, &check_on, &payload_pos) != 1) { return 0; } /* ÀÚ±â ÁÖ¼Ò°¡ ¾Æ´Ï¸é ±âÁ¸ °æ·Î·Î ³Ñ±è */ if (addr != g_fixed_addr) { return 0; } if (ch < 1 || ch > 20) { OUT_PRINT(src, "Err:ch_range\r\n"); return 1; } /* prefix µ¿ÀÛ À¯Áö: ±âÁ¸ process_one_line_now()¿Í µ¿ÀÏÇÏ°Ô ¼±Çà */ if (mode == 'C') { s_prefix_mode = PREFIX_CAL; Cal_Init(); Gate_SetByNum(ch, hash_on, anaout_on, check_on); GateCtrl_SelectChannel(ch); } else { s_prefix_mode = PREFIX_EOL; Eol_Init(); Gate_SetByNum(ch, hash_on, anaout_on, check_on); GateCtrl_SelectChannel(ch); } if (payload_pos >= len) { if (mode == 'E') { OUT_PRINT(src, "XE51\r\n"); send_end_response(src); return 1; } else { OUT_PRINT(src, "Err:CAL_need_payload\r\n"); return 1; } } pos = payload_pos; { char h0, h1; h0 = (char)toupper((unsigned char)line[pos]); h1 = (char)toupper((unsigned char)line[pos + 1]); proto = detect_protocol(h0, h1); if (proto != PROTOCOL_OWIW && proto != PROTOCOL_OWIR) { return 0; /* I2C µîÀº ±âÁ¸ °æ·Î fallback */ } } pos += 2; if ((line[pos] == 't' || line[pos] == 'T') && proto == PROTOCOL_OWIW) { proto = PROTOCOL_OWIT; pos++; } if (line[pos] == '_' || line[pos] == ':') { pos++; } if (pos + 1 >= len) { OUT_PRINT(src, "Err:id_short\r\n"); return 1; } id = hex2byte(line[pos], line[pos + 1]); pos += 2; if (pos + 2 >= len || !(line[pos] >= '0' && line[pos] <= '9') || !(line[pos+1] >= '0' && line[pos+1] <= '9') || !(line[pos+2] >= '0' && line[pos+2] <= '9')) { OUT_PRINT(src, "Err:len_dec\r\n"); return 1; } byte_len = (unsigned int)(100 * (line[pos] - '0') + 10 * (line[pos+1] - '0') + (line[pos+2] - '0')); pos += 3; if (byte_len > CMD_MAX) { OUT_PRINT(src, "Err:len_range\r\n"); return 1; } if (proto == PROTOCOL_OWIT || proto == PROTOCOL_OWIW) { if (byte_len == 0) { OUT_PRINT(src, "Err:payload0\r\n"); return 1; } if ((int)(pos + (int)byte_len * 2) > len) { OUT_PRINT(src, "Err:len_mismatch\r\n"); return 1; } for (k = 0; k < byte_len; k++) { cmd[k] = hex2byte(line[pos + (int)(2 * k)], line[pos + (int)(2 * k + 1)]); } if (proto == PROTOCOL_OWIT) { r = app_owi_write_t_basic(id, cmd, (uint8_t)byte_len); } else { r = app_owi_write_basic(id, cmd, (uint8_t)byte_len); } print_owi_write_result(src, &r); return 1; } if (proto == PROTOCOL_OWIR) { if (byte_len == 0) { OUT_PRINT(src, "Err:read_len_nonzero\r\n"); return 1; } r = app_owi_read_basic(id, (int)byte_len); print_owi_read_result(src, &r); return 1; } return 0; } static void process_cmd(ProtocolType protocol, uint8_t id, const unsigned char *data, unsigned int len) { switch (protocol) { case PROTOCOL_I2CT: I2C_T_Command_Mode_receiveData(data, (uint8_t)len, id); break; case PROTOCOL_OWIT: OWI_T_CommandMode(data, (uint8_t)len, id); break; case PROTOCOL_I2CW: I2C_Command_Mode_receiveData(data, (uint8_t)len, id); break; case PROTOCOL_I2CR: I2C_Command_Mode_Send((uint8_t)len, id); break; case PROTOCOL_OWIW: OWI_CommandMode(data, (uint8_t)len, id); break; case PROTOCOL_OWIR: OWI_ReadBytesAndPrint(len, id); break; default: cmd_unknown(data, len); break; } } static void process_cmd_by_prefix(PrefixMode pm, ProtocolType protocol, uint8_t id, const unsigned char *data, unsigned int len) { (void)pm; process_cmd(protocol, id, data, len); } /* ========================= * Main line processor * ========================= */ static void process_one_line_now(CmdSource src, const char *input_line) { char line[UART_RX_BUF_SIZE]; uint8_t v_addr = 0; int is_v = 0; uint8_t a = 0; int i; int idx = 0; int pos = 2; ProtocolType proto; uint8_t id; unsigned int byte_len; uint8_t cmd[CMD_MAX]; unsigned int k = 0; char orig_line[UART_RX_BUF_SIZE]; int orig_len = 0; s_prefix_mode = PREFIX_NONE; if (!input_line) return; strncpy(line, input_line, sizeof(line) - 1); line[sizeof(line) - 1] = '\0'; idx = (int)strlen(line); if (idx <= 0) return; if (src == CMD_SRC_RS485) { if (!(line[0] == 'x' || line[0] == 'X')) return; // V/N/Err } /* ========================= * 1) xNNv (x-prefix ) * ========================= */ is_v = parse_x_v_cmd(line, idx, &v_addr); if (is_v) { if (v_addr > 31) { OUT_PRINT(src, "Err:addr_range\r\n"); return; } /* 0(addr=0) + PC x00v => 00~31 */ if (g_fixed_addr == 0 && src == CMD_SRC_PC && v_addr == 0) { send_v_response(CMD_SRC_PC, 0); /* 01~31 */ for (a = 1; a <= 31; a++) { scan_one_addr_rs485(a); } send_end_response(CMD_SRC_PC); return; } if (v_addr == g_fixed_addr) { send_v_response(src, g_fixed_addr); } 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; } /* ÀÚ±â ÁÖ¼Ò¸é ·ÎÄà OFF ó¸® */ if (off_addr == g_fixed_addr) { Cal_Init(); OUT_PRINT(src, "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; memcpy(orig_line, line, (size_t)orig_len); orig_line[orig_len] = '\0'; /* ========================= * 2) x-prefix * ========================= */ { uint8_t addr = 0; uint8_t ch = 0; char mode = 0; int payload_pos = 0; uint8_t hash_on = 0; uint8_t anaout_on = 0; uint8_t check_on = 1; 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; int r = parse_x_prefix(line, idx, &addr, &ch, &mode, &hash_on, &anaout_on, &check_on, &payload_pos); if (r == -1) { OUT_PRINT(src, "Err:X_prefix\r\n"); return; } if (r == 1) { if (addr > 31) { OUT_PRINT(src, "Err:addr_range\r\n"); return; } if (ch < 1 || ch > 20) { OUT_PRINT(src, "Err:ch_range\r\n"); 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') { s_prefix_mode = PREFIX_CAL; Cal_Init(); Gate_SetByNum(ch, hash_on, anaout_on, check_on); GateCtrl_SelectChannel(ch); } else { s_prefix_mode = PREFIX_EOL; Eol_Init(); Gate_SetByNum(ch, hash_on, anaout_on, check_on); GateCtrl_SelectChannel(ch); } /* prefix */ { int rem = idx - payload_pos; if (rem <= 0) { if (mode == 'E') { OUT_PRINT(src, "XE51\r\n"); send_end_response(src); return; } else { OUT_PRINT(src, "Err:CAL_need_payload\r\n"); return; } } if (mode == 'E') { OUT_PRINT(src, "Err:EOL_no_payload\r\n"); return; } for (i = 0; i < rem; i++) line[i] = line[payload_pos + i]; line[rem] = '\0'; idx = rem; pos = 2; } } } if (idx < 7) { OUT_PRINT(src, "Err:short\r\n"); return; } { char h0 = (char)toupper((unsigned char)line[0]); char h1 = (char)toupper((unsigned char)line[1]); proto = detect_protocol(h0, h1); } if (proto == PROTOCOL_UNKNOWN) { OUT_PRINT(src, "Err:ID\r\n"); return; } if (line[pos] == 't' || line[pos] == 'T') { if (proto == PROTOCOL_OWIW) proto = PROTOCOL_OWIT; else if (proto == PROTOCOL_I2CW) proto = PROTOCOL_I2CT; pos++; } if (line[pos] == '_' || line[pos] == ':') pos++; if (pos + 1 >= idx) { OUT_PRINT(src, "Err:id_short\r\n"); return; } id = hex2byte(line[pos], line[pos + 1]); pos += 2; if (pos + 2 >= idx || !(line[pos] >= '0' && line[pos] <= '9') || !(line[pos+1] >= '0' && line[pos+1] <= '9') || !(line[pos+2] >= '0' && line[pos+2] <= '9')) { OUT_PRINT(src, "Err:len_dec\r\n"); return; } byte_len = (unsigned int)(100*(line[pos]-'0') + 10*(line[pos+1]-'0') + (line[pos+2]-'0')); pos += 3; if (byte_len > CMD_MAX) { OUT_PRINT(src, "Err:len_range\r\n"); return; } if (proto == PROTOCOL_OWIT || proto == PROTOCOL_I2CT || proto == PROTOCOL_OWIW || proto == PROTOCOL_I2CW) { if (byte_len == 0) { OUT_PRINT(src, "Err:payload0\r\n"); return; } if ((int)(pos + (int)byte_len*2) > idx) { OUT_PRINT(src, "Err:len_mismatch\r\n"); return; } for (k = 0; k < byte_len; k++) { cmd[k] = hex2byte(line[pos + 2*k], line[pos + 2*k + 1]); } pos += (int)byte_len * 2; if (pos != idx) { OUT_PRINT(src, "Err:len_trail\r\n"); return; } } else if (proto == PROTOCOL_OWIR || proto == PROTOCOL_I2CR) { if (byte_len == 0) { OUT_PRINT(src, "Err:read_len_nonzero\r\n"); return; } if (pos != idx) { OUT_PRINT(src, "Err:read_no_payload\r\n"); return; } } process_cmd_by_prefix(s_prefix_mode, proto, id, cmd, byte_len); } static void process_one_line(CmdSource src, const volatile uint8_t *rx_buf, uint16_t rx_len) { char line[UART_RX_BUF_SIZE]; int idx; app_job_t job; app_cmd_src_t app_src; idx = build_line_from_rx(rx_buf, (int)rx_len, line, (int)sizeof(line)); 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 (!(line[0] == 'x' || line[0] == 'X')) return; } app_src = (src == CMD_SRC_PC) ? APP_CMD_SRC_PC : APP_CMD_SRC_RS485; if (!app_cmd_parse_line(app_src, line, &job)) { OUT_PRINT(src, "Err:parse\r\n"); return; } if (!app_scheduler_push(&job)) { OUT_PRINT(src, "Err:queue_full\r\n"); return; } } static void app_runtime_try_start(void) { if (g_app_runtime_job.active) return; if (app_scheduler_pop(&g_app_runtime_job.job)) { g_app_runtime_job.active = 1; g_app_runtime_job.scan_started = 0; g_app_runtime_job.current_scan_addr = 1; } } static void app_job_tick(void) { CmdSource src; uint8_t scan_addr; app_runtime_try_start(); if (!g_app_runtime_job.active) return; src = (g_app_runtime_job.job.src == APP_CMD_SRC_PC) ? CMD_SRC_PC : CMD_SRC_RS485; switch (g_app_runtime_job.job.type) { case APP_JOB_SCAN_ADDR: scan_addr = g_app_runtime_job.job.addr; if (scan_addr > 31) { OUT_PRINT(src, "Err:addr_range\r\n"); app_runtime_reset(); return; } /* ¸¶½ºÅÍ x00v */ if (g_fixed_addr == 0 && src == CMD_SRC_PC && scan_addr == 0) { if (!g_app_runtime_job.scan_started) { send_v_response(CMD_SRC_PC, 0); g_app_runtime_job.scan_started = 1; g_app_runtime_job.current_scan_addr = 1; return; } if (g_app_runtime_job.current_scan_addr <= 31) { scan_one_addr_rs485(g_app_runtime_job.current_scan_addr); g_app_runtime_job.current_scan_addr++; return; } send_end_response(CMD_SRC_PC); app_runtime_reset(); return; } /* ½½·¹À̺ê xNNv Á÷Á¢ ó¸® */ if (scan_addr == g_fixed_addr) { send_v_response(src, g_fixed_addr); } 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"); } 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; } /* ½½·¹À̺갡 RS485¿¡¼­ ¹ÞÀº ºñ´ë»ó ¸í·ÉÀº ¹«½Ã */ if (src == CMD_SRC_RS485) { app_runtime_reset(); return; } OUT_PRINT(src, "Err:job_exec\r\n"); app_runtime_reset(); return; case APP_JOB_FORWARD_LINE: case APP_JOB_LOCAL_EXEC: default: process_one_line_now(src, g_app_runtime_job.job.line); app_runtime_reset(); return; } } /* ========================= * Main loop handler * ========================= */ void handle_uart_command_line(void) { while (1) { if (g_rs485_need_recover) { g_rs485_bridge_active = 0; g_rs485_bridge_done = 0; RS485_Bridge_ResetFifo(); // static? ? /* RS485 RX */ rs485_rx_done = 0; rs485_rx_index = 0; rs485_rx_length = 0; /* UART0 stop/start + RX arm */ rs485_recover(); g_rs485_need_recover = 0; } if (g_rs485_bridge_active) { RS485_Bridge_DrainToPC(); } /* PC(UART1) */ if (uart_rx_done) { uart_rx_done = 0; process_one_line(CMD_SRC_PC, uart_rx_buffer, uart_rx_length); uart_rx_index = 0; uart_rx_length = 0; R_UART1_Receive((uint8_t *)&uart_rx_buffer[uart_rx_index], 1); } /* RS485(UART0) */ if (rs485_rx_done) { rs485_rx_done = 0; if (!g_rs485_bridge_active) { process_one_line(CMD_SRC_RS485, rs485_rx_buffer, rs485_rx_length); } rs485_rx_index = 0; rs485_rx_length = 0; R_UART0_Receive((uint8_t *)&rs485_rx_buffer[rs485_rx_index], 1); } else { } app_job_tick(); } } /* ========================= * Renesas entrypoints * ========================= */ void R_MAIN_UserInit(void); void main(void) { char b[64]; R_MAIN_UserInit(); R_UART0_Create(); /* UART0 : RS485 */ R_UART1_Create(); /* UART1 : PC */ R_IICA0_Create(); /* I2C */ R_UART0_Start(); R_UART1_Start(); app_scheduler_init(); app_runtime_reset(); sprintf(b, "BOOT addr=%u\r\n", g_fixed_addr); /* ? BOOT ¥ì */ UART1_SendString_Safe(b); RS485_PRINT(b); R_UART1_Receive((uint8_t *)&uart_rx_buffer[uart_rx_index], 1); R_UART0_Receive((uint8_t *)&rs485_rx_buffer[rs485_rx_index], 1); handle_uart_command_line(); while (1U) { ; } } void R_MAIN_UserInit(void) { /* Start user code. Do not edit comment generated here */ EI(); R_PORT_Create(); rs485_init(); DipSwitch_Init(); g_fixed_addr = DipSwitch_ReadAddr_0to31(); /* End user code. Do not edit comment generated here */ } /* End user code. Do not edit comment generated here */