diff --git a/Drivers/CH390/CH390.c b/Drivers/CH390/CH390.c index 1af31ac..766cee2 100644 --- a/Drivers/CH390/CH390.c +++ b/Drivers/CH390/CH390.c @@ -12,6 +12,25 @@ #include "CH390.h" #include "CH390_Interface.h" +#define CH390_EPCR_POLL_LIMIT 100000u + +static int ch390_wait_epcr_ready(void) +{ + uint32_t poll_count = CH390_EPCR_POLL_LIMIT; + + while ((ch390_read_reg(CH390_EPCR) & 0x01u) != 0u) + { + if (poll_count == 0u) + { + ch390_write_reg(CH390_EPCR, 0x00u); + return -1; + } + --poll_count; + } + + return 0; +} + void ch390_probe_rx_header(uint8_t *head) { if (head == 0) @@ -22,6 +41,46 @@ void ch390_probe_rx_header(uint8_t *head) ch390_read_mem(head, 4); } +int ch390_peek_packet(uint8_t *rx_status, uint16_t *rx_len) +{ + uint8_t nsr; + uint8_t header[4]; + uint16_t mrr; + + if (rx_status != 0) + { + *rx_status = 0u; + } + + if (rx_len != 0) + { + *rx_len = 0u; + } + + nsr = ch390_read_reg(CH390_NSR); + if ((nsr & NSR_RXRDY) == 0u) + { + return 0; + } + + mrr = (uint16_t)ch390_read_mrrl() | ((uint16_t)ch390_read_mrrh() << 8); + ch390_read_mem(header, 4); + ch390_write_reg(CH390_MRRL, (uint8_t)(mrr & 0xffu)); + ch390_write_reg(CH390_MRRH, (uint8_t)((mrr >> 8) & 0xffu)); + + if (rx_status != 0) + { + *rx_status = header[1]; + } + + if (rx_len != 0) + { + *rx_len = (uint16_t)header[2] | ((uint16_t)header[3] << 8); + } + + return 1; +} + /** * @name ch390_receive_packet * @brief Receive packet @@ -125,6 +184,16 @@ void ch390_drop_packet(uint16_t len) ch390_write_reg(CH390_MRRH, (mdr >> 8) & 0xff); } +void ch390_rx_reset(void) +{ + uint8_t rcr = ch390_read_reg(CH390_RCR); + + ch390_write_reg(CH390_RCR, (uint8_t)(rcr & (uint8_t)(~RCR_RXEN))); + ch390_write_reg(CH390_NSR, NSR_RXOV); + ch390_write_reg(CH390_ISR, (uint8_t)(ISR_ROS | ISR_ROO | ISR_PR)); + ch390_write_reg(CH390_RCR, (uint8_t)(rcr | RCR_RXEN)); +} + /** * @name ch390_read_phy * @brief Read PHY register @@ -135,7 +204,10 @@ uint16_t ch390_read_phy(uint8_t reg) ch390_write_reg(CH390_EPAR, CH390_PHY | reg); // Chose PHY, send read command ch390_write_reg(CH390_EPCR, EPCR_ERPRR | EPCR_EPOS); - while(ch390_read_reg(CH390_EPCR) & 0x01); + if (ch390_wait_epcr_ready() != 0) + { + return 0xFFFFu; + } // Clear read command ch390_write_reg(CH390_EPCR, 0x00); return (ch390_read_reg(CH390_EPDRH) << 8) | @@ -155,7 +227,10 @@ void ch390_write_phy(uint8_t reg, uint16_t value) ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte // Chose PHY, send write command ch390_write_reg(CH390_EPCR, 0x0A); - while(ch390_read_reg(CH390_EPCR) & 0x01); + if (ch390_wait_epcr_ready() != 0) + { + return; + } // Clear write command ch390_write_reg(CH390_EPCR, 0x00); } @@ -173,7 +248,10 @@ void ch390_write_eeprom(uint8_t reg, uint16_t value) ch390_write_reg(CH390_EPDRH, ((value >> 8) & 0xff)); // High byte // Chose EEPROM, send write command ch390_write_reg(CH390_EPCR, EPCR_ERPRW); - while(ch390_read_reg(CH390_EPCR) & 0x01); + if (ch390_wait_epcr_ready() != 0) + { + return; + } // Clear write command ch390_write_reg(CH390_EPCR, 0x00); } diff --git a/Drivers/CH390/CH390.h b/Drivers/CH390/CH390.h index 34a3ca8..61e3e0d 100644 --- a/Drivers/CH390/CH390.h +++ b/Drivers/CH390/CH390.h @@ -657,6 +657,21 @@ int ch390_runtime_link_up_from_status(const struct ch390_runtime_status *status) */ void ch390_probe_rx_header(uint8_t *head); +/** + * @name ch390_peek_packet + * @brief Peek current RX header without consuming the packet. + * @param rx_status - Output abnormal status while receiving packet + * @param rx_len - Output packet length from RX header + * @return 0: no packet pending 1: header sampled + */ +int ch390_peek_packet(uint8_t *rx_status, uint16_t *rx_len); + +/** + * @name ch390_rx_reset + * @brief Repair RX datapath after overflow/corruption without full chip reset. + */ +void ch390_rx_reset(void); + /** * @name ch390_runtime_receive_packet * @brief Runtime RX entry point for packet receive