/*********************************************************************************************************************** * 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 5000U // ? 3ms ? ? #define BRIDGE_TOTAL_WAIT_US 1290000U /* ========================= * 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; } 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); } /* ========================= * Prefix mode * ========================= */ typedef enum { PREFIX_NONE = 0, PREFIX_CAL, PREFIX_EOL } PrefixMode; static PrefixMode s_prefix_mode = PREFIX_NONE; 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; /* ========================= * 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[40]; 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 0) { int got = RS485_Bridge_ReadLine(linebuf, sizeof(linebuf), 1000); if (got && Is_V_Response_For(linebuf, addr)) { PC_PrintLine_CRLF(linebuf); g_rs485_bridge_active = 0; return; } if (total_wait_us >= 1000) total_wait_us -= 1000; else total_wait_us = 0; } } 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) { (void)r; 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) + 40]; 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); } 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"); 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; char msg[64]; 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); } 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; } /* 1) OFF */ if (off_addr == g_fixed_addr) { Cal_Init(); OUT_PRINT(src, "OFF\r\n"); send_end_response(src); //? 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; // 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 } } /* 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(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 */ } /* 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"); 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; 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_reset(void) { memset(&g_app_runtime_job, 0, sizeof(g_app_runtime_job)); } 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 on master(0) from PC ¸¸ ºÐÇÒ ½ÇÇà */ 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; } 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 (!execute_owi_service_from_line(src, g_app_runtime_job.job.line)) { /* service·Î ¸ø ó¸®ÇÏ¸é ±âÁ¸ °æ·Î·Î fallback */ process_one_line_now(src, g_app_runtime_job.job.line); } 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 */