/**************************************************************************** Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT be copied by any method or incorporated into another program without the express written consent of Aerospace C.Power. This Information or any portion thereof remains the property of Aerospace C.Power. The Information contained herein is believed to be accurate and Aerospace C.Power assumes no responsibility or liability for its use in any way and conveys no license or title under any patent or copyright and makes no representation or warranty that this Information is free from patent or copyright infringement. ****************************************************************************/ /* os shim inlcude */ #include "os_utils_api.h" /* common inlcude */ #include "iot_config_api.h" #include "iot_ntoh_api.h" #include "iot_utils_api.h" #include "iot_uart_api.h" #include "iot_board_api.h" #include "iot_uart_eth_api.h" #include "iot_crc_api.h" #include "iot_oem_api.h" /* to resolve conflict with lwip internal definition. fortunately the value * is the same. */ #ifdef ERR_OK #undef ERR_OK #endif /* lwip internal includes */ #include "lwip/opt.h" #include "lwip/sys.h" #include "lwip/tcpip.h" #include "lwip/snmp.h" #include "lwip/dhcp.h" #include "lwip/etharp.h" #include "netif/netif_plc.h" #include "netif/netif_eth.h" #if IOT_LWIP_NETIF_UART_SUPPORT /* force open cli uart port for uart_link, set to 1 if the other ports are occupied. */ #define NETIF_UART_PORT_FORCE_CLI 0 #define netif_uart_printf iot_printf /* global data strcucture for uart network interface */ typedef struct _netif_uart_global { /* uart network interface descriptor */ struct netif netif; /* IPv4 configurations */ ip_addr_t ipaddr; ip_addr_t netmask; ip_addr_t gateway; /* uart port handler */ iot_uart_h uart_link; uart_eth_state_msg_t netif_plc_state; } netif_uart_global_t; static netif_uart_global_t *p_netif_uart = NULL; #if !IOT_LWIP_UART_OVER_ETH_SUPPORT static void netif_uart_rpt_to_stack(uint8_t *data, uint16_t len, uint8_t unicast) { struct pbuf *p; p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); if (p != NULL) { pbuf_take(p, data, len); pbuf_realloc(p, len); LINK_STATS_INC(link.recv); MIB2_STATS_NETIF_ADD(&p_netif_uart->netif, ifinoctets, p->len); if (unicast) { MIB2_STATS_NETIF_INC(&p_netif_uart->netif, ifinucastpkts); } else { MIB2_STATS_NETIF_INC(&p_netif_uart->netif, ifinnucastpkts); } /* deliver to upper stack */ p_netif_uart->netif.input(p, &p_netif_uart->netif); } else { /* drop packet */ LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); MIB2_STATS_NETIF_INC(&p_netif_uart->netif, ifindiscards); } } #endif #if (IOT_LWIP_NETIF_PLC_SUPPORT || PLC_SUPPORT_CCO_ROLE) static err_t netif_uart_send(struct netif *netif, struct pbuf *p) { (void)netif; (void)p; //IOT_ASSERT(0); return ERR_OK; } static err_t netif_uart_send_ip4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) { iot_pkt_t *pkt; uart_eth_header_t *header; if (!p_netif_uart->uart_link) { goto out; } if (ip4_addr_isbroadcast(ipaddr, netif) || ip4_addr_ismulticast(ipaddr)) { goto out; } pkt = iot_pkt_alloc(p->tot_len + UART_ETH_PREAMBLE_LEN + sizeof(*header) + UART_ETH_BACKEND_LEN, IOT_LWIP_MID); if (pkt) { /* add preamble code */ os_mem_cpy(iot_pkt_put(pkt, UART_ETH_PREAMBLE_LEN), UART_ETH_PREAMBLE_CODE, UART_ETH_PREAMBLE_LEN); /* add header */ header = (uart_eth_header_t *)iot_pkt_tail(pkt); header->type = UART_ETH_TYPE_P2P; header->len = p->tot_len; header->crc = iot_getcrc32_h16((uint8_t *)header, sizeof(*header) - 2); iot_pkt_put(pkt, sizeof(*header)); /* add data */ while (p) { os_mem_cpy(iot_pkt_tail(pkt), p->payload, p->len); iot_pkt_put(pkt, p->len); MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->len); p = p->next; } /* add backend code */ os_mem_cpy(iot_pkt_tail(pkt), UART_ETH_BACKEND_CODE, UART_ETH_BACKEND_LEN); iot_pkt_put(pkt, UART_ETH_BACKEND_LEN); /* send to uart link */ iot_uart_send(p_netif_uart->uart_link, pkt, NULL); LINK_STATS_INC(link.xmit); MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); } else { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); MIB2_STATS_NETIF_INC(netif, ifoutdiscards); } out: return ERR_OK; } #else #define netif_uart_send_ip4 etharp_output static err_t netif_uart_send(struct netif *netif, struct pbuf *p) { iot_pkt_t *pkt; uart_eth_header_t *header; if (!p_netif_uart->uart_link) { goto out; } pkt = iot_pkt_alloc(p->tot_len + UART_ETH_PREAMBLE_LEN + sizeof(*header) + UART_ETH_BACKEND_LEN, IOT_LWIP_MID); if (pkt) { /* add preamble code */ os_mem_cpy(iot_pkt_put(pkt, UART_ETH_PREAMBLE_LEN), UART_ETH_PREAMBLE_CODE, UART_ETH_PREAMBLE_LEN); /* add header */ header = (uart_eth_header_t *)iot_pkt_tail(pkt); header->type = UART_ETH_TYPE_P2P; header->len = p->tot_len; header->crc = iot_getcrc32_h16((uint8_t *)header, sizeof(*header) - 2); iot_pkt_put(pkt, sizeof(*header)); /* add data */ while (p) { os_mem_cpy(iot_pkt_tail(pkt), p->payload, p->len); iot_pkt_put(pkt, p->len); MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->len); p = p->next; } /* add backend code */ os_mem_cpy(iot_pkt_tail(pkt), UART_ETH_BACKEND_CODE, UART_ETH_BACKEND_LEN); iot_pkt_put(pkt, UART_ETH_BACKEND_LEN); /* send to uart link */ iot_uart_send(p_netif_uart->uart_link, pkt, NULL); LINK_STATS_INC(link.xmit); MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); } else { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); MIB2_STATS_NETIF_INC(netif, ifoutdiscards); } out: return ERR_OK; } #endif static err_t uartif_init(struct netif *netif) { uint8_t local_mac[IOT_MAC_ADDR_LEN] = {0x00, 0x01, 0x7f, 0x04, 0x05, 0x06}; netif->name[0] = 'u'; netif->name[1] = 'r'; netif->linkoutput = netif_uart_send; #if LWIP_IPV4 netif->output = netif_uart_send_ip4; #endif /* LWIP_IPV4 */ #if LWIP_IPV6 netif->output_ip6 = NULL; #endif /* LWIP_IPV6 */ netif->mtu = 4096; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_IGMP; netif->hwaddr_len = IOT_MAC_ADDR_LEN; iot_oem_get_module_mac(local_mac); iot_mac_addr_cpy(netif->hwaddr, local_mac); #if IOT_LWIP_UART_OVER_ETH_SUPPORT /* initialize dwc eth. */ netif_eth_set_mac_addr(netif->hwaddr); #endif #if (!IOT_LWIP_NETIF_PLC_SUPPORT) netif->flags |= NETIF_FLAG_ETHERNET | NETIF_FLAG_ETHARP; #endif iot_cus_printf("[%s][info] netif macaddr[%x:%x:%x:%x:%x:%x]\n", __FUNCTION__, netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]); NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 1000000); return ERR_OK; } static void netif_uart_status_callback(struct netif *state_netif) { if (netif_is_up(state_netif)) { #if LWIP_IPV4 netif_uart_printf("%s status_callback==UP, local interface IP is %s\n", __FUNCTION__, ip4addr_ntoa(netif_ip4_addr(state_netif))); #else netif_uart_printf("%s status_callback==UP\n", __FUNCTION__); #endif } else { netif_uart_printf("%s status_callback==DOWN\n", __FUNCTION__); } } static void netif_uart_link_callback(struct netif *state_netif) { if (netif_is_link_up(state_netif)) { netif_uart_printf("%s link_callback==UP\n", __FUNCTION__); } else { netif_uart_printf("%s link_callback==DOWN\n", __FUNCTION__); } } #if !IOT_LWIP_UART_OVER_ETH_SUPPORT static void netif_uart_recv_intern(void *ctx) { iot_pkt_t *pkt = ctx; netif_uart_rpt_to_stack(iot_pkt_data(pkt), (uint16_t)iot_pkt_data_len(pkt), 1); iot_pkt_free(pkt); } #endif static void netif_plc_report_uart_state() { iot_pkt_t *pkt; uart_eth_header_t *header; uart_eth_state_msg_t *msg; pkt = iot_pkt_alloc(UART_ETH_PREAMBLE_LEN + sizeof(*header) + sizeof(*msg) + UART_ETH_BACKEND_LEN, IOT_LWIP_MID); if (pkt) { /* add preamble code */ os_mem_cpy(iot_pkt_put(pkt, UART_ETH_PREAMBLE_LEN), UART_ETH_PREAMBLE_CODE, UART_ETH_PREAMBLE_LEN); /* add header */ header = (uart_eth_header_t *)iot_pkt_tail(pkt); header->type = UART_ETH_TYPE_STATE; header->len = sizeof(*msg); header->crc = iot_getcrc32_h16((uint8_t *)header, sizeof(*header) - 2); iot_pkt_put(pkt, sizeof(*header)); /* add message */ msg = (uart_eth_state_msg_t *)iot_pkt_tail(pkt); os_mem_cpy(msg, &(p_netif_uart->netif_plc_state), sizeof(uart_eth_state_msg_t)); iot_pkt_put(pkt, sizeof(*msg)); /* add backend code */ os_mem_cpy(iot_pkt_tail(pkt), UART_ETH_BACKEND_CODE, UART_ETH_BACKEND_LEN); iot_pkt_put(pkt, UART_ETH_BACKEND_LEN); /* send to uart link */ iot_uart_send(p_netif_uart->uart_link, pkt, NULL); } } static void netif_uart_recv(uint8_t *buffer, uint32_t buffer_len, bool_t is_full_frame, uint32_t invalid_data_len) { iot_pkt_t *pkt; uart_eth_header_t *header; struct eth_hdr *ethhdr; (void)invalid_data_len; if (is_full_frame) { /* skip preamble code */ buffer += UART_ETH_PREAMBLE_LEN; buffer_len -= UART_ETH_PREAMBLE_LEN; /* get header */ header = (uart_eth_header_t *)buffer; buffer += sizeof(*header); buffer_len -= sizeof(*header); /* validate length field again with backend code removed */ if (header->len > (buffer_len - UART_ETH_BACKEND_LEN)) return; /* check header crc */ if (iot_getcrc32_h16((uint8_t *)header, sizeof(*header) - 2) != header->crc) { return; } switch (header->type) { case UART_ETH_TYPE_P2P: { #if IOT_LWIP_UART_OVER_ETH_SUPPORT netif_uart_to_eth_send_by_data(buffer, header->len); #else /* report ip data to uart interface */ pkt = iot_pkt_alloc(header->len, IOT_LWIP_MID); os_mem_cpy(iot_pkt_put(pkt, header->len), buffer, header->len); tcpip_callback_with_block(netif_uart_recv_intern, pkt, 0); #endif break; } case UART_ETH_TYPE_PLC: { /* validate source mac address */ ethhdr = (struct eth_hdr *)buffer; if (!iot_mac_addr_cmp(ethhdr->src.addr, header->src_addr)) { break; } /* foward ethernet to plc link */ pkt = iot_pkt_alloc(header->len, IOT_LWIP_MID); os_mem_cpy(iot_pkt_put(pkt, header->len), buffer, header->len); tcpip_callback_with_block((tcpip_callback_fn)netif_uart_to_plc_send, pkt, 0); break; } case UART_ETH_TYPE_QUERY_STATE: { netif_plc_report_uart_state(); break; } default: break; } } } void netif_plc_to_uart_send_by_data(uint8_t *data, uint16_t len) { iot_pkt_t *pkt; uart_eth_header_t *header; if (!p_netif_uart) return; pkt = iot_pkt_alloc(len + UART_ETH_PREAMBLE_LEN + sizeof(*header) + UART_ETH_BACKEND_LEN, IOT_LWIP_MID); if (pkt) { /* add preamble code */ os_mem_cpy(iot_pkt_put(pkt, UART_ETH_PREAMBLE_LEN), UART_ETH_PREAMBLE_CODE, UART_ETH_PREAMBLE_LEN); /* add header */ header = (uart_eth_header_t *)iot_pkt_tail(pkt); header->type = UART_ETH_TYPE_PLC; header->len = len; header->crc = iot_getcrc32_h16((uint8_t *)header, sizeof(*header) - 2); iot_pkt_put(pkt, sizeof(*header)); /* add data */ os_mem_cpy(iot_pkt_tail(pkt), data, len); iot_pkt_put(pkt, len); /* add backend code */ os_mem_cpy(iot_pkt_tail(pkt), UART_ETH_BACKEND_CODE, UART_ETH_BACKEND_LEN); iot_pkt_put(pkt, UART_ETH_BACKEND_LEN); /* send to uart link */ iot_uart_send(p_netif_uart->uart_link, pkt, NULL); } } void netif_plc_to_uart_send_by_pbuf(struct pbuf *p) { iot_pkt_t *pkt; uart_eth_header_t *header; if (!p_netif_uart) return; pkt = iot_pkt_alloc(p->tot_len + UART_ETH_PREAMBLE_LEN + sizeof(*header) + UART_ETH_BACKEND_LEN, IOT_LWIP_MID); if (pkt) { /* add preamble code */ os_mem_cpy(iot_pkt_put(pkt, UART_ETH_PREAMBLE_LEN), UART_ETH_PREAMBLE_CODE, UART_ETH_PREAMBLE_LEN); /* add header */ header = (uart_eth_header_t *)iot_pkt_tail(pkt); header->type = UART_ETH_TYPE_PLC; header->len = p->tot_len; header->crc = iot_getcrc32_h16((uint8_t *)header, sizeof(*header) - 2); iot_pkt_put(pkt, sizeof(*header)); /* add data */ while (p) { os_mem_cpy(iot_pkt_tail(pkt), p->payload, p->len); iot_pkt_put(pkt, p->len); p = p->next; } /* add backend code */ os_mem_cpy(iot_pkt_tail(pkt), UART_ETH_BACKEND_CODE, UART_ETH_BACKEND_LEN); iot_pkt_put(pkt, UART_ETH_BACKEND_LEN); /* send to uart link */ iot_uart_send(p_netif_uart->uart_link, pkt, NULL); } } void netif_plc_to_uart_state_chg(uint8_t ready, ip_addr_t *ip, ip_addr_t *netmask, ip_addr_t *gateway, uint16_t mtu) { if (!p_netif_uart) return; p_netif_uart->netif_plc_state.ready = !!ready; if (ip && netmask && gateway) { p_netif_uart->netif_plc_state.ip_valid = 1; p_netif_uart->netif_plc_state.ip = ip_addr_get_ip4_u32(ip); p_netif_uart->netif_plc_state.netmask = ip_addr_get_ip4_u32(netmask); p_netif_uart->netif_plc_state.gateway = ip_addr_get_ip4_u32(gateway); } else { p_netif_uart->netif_plc_state.ip_valid = 0; } p_netif_uart->netif_plc_state.mtu = mtu; p_netif_uart->netif_plc_state.crc = iot_getcrc32_h16((uint8_t *)&(p_netif_uart->netif_plc_state), sizeof(p_netif_uart->netif_plc_state) - 2); netif_plc_report_uart_state(); } #if IOT_LWIP_UART_OVER_ETH_SUPPORT void netif_eth_to_uart_send_by_data(uint8_t * data, uint32_t len) { iot_pkt_t *pkt; uart_eth_header_t *header; pkt = iot_pkt_alloc(len + UART_ETH_PREAMBLE_LEN + sizeof(*header) + UART_ETH_BACKEND_LEN, IOT_LWIP_MID); if (pkt) { /* add preamble code */ os_mem_cpy(iot_pkt_put(pkt, UART_ETH_PREAMBLE_LEN), UART_ETH_PREAMBLE_CODE, UART_ETH_PREAMBLE_LEN); /* add header */ header = (uart_eth_header_t *)iot_pkt_tail(pkt); header->type = UART_ETH_TYPE_P2P; header->len = len; header->crc = iot_getcrc32_h16((uint8_t *)header, sizeof(*header) - 2); iot_pkt_put(pkt, sizeof(*header)); /* add data */ os_mem_cpy(iot_pkt_tail(pkt), data, len); iot_pkt_put(pkt, len); /* add backend code */ os_mem_cpy(iot_pkt_tail(pkt), UART_ETH_BACKEND_CODE, UART_ETH_BACKEND_LEN); iot_pkt_put(pkt, UART_ETH_BACKEND_LEN); /* send to uart link */ iot_uart_send(p_netif_uart->uart_link, pkt, NULL); } } #else void netif_eth_to_uart_send_by_data(uint8_t * data, uint32_t len) { (void)data; (void)len; } #endif void netif_uart_init() { iot_oem_base_cfg_t *cfg; iot_oem_get_base_cfg(&cfg); uint32_t module_type = cfg->module_type; if (module_type != MODULE_TYPE_CCO && !IOT_STA_CONTROL_MODE) { return; } iot_frame_fmt uart_fmt; if (p_netif_uart) return; p_netif_uart = os_mem_malloc(IOT_LWIP_MID, sizeof(*p_netif_uart)); IOT_ASSERT(p_netif_uart); /* ## + uart_eth_header_t + data + @@ */ os_mem_set(&uart_fmt, 0, sizeof(uart_fmt)); uart_fmt.preamble_codelen = UART_ETH_PREAMBLE_LEN; os_mem_cpy(uart_fmt.preamble_code, UART_ETH_PREAMBLE_CODE, UART_ETH_PREAMBLE_LEN); uart_fmt.backcode_len = UART_ETH_BACKEND_LEN; os_mem_cpy(uart_fmt.backcode, UART_ETH_BACKEND_CODE, UART_ETH_BACKEND_LEN); uart_fmt.datalen_offset = 8; uart_fmt.datalen_size = 2; /* set this value to 2 to skip the crc in the header */ uart_fmt.backcode_offset = 2; uart_fmt.frame_timeout = 10; #if (NETIF_UART_PORT_FORCE_CLI) p_netif_uart->uart_link = iot_uart_open(iot_board_get_uart(UART_CLI_PORT), netif_uart_recv, 2048, &uart_fmt); #else /* NETIF_UART_PORT_FORCE_CLI */ #if (IOT_STA_CONTROL_MODE == IOT_STA_CONTROL_TYPE_STA) p_netif_uart->uart_link = iot_uart_open(iot_board_get_uart(UART_METER_PORT), netif_uart_recv, 2048, &uart_fmt); #else /* (IOT_STA_CONTROL_MODE == IOT_STA_CONTROL_TYPE_STA) */ p_netif_uart->uart_link = iot_uart_open(iot_board_get_uart(UART_CLI_PORT), netif_uart_recv, 4096, &uart_fmt); #endif /* (IOT_STA_CONTROL_MODE == IOT_STA_CONTROL_TYPE_STA) */ #endif /* NETIF_UART_PORT_FORCE_CLI */ IOT_ASSERT(p_netif_uart->uart_link); os_mem_set(&(p_netif_uart->netif_plc_state), 0, sizeof(p_netif_uart->netif_plc_state)); p_netif_uart->netif_plc_state.crc = iot_getcrc32_h16((uint8_t *)&(p_netif_uart->netif_plc_state), sizeof(p_netif_uart->netif_plc_state) - 2); /* initialize uart interface IP. as uart is P2P link, so FW will use * 192.168.0.1 and host will use 192.168.0.2 as fixed IP. */ IP_ADDR4(&p_netif_uart->gateway, 0, 0, 0, 0); IP_ADDR4(&p_netif_uart->ipaddr, 192, 168, 0, 1); IP_ADDR4(&p_netif_uart->netmask, 255, 255, 255, 0); netif_add(&p_netif_uart->netif, ip_2_ip4(&p_netif_uart->ipaddr), ip_2_ip4(&p_netif_uart->netmask), ip_2_ip4(&p_netif_uart->gateway), NULL, uartif_init, tcpip_input); netif_set_status_callback(&p_netif_uart->netif, netif_uart_status_callback); netif_set_link_callback(&p_netif_uart->netif, netif_uart_link_callback); /* enable interface by default */ netif_set_up(&p_netif_uart->netif); netif_set_link_up(&p_netif_uart->netif); } #else /* IOT_LWIP_NETIF_UART_SUPPORT */ void netif_plc_to_uart_send_by_data(uint8_t *data, uint16_t len) { (void)data; (void)len; } void netif_plc_to_uart_send_by_pbuf(struct pbuf *p) { (void)p; } void netif_plc_to_uart_state_chg(uint8_t ready, ip_addr_t *ip) { (void)ready; (void)ip; } void netif_uart_init() { } #endif /* IOT_LWIP_NETIF_UART_SUPPORT */