#include "ch390_runtime.h" #include "CH390.h" #include "CH390_Interface.h" #include "SEGGER_RTT.h" #include "ethernetif.h" #include "stm32f1xx_hal.h" #include "lwip/etharp.h" #include "lwip/pbuf.h" #include "lwip/stats.h" static volatile uint8_t g_ch390_irq_pending; static uint8_t g_ch390_ready; static ch390_diag_t g_diag; static uint8_t ch390_runtime_probe_identity(void) { g_diag.vendor_id = ch390_get_vendor_id(); g_diag.product_id = ch390_get_product_id(); g_diag.revision = ch390_get_revision(); g_diag.nsr = ch390_read_reg(CH390_NSR); g_diag.ncr = ch390_read_reg(CH390_NCR); g_diag.rcr = ch390_read_reg(CH390_RCR); g_diag.imr = ch390_read_reg(CH390_IMR); g_diag.intcr = ch390_read_reg(CH390_INTCR); g_diag.gpr = ch390_read_reg(CH390_GPR); g_diag.isr = ch390_read_reg(CH390_ISR); g_diag.link_up = (uint8_t)0u; g_diag.id_valid = (uint8_t)((g_diag.vendor_id != 0x0000u) && (g_diag.vendor_id != 0xFFFFu) && (g_diag.product_id != 0x0000u) && (g_diag.product_id != 0xFFFFu)); return g_diag.id_valid; } static void ch390_runtime_refresh_diag(void) { uint8_t id_valid = ch390_runtime_probe_identity(); if (id_valid != 0u) { g_diag.link_up = (uint8_t)ch390_get_link_status(); } } static struct pbuf *ch390_runtime_input(struct netif *netif) { struct ethernetif *ethernetif = (struct ethernetif *)netif->state; struct pbuf *p = NULL; struct pbuf *q; uint16_t len; uint8_t rcr; uint8_t rx_ready; uint8_t rx_header[4]; ch390_read_reg(CH390_MRCMDX); rx_ready = ch390_read_reg(CH390_MRCMDX); if (rx_ready & CH390_PKT_ERR) { rcr = ch390_read_reg(CH390_RCR); ch390_write_reg(CH390_RCR, (uint8_t)(rcr & (uint8_t)(~RCR_RXEN))); ch390_write_reg(CH390_MPTRCR, 0x01u); ch390_write_reg(CH390_MRRH, 0x0Cu); ch390_delay_us(1000u); ch390_write_reg(CH390_RCR, rcr); ethernetif->rx_len = 0u; LINK_STATS_INC(link.drop); return NULL; } if ((rx_ready & CH390_PKT_RDY) == 0u) { ethernetif->rx_len = 0u; return NULL; } ch390_read_mem(rx_header, 4); ethernetif->rx_status = rx_header[1]; ethernetif->rx_len = (uint16_t)(((uint16_t)rx_header[2] | ((uint16_t)rx_header[3] << 8)) - 4u); if ((ethernetif->rx_status & 0x3Fu) != 0u || ethernetif->rx_len == 0u || ethernetif->rx_len > 1520u) { ch390_drop_packet((uint16_t)(ethernetif->rx_len + 4u)); LINK_STATS_INC(link.drop); return NULL; } len = ethernetif->rx_len; #if ETH_PAD_SIZE len += ETH_PAD_SIZE; #endif p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { #if ETH_PAD_SIZE pbuf_remove_header(p, ETH_PAD_SIZE); #endif for (q = p; q != NULL; q = q->next) { ch390_read_mem((uint8_t *)q->payload, q->len); } #if ETH_PAD_SIZE pbuf_add_header(p, ETH_PAD_SIZE); #endif ch390_drop_packet(4u); LINK_STATS_INC(link.recv); } else { ch390_drop_packet((uint16_t)(ethernetif->rx_len + 4u)); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } return p; } void ch390_runtime_init(struct netif *netif, const uint8_t *mac) { struct ethernetif *ethernetif = (struct ethernetif *)netif->state; SEGGER_RTT_WriteString(0, "ETH init: gpio\r\n"); ch390_gpio_init(); SEGGER_RTT_WriteString(0, "ETH init: spi\r\n"); ch390_spi_init(); SEGGER_RTT_WriteString(0, "ETH init: reset\r\n"); ch390_hardware_reset(); SEGGER_RTT_WriteString(0, "ETH init: probe\r\n"); g_ch390_ready = ch390_runtime_probe_identity(); if (g_ch390_ready == 0u) { netif->hwaddr_len = ETHARP_HWADDR_LEN; netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; ethernetif->rx_len = 0u; ethernetif->rx_status = 0u; netif_set_link_down(netif); SEGGER_RTT_WriteString(0, "ETH init: invalid chip id\r\n"); return; } SEGGER_RTT_WriteString(0, "ETH init: default\r\n"); ch390_default_config(); SEGGER_RTT_WriteString(0, "ETH init: mac\r\n"); ch390_set_mac_address((uint8_t *)mac); netif->hwaddr_len = ETHARP_HWADDR_LEN; SEGGER_RTT_WriteString(0, "ETH init: getmac\r\n"); ch390_get_mac(netif->hwaddr); netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; ethernetif->rx_len = 0u; ethernetif->rx_status = 0u; ch390_runtime_refresh_diag(); g_ch390_ready = g_diag.id_valid; SEGGER_RTT_WriteString(0, "ETH init: irq\r\n"); ch390_interrupt_init(); SEGGER_RTT_WriteString(0, "ETH init: done\r\n"); } void ch390_runtime_set_irq_pending(void) { g_ch390_irq_pending = 1u; } void ch390_runtime_poll(struct netif *netif) { uint8_t int_status; if (!g_ch390_ready) { return; } if (g_ch390_irq_pending == 0u) { return; } g_ch390_irq_pending = 0u; int_status = ch390_read_reg(CH390_ISR); ch390_write_reg(CH390_ISR, int_status); if ((int_status & ISR_LNKCHG) != 0u) { HAL_Delay(65u); ch390_runtime_check_link(netif); } if ((int_status & ISR_ROS) != 0u) { LINK_STATS_INC(link.err); } if ((int_status & ISR_PR) != 0u) { uint8_t loops = 0u; while (loops++ < 8u) { struct pbuf *p = ch390_runtime_input(netif); if (p == NULL) { break; } if (netif->input(p, netif) != ERR_OK) { pbuf_free(p); } } } } void ch390_runtime_check_link(struct netif *netif) { uint8_t link_up; if (!g_ch390_ready) { netif_set_link_down(netif); return; } link_up = (uint8_t)ch390_get_link_status(); if (link_up) { if (!netif_is_link_up(netif)) { netif_set_link_up(netif); } } else if (netif_is_link_up(netif)) { netif_set_link_down(netif); } } err_t ch390_runtime_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; uint32_t start_tick; LWIP_UNUSED_ARG(netif); if (!g_ch390_ready) { LINK_STATS_INC(link.drop); return ERR_IF; } #if ETH_PAD_SIZE pbuf_remove_header(p, ETH_PAD_SIZE); #endif start_tick = HAL_GetTick(); while (ch390_read_reg(CH390_TCR) & TCR_TXREQ) { if ((HAL_GetTick() - start_tick) > 10u) { #if ETH_PAD_SIZE pbuf_add_header(p, ETH_PAD_SIZE); #endif LINK_STATS_INC(link.drop); return ERR_TIMEOUT; } } for (q = p; q != NULL; q = q->next) { ch390_write_mem((uint8_t *)q->payload, q->len); } ch390_write_reg(CH390_TXPLL, p->tot_len & 0xFFu); ch390_write_reg(CH390_TXPLH, (p->tot_len >> 8) & 0xFFu); ch390_send_request(); #if ETH_PAD_SIZE pbuf_add_header(p, ETH_PAD_SIZE); #endif LINK_STATS_INC(link.xmit); return ERR_OK; } void ch390_runtime_get_diag(ch390_diag_t *diag) { if (diag != NULL) { ch390_runtime_refresh_diag(); *diag = g_diag; } } bool ch390_runtime_is_ready(void) { return g_ch390_ready != 0u; }