Files
TCP2UART/Drivers/CH390/ch390_runtime.c
T

286 lines
7.5 KiB
C

#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) {
SEGGER_RTT_printf(0,
"CH390 bitbang VIDL=0x%02X VIDH=0x%02X PIDL=0x%02X PIDH=0x%02X CHIPR=0x%02X\r\n",
ch390_bitbang_read_reg(CH390_VIDL),
ch390_bitbang_read_reg(CH390_VIDH),
ch390_bitbang_read_reg(CH390_PIDL),
ch390_bitbang_read_reg(CH390_PIDH),
ch390_bitbang_read_reg(CH390_CHIPR));
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;
}