From 090160485498a92fdf896ad74ffd97f768a4a269 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 12 Jul 2021 21:21:03 +0200 Subject: [PATCH] added STM32H7 files --- CMakeLists.txt | 4 + stm32h7/CMakeLists.txt | 5 + stm32h7/STM32TestTask.cpp | 19 + stm32h7/STM32TestTask.h | 19 + stm32h7/networking/CMakeLists.txt | 7 + stm32h7/networking/TmTcLwIpUdpBridge.cpp | 204 +++++++ stm32h7/networking/TmTcLwIpUdpBridge.h | 79 +++ stm32h7/networking/UdpTcLwIpPollingTask.cpp | 61 ++ stm32h7/networking/UdpTcLwIpPollingTask.h | 38 ++ stm32h7/networking/app_dhcp.c | 155 +++++ stm32h7/networking/app_dhcp.h | 34 ++ stm32h7/networking/app_ethernet.c | 100 ++++ stm32h7/networking/app_ethernet.h | 76 +++ stm32h7/networking/ethernetif.c | 621 ++++++++++++++++++++ stm32h7/networking/ethernetif.h | 77 +++ stm32h7/networking/udp_config.h | 39 ++ 16 files changed, 1538 insertions(+) create mode 100644 stm32h7/CMakeLists.txt create mode 100644 stm32h7/STM32TestTask.cpp create mode 100644 stm32h7/STM32TestTask.h create mode 100644 stm32h7/networking/CMakeLists.txt create mode 100644 stm32h7/networking/TmTcLwIpUdpBridge.cpp create mode 100644 stm32h7/networking/TmTcLwIpUdpBridge.h create mode 100644 stm32h7/networking/UdpTcLwIpPollingTask.cpp create mode 100644 stm32h7/networking/UdpTcLwIpPollingTask.h create mode 100644 stm32h7/networking/app_dhcp.c create mode 100644 stm32h7/networking/app_dhcp.h create mode 100644 stm32h7/networking/app_ethernet.c create mode 100644 stm32h7/networking/app_ethernet.h create mode 100644 stm32h7/networking/ethernetif.c create mode 100644 stm32h7/networking/ethernetif.h create mode 100644 stm32h7/networking/udp_config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aadc39c..e0ee249 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,3 +6,7 @@ add_subdirectory(utility) target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ) + +if(TGT_BSP MATCHES "arm/stm32h743zi-nucleo") + add_subdirectory(stm32h7) +endif() diff --git a/stm32h7/CMakeLists.txt b/stm32h7/CMakeLists.txt new file mode 100644 index 0000000..43a0b7c --- /dev/null +++ b/stm32h7/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${TARGET_NAME} PRIVATE + STM32TestTask.cpp +) + +add_subdirectory(networking) \ No newline at end of file diff --git a/stm32h7/STM32TestTask.cpp b/stm32h7/STM32TestTask.cpp new file mode 100644 index 0000000..9d70e3c --- /dev/null +++ b/stm32h7/STM32TestTask.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +STM32TestTask::STM32TestTask(object_id_t objectId, bool enablePrintout, + bool blinkyLed): TestTask(objectId, enablePrintout), + blinkyLed(blinkyLed) { +} + +ReturnValue_t STM32TestTask::performPeriodicAction() { + if(blinkyLed) { +#if OBSW_ETHERNET_USE_LEDS == 0 + BSP_LED_Toggle(LED1); + BSP_LED_Toggle(LED2); +#endif + BSP_LED_Toggle(LED3); + } + return TestTask::performPeriodicAction(); +} diff --git a/stm32h7/STM32TestTask.h b/stm32h7/STM32TestTask.h new file mode 100644 index 0000000..260170d --- /dev/null +++ b/stm32h7/STM32TestTask.h @@ -0,0 +1,19 @@ +#ifndef BSP_STM32_BOARDTEST_STM32TESTTASK_H_ +#define BSP_STM32_BOARDTEST_STM32TESTTASK_H_ + +#include + +class STM32TestTask: public TestTask { +public: + STM32TestTask(object_id_t objectId, bool enablePrintout, bool blinkyLed = true); + + ReturnValue_t performPeriodicAction() override; +private: + + bool blinkyLed = false; + +}; + + + +#endif /* BSP_STM32_BOARDTEST_STM32TESTTASK_H_ */ diff --git a/stm32h7/networking/CMakeLists.txt b/stm32h7/networking/CMakeLists.txt new file mode 100644 index 0000000..9e7138a --- /dev/null +++ b/stm32h7/networking/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${TARGET_NAME} PRIVATE + app_dhcp.c + app_ethernet.c + ethernetif.c + UdpTcLwIpPollingTask.cpp + TmTcLwIpUdpBridge.cpp +) diff --git a/stm32h7/networking/TmTcLwIpUdpBridge.cpp b/stm32h7/networking/TmTcLwIpUdpBridge.cpp new file mode 100644 index 0000000..5404f3c --- /dev/null +++ b/stm32h7/networking/TmTcLwIpUdpBridge.cpp @@ -0,0 +1,204 @@ +#include "TmTcLwIpUdpBridge.h" +#include "udp_config.h" +#include "app_ethernet.h" +#include "ethernetif.h" +#include + +#include +#include +#include + + +TmTcLwIpUdpBridge::TmTcLwIpUdpBridge(object_id_t objectId, + object_id_t ccsdsPacketDistributor, object_id_t tmStoreId, + object_id_t tcStoreId): + TmTcBridge(objectId, ccsdsPacketDistributor, tmStoreId, tcStoreId) { + TmTcLwIpUdpBridge::lastAdd.addr = IPADDR_TYPE_ANY; +} + +TmTcLwIpUdpBridge::~TmTcLwIpUdpBridge() {} + +ReturnValue_t TmTcLwIpUdpBridge::initialize() { + TmTcBridge::initialize(); + bridgeLock = MutexFactory::instance()->createMutex(); + if(bridgeLock == nullptr) { + return ObjectManagerIF::CHILD_INIT_FAILED; + } + ReturnValue_t result = udp_server_init(); + return result; +} + +ReturnValue_t TmTcLwIpUdpBridge::udp_server_init(void) { + err_t err; + /* Create a new UDP control block */ + TmTcLwIpUdpBridge::upcb = udp_new(); + if (TmTcLwIpUdpBridge::upcb) + { + /* Bind the upcb to the UDP_PORT port */ + /* Using IP_ADDR_ANY allow the upcb to be used by any local interface */ + err = udp_bind(TmTcLwIpUdpBridge::upcb, IP_ADDR_ANY, UDP_SERVER_PORT); + + if(err == ERR_OK) + { + /* Set a receive callback for the upcb */ + udp_recv(TmTcLwIpUdpBridge::upcb, &udp_server_receive_callback, + (void*) this); + return RETURN_OK; + } + else + { + udp_remove(TmTcLwIpUdpBridge::upcb); + return RETURN_FAILED; + } + } else { + return RETURN_FAILED; + } +} + +ReturnValue_t TmTcLwIpUdpBridge::performOperation(uint8_t operationCode) { + TmTcBridge::performOperation(); + +#if TCPIP_RECV_WIRETAPPING == 1 + if(connectFlag) { + uint32_t ipAddress = ((ip4_addr*) &lastAdd)->addr; + int ipAddress1 = (ipAddress & 0xFF000000) >> 24; + int ipAddress2 = (ipAddress & 0xFF0000) >> 16; + int ipAddress3 = (ipAddress & 0xFF00) >> 8; + int ipAddress4 = ipAddress & 0xFF; +#if OBSW_VERBOSE_LEVEL == 1 +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "TmTcLwIpUdpBridge: Client IP Address " << std::dec + << ipAddress4 << "." << ipAddress3 << "." << ipAddress2 << "." + << ipAddress1 << std::endl; + uint16_t portSwapped = EndianConverter::convertBigEndian(lastPort); + sif::info << "TmTcLwIpUdpBridge: Client IP Port " + << (int)portSwapped << std::endl; +#else + sif::printInfo("TmTcLwIpUdpBridge: Client IP Address %d.%d.%d.%d\n", + ipAddress4, ipAddress3, ipAddress2, ipAddress1); + uint16_t portSwapped = EndianConverter::convertBigEndian(lastPort); + sif::printInfo("TmTcLwIpUdpBridge: Client IP Port: %d\n", portSwapped); +#endif +#endif + connectFlag = false; + } +#endif + + return RETURN_OK; +} + +ReturnValue_t TmTcLwIpUdpBridge::sendTm(const uint8_t * data, size_t dataLen) { + struct pbuf *p_tx = pbuf_alloc(PBUF_TRANSPORT, dataLen, PBUF_RAM); + if ((p_tx != nullptr) && (lastAdd.addr != IPADDR_TYPE_ANY) && (upcb != nullptr)) { + /* copy data to pbuf */ + err_t err = pbuf_take(p_tx, (char*) data, dataLen); + if(err!=ERR_OK){ + pbuf_free(p_tx); + return err; + } + /* Connect to the remote client */ + err = udp_connect(TmTcLwIpUdpBridge::upcb, &lastAdd , lastPort); + if(err != ERR_OK){ + pbuf_free(p_tx); + return err; + } + /* Tell the client that we have accepted it */ + err = udp_send(TmTcLwIpUdpBridge::upcb, p_tx); + pbuf_free(p_tx); + if(err!=ERR_OK){ + return err; + } + + /* free the UDP connection, so we can accept new clients */ + udp_disconnect (TmTcLwIpUdpBridge::upcb); + } + else{ + return RETURN_FAILED; + } + return RETURN_OK; +} + + +void TmTcLwIpUdpBridge::udp_server_receive_callback(void* arg, + struct udp_pcb* upcb_, struct pbuf* p, const ip_addr_t* addr, + u16_t port) { + struct pbuf *p_tx = nullptr; + auto udpBridge = reinterpret_cast(arg); + if(udpBridge == nullptr) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TmTcLwIpUdpBridge::udp_server_receive_callback: Invalid UDP bridge!" << + std::endl; +#else + sif::printWarning("TmTcLwIpUdpBridge::udp_server_receive_callback: Invalid UDP bridge!\n"); +#endif + } + /* allocate pbuf from RAM*/ + p_tx = pbuf_alloc(PBUF_TRANSPORT,p->len, PBUF_RAM); + + if(p_tx != NULL) + { + if(udpBridge != nullptr) { + MutexGuard lg(udpBridge->bridgeLock); + udpBridge->upcb = upcb_; + udpBridge->lastAdd = *addr; + udpBridge->lastPort = port; + if(not udpBridge->comLinkUp()) { + udpBridge->registerCommConnect(); +#if TCPIP_RECV_WIRETAPPING == 1 + udpBridge->connectFlag = true; +#endif + /* This should have already been done, but we will still do it */ + udpBridge->physicalConnectStatusChange(true); + } + } + pbuf_take(p_tx, (char*)p->payload, p->len); + /* send the received data to the uart port */ + char* data = reinterpret_cast(p_tx->payload); + *(data+p_tx->len) = '\0'; + +#if TCPIP_RECV_WIRETAPPING == 1 + udpBridge->printData(p,data); +#endif + + store_address_t storeId; + ReturnValue_t returnValue = udpBridge->tcStore->addData(&storeId, + reinterpret_cast(p->payload), p->len); + if (returnValue != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "UDP Server: Data storage failed" << std::endl; +#endif + pbuf_free(p_tx); + return; + } + TmTcMessage message(storeId); + if (udpBridge->tmTcReceptionQueue->sendToDefault(&message) + != RETURN_OK) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "TmTcLwIpUdpBridgw::udp_server_receive_callback:" + << " Sending message to queue failed" << std::endl; +#endif + udpBridge->tcStore->deleteData(storeId); + } + } + /* Free the p_tx buffer */ + pbuf_free(p_tx); +} + +/* Caller must ensure thread-safety */ +bool TmTcLwIpUdpBridge::comLinkUp() const { + return communicationLinkUp; +} + +/* Caller must ensure thread-safety */ +void TmTcLwIpUdpBridge::physicalConnectStatusChange(bool connect) { + if(connect) { + /* Physical connection does not mean there is a recipient to send packets too. + This will be done by the receive callback! */ + physicalConnection = true; + } + else { + physicalConnection = false; + /* If there is no physical connection, we can't send anything back */ + registerCommDisconnect(); + } +} diff --git a/stm32h7/networking/TmTcLwIpUdpBridge.h b/stm32h7/networking/TmTcLwIpUdpBridge.h new file mode 100644 index 0000000..fb2f5d5 --- /dev/null +++ b/stm32h7/networking/TmTcLwIpUdpBridge.h @@ -0,0 +1,79 @@ +#ifndef BSP_STM32_RTEMS_NETWORKING_TMTCUDPBRIDGE_H_ +#define BSP_STM32_RTEMS_NETWORKING_TMTCUDPBRIDGE_H_ + +#include + +#include +#include + +#define TCPIP_RECV_WIRETAPPING 0 + +/** + * This bridge is used to forward TMTC packets received via LwIP UDP to the internal software bus. + */ +class TmTcLwIpUdpBridge : public TmTcBridge { + friend class UdpTcLwIpPollingTask; +public: + TmTcLwIpUdpBridge(object_id_t objectId, + object_id_t ccsdsPacketDistributor, object_id_t tmStoreId, + object_id_t tcStoreId); + virtual ~TmTcLwIpUdpBridge(); + + virtual ReturnValue_t initialize() override; + ReturnValue_t udp_server_init(); + + /** + * In addition to default implementation, ethernet link status is checked. + * @param operationCode + * @return + */ + virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; + + /** TM Send implementation uses udp_send function from lwIP stack + * @param data + * @param dataLen + * @return + */ + virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; + + /** + * @brief This function is called when an UDP datagram has been + * received on the port UDP_PORT. + * @param arg + * @param upcb_ + * @param p + * @param addr Source address which will be bound to TmTcUdpBridge::lastAdd + * @param port + */ + static void udp_server_receive_callback(void *arg, + struct udp_pcb *upcb_, struct pbuf *p, const ip_addr_t *addr, + u16_t port); + + /** + * Check whether the communication link is up. + * Caller must ensure thread-safety by using the bridge lock. + * @return + */ + bool comLinkUp() const; + +private: + struct udp_pcb *upcb = nullptr; + ip_addr_t lastAdd; + u16_t lastPort = 0; + bool physicalConnection = false; + MutexIF* bridgeLock = nullptr; + +#if TCPIP_RECV_WIRETAPPING == 1 + bool connectFlag = false; +#endif + + /** + * Used to notify bridge about change in the physical ethernet connection. + * Connection does not mean that replies are possible (recipient not set yet), but + * disconnect means that we can't send anything. Caller must ensure thread-safety + * by using the bridge lock. + */ + void physicalConnectStatusChange(bool connect); +}; + +#endif /* BSP_STM32_RTEMS_NETWORKING_TMTCUDPBRIDGE_H_ */ diff --git a/stm32h7/networking/UdpTcLwIpPollingTask.cpp b/stm32h7/networking/UdpTcLwIpPollingTask.cpp new file mode 100644 index 0000000..4972976 --- /dev/null +++ b/stm32h7/networking/UdpTcLwIpPollingTask.cpp @@ -0,0 +1,61 @@ +#include "UdpTcLwIpPollingTask.h" +#include "TmTcLwIpUdpBridge.h" +#include "app_ethernet.h" +#include "ethernetif.h" +#include "app_dhcp.h" +#include + +#include +#include + +#include + +UdpTcLwIpPollingTask::UdpTcLwIpPollingTask(object_id_t objectId, object_id_t bridgeId): + SystemObject(objectId), periodicHandleCounter(0), bridgeId(bridgeId) { +} + +UdpTcLwIpPollingTask::~UdpTcLwIpPollingTask() { +} + +ReturnValue_t UdpTcLwIpPollingTask::initialize() { + udpBridge = objectManager->get(bridgeId); + if(udpBridge == nullptr) { + return ObjectManagerIF::CHILD_INIT_FAILED; + } + if (netif_is_link_up(&gnetif)) { + set_eth_cable_connected(true); + } + return RETURN_OK; +} + + +/* Poll the EMAC Interface and pass content to the network interface (lwIP) */ +ReturnValue_t UdpTcLwIpPollingTask::performOperation(uint8_t operationCode) { + /* Read a received packet from the Ethernet buffers and send it + to the lwIP for handling */ + ethernetif_input(&gnetif); + + /* Handle timeouts */ + sys_check_timeouts(); + +#if LWIP_NETIF_LINK_CALLBACK == 1 + ethernet_link_periodic_handle(&gnetif); +#endif + + if(udpBridge != nullptr) { + MutexGuard lg(udpBridge->bridgeLock); + /* In case ethernet cable is disconnected */ + if(not get_eth_cable_connected() and udpBridge->comLinkUp()) { + udpBridge->physicalConnectStatusChange(false); + } + else if(get_eth_cable_connected() and not udpBridge->comLinkUp()) { + udpBridge->physicalConnectStatusChange(true); + } + } + +#if LWIP_DHCP == 1 + DHCP_Periodic_Handle(&gnetif); +#endif + + return RETURN_OK; +} diff --git a/stm32h7/networking/UdpTcLwIpPollingTask.h b/stm32h7/networking/UdpTcLwIpPollingTask.h new file mode 100644 index 0000000..9262399 --- /dev/null +++ b/stm32h7/networking/UdpTcLwIpPollingTask.h @@ -0,0 +1,38 @@ +#ifndef BSP_STM32_RTEMS_EMACPOLLINGTASK_H_ +#define BSP_STM32_RTEMS_EMACPOLLINGTASK_H_ + +#include +#include +#include + +class TmTcLwIpUdpBridge; + +/** + * @brief Separate task to poll EMAC interface. + * Polled data is passed to the netif (lwIP) + */ +class UdpTcLwIpPollingTask: + public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { +public: + UdpTcLwIpPollingTask(object_id_t objectId, object_id_t bridgeId); + virtual ~UdpTcLwIpPollingTask(); + + virtual ReturnValue_t initialize() override; + + /** + * Executed periodically. + * @param operationCode + * @return + */ + virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; +private: + static const uint8_t PERIODIC_HANDLE_TRIGGER = 5; + uint8_t periodicHandleCounter; + object_id_t bridgeId = 0; + TmTcLwIpUdpBridge* udpBridge = nullptr; +}; + + +#endif /* BSP_STM32_RTEMS_EMACPOLLINGTASK_H_ */ diff --git a/stm32h7/networking/app_dhcp.c b/stm32h7/networking/app_dhcp.c new file mode 100644 index 0000000..6209c86 --- /dev/null +++ b/stm32h7/networking/app_dhcp.c @@ -0,0 +1,155 @@ +#include "app_dhcp.h" +#include "app_ethernet.h" +#include +#include +#include + +#include +#include + +#include + +#if LWIP_DHCP == 1 + +uint8_t DHCP_state = DHCP_OFF; +uint32_t DHCPfineTimer = 0; + +void handle_dhcp_timeout(struct netif* netif); +void handle_dhcp_start(struct netif* netif); +void handle_dhcp_wait(struct netif* netif, struct dhcp** dhcp); +void handle_dhcp_down(struct netif* netif); + +/** + * @brief DHCP_Process_Handle + * @param None + * @retval None + */ +void DHCP_Process(struct netif *netif) +{ + struct dhcp* dhcp = NULL; + switch (DHCP_state) { + case DHCP_START: { + handle_dhcp_start(netif); + break; + } + case DHCP_WAIT_ADDRESS: { + handle_dhcp_wait(netif, &dhcp); + break; + } + + case DHCP_LINK_DOWN: { + handle_dhcp_down(netif); + break; + } + default: { + break; + } + } +} + +void handle_dhcp_timeout(struct netif* netif) { + ip_addr_t ipaddr; + ip_addr_t netmask; + ip_addr_t gw; + + DHCP_state = DHCP_TIMEOUT; + + /* Stop DHCP */ + dhcp_stop(netif); + + /* Static address used */ + set_lwip_addresses(&ipaddr, &netmask, &gw); + netif_set_addr(netif, &ipaddr, &netmask, &gw); + + printf("DHCP Timeout\n\r"); + uint8_t iptxt[20]; + sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif))); + printf("Assigning static IP address: %s\n", iptxt); + + ETH_HandleTypeDef* handle = getEthernetHandle(); + handle->gState = HAL_ETH_STATE_READY; + +#if OBSW_ETHERNET_TMTC_COMMANDING == 1 +#if OBSW_ETHERNET_USE_LED1_LED2 == 1 + BSP_LED_On(LED1); + BSP_LED_Off(LED2); +#endif +#endif +} + +/** + * @brief DHCP periodic check + * @param netif + * @retval None + */ +void DHCP_Periodic_Handle(struct netif *netif) +{ + /* Fine DHCP periodic process every 500ms */ + if (HAL_GetTick() - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS) { + DHCPfineTimer = HAL_GetTick(); + /* process DHCP state machine */ + DHCP_Process(netif); + } +} + +void handle_dhcp_start(struct netif* netif) { + printf("handle_dhcp_start: Looking for DHCP server ...\n\r"); +#if OBSW_ETHERNET_TMTC_COMMANDING == 1 +#if OBSW_ETHERNET_USE_LED1_LED2 == 1 + BSP_LED_Off(LED1); + BSP_LED_Off(LED2); +#endif +#endif + ip_addr_set_zero_ip4(&netif->ip_addr); + ip_addr_set_zero_ip4(&netif->netmask); + ip_addr_set_zero_ip4(&netif->gw); + dhcp_start(netif); + DHCP_state = DHCP_WAIT_ADDRESS; +} + +void handle_dhcp_wait(struct netif* netif, struct dhcp** dhcp) { + if (dhcp_supplied_address(netif)) { + DHCP_state = DHCP_ADDRESS_ASSIGNED; + printf("IP address assigned by a DHCP server: %s\n\r", ip4addr_ntoa(netif_ip4_addr(netif))); + printf("Listener port: %d\n\r", UDP_SERVER_PORT); +#if OBSW_ETHERNET_TMTC_COMMANDING == 1 +#if OBSW_ETHERNET_USE_LED1_LED2 == 1 + BSP_LED_On(LED1); + BSP_LED_Off(LED2); +#endif +#endif + } + else { + *dhcp = (struct dhcp*) netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); + + /* DHCP timeout */ + if ((*dhcp)->tries > MAX_DHCP_TRIES) + { + handle_dhcp_timeout(netif); + } + } +} + +void handle_dhcp_down(struct netif* netif) { + DHCP_state = DHCP_OFF; +#if OBSW_ETHERNET_TMTC_COMMANDING == 1 + printf("DHCP_Process: The network cable is not connected.\n\r"); +#if OBSW_ETHERNET_USE_LED1_LED2 == 1 + BSP_LED_Off(LED1); + BSP_LED_On(LED2); +#endif +#endif + + /* Global boolean to track ethernet connection */ + set_eth_cable_connected(false); +} + +uint8_t get_dhcp_state() { + return DHCP_state; +} + +void set_dhcp_state(uint8_t new_state) { + DHCP_state = new_state; +} + +#endif /* LWIP_DHCP == 1 */ diff --git a/stm32h7/networking/app_dhcp.h b/stm32h7/networking/app_dhcp.h new file mode 100644 index 0000000..8f58b81 --- /dev/null +++ b/stm32h7/networking/app_dhcp.h @@ -0,0 +1,34 @@ +#ifndef BSP_STM32_STM32CUBEH7_BOARDS_NUCLEO_H743ZI_INC_APP_DHCP_H_ +#define BSP_STM32_STM32CUBEH7_BOARDS_NUCLEO_H743ZI_INC_APP_DHCP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if LWIP_DHCP == 1 + +#include + +/* DHCP process states */ +#define DHCP_OFF (uint8_t) 0 +#define DHCP_START (uint8_t) 1 +#define DHCP_WAIT_ADDRESS (uint8_t) 2 +#define DHCP_ADDRESS_ASSIGNED (uint8_t) 3 +#define DHCP_TIMEOUT (uint8_t) 4 +#define DHCP_LINK_DOWN (uint8_t) 5 + +uint8_t get_dhcp_state(); +void set_dhcp_state(uint8_t new_state); + +void DHCP_Process(struct netif *netif); +void DHCP_Periodic_Handle(struct netif *netif); + +#endif /* LWIP_DHCP == 1 */ + +#ifdef __cplusplus +} +#endif + +#endif /* BSP_STM32_STM32CUBEH7_BOARDS_NUCLEO_H743ZI_INC_APP_DHCP_H_ */ diff --git a/stm32h7/networking/app_ethernet.c b/stm32h7/networking/app_ethernet.c new file mode 100644 index 0000000..b1de345 --- /dev/null +++ b/stm32h7/networking/app_ethernet.c @@ -0,0 +1,100 @@ +/* Includes ------------------------------------------------------------------*/ +#include "app_ethernet.h" +#include "ethernetif.h" +#include "udp_config.h" + +#if LWIP_DHCP +#include "app_dhcp.h" +#endif + +#include +#include +#include +#include + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +uint32_t ethernetLinkTimer = 0; + +/* Private function prototypes -----------------------------------------------*/ +void handle_status_change(struct netif* netif, bool link_up); + + +/* Private functions ---------------------------------------------------------*/ +/** + * @brief Notify the User about the network interface config status + * @param netif: the network interface + * @retval None + */ +void ethernet_link_status_updated(struct netif *netif) +{ + if (netif_is_link_up(netif)) + { + set_eth_cable_connected(true); + handle_status_change(netif, true); + } + else + { + set_eth_cable_connected(false); + handle_status_change(netif, false); + } +} + +void set_lwip_addresses(ip_addr_t* ipaddr, ip_addr_t* netmask, ip_addr_t* gw) { + IP4_ADDR(ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3); + IP4_ADDR(netmask, NETMASK_ADDR0, NETMASK_ADDR1 , + NETMASK_ADDR2, NETMASK_ADDR3); + IP4_ADDR(gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3); +} + + +void handle_status_change(struct netif* netif, bool link_up) { + if(link_up) { +#if LWIP_DHCP + /* Update DHCP state machine */ + set_dhcp_state(DHCP_START); +#else + uint8_t iptxt[20]; + sprintf((char *)iptxt, "%s", ip4addr_ntoa(netif_ip4_addr(netif))); + printf("\rNetwork cable connected. Static IP address: %s | Port: %d\n\r", iptxt, + UDP_SERVER_PORT); +#if OBSW_ETHERNET_USE_LED1_LED2 == 1 + BSP_LED_On(LED1); + BSP_LED_Off(LED2); +#endif +#endif /* LWIP_DHCP */ + } + else { + printf("Network cable disconnected\n\r"); +#if LWIP_DHCP + /* Update DHCP state machine */ + set_dhcp_state(DHCP_LINK_DOWN); +#else +#if OBSW_ETHERNET_USE_LED1_LED2 == 1 + BSP_LED_Off(LED1); + BSP_LED_On(LED2); +#endif +#endif /* LWIP_DHCP */ + } +} + +#if LWIP_NETIF_LINK_CALLBACK + +/** + * @brief Ethernet Link periodic check + * @param netif + * @retval None + */ +void ethernet_link_periodic_handle(struct netif *netif) +{ + /* Ethernet Link every 100ms */ + if (HAL_GetTick() - ethernetLinkTimer >= 100) + { + ethernetLinkTimer = HAL_GetTick(); + ethernet_link_check_state(netif); + } +} + +#endif /* LWIP_NETIF_LINK_CALLBACK */ diff --git a/stm32h7/networking/app_ethernet.h b/stm32h7/networking/app_ethernet.h new file mode 100644 index 0000000..da89593 --- /dev/null +++ b/stm32h7/networking/app_ethernet.h @@ -0,0 +1,76 @@ +/** + ****************************************************************************** + * @file LwIP/LwIP_UDP_Echo_Client/Inc/app_ethernet.h + * @author MCD Application Team + * @brief Header for app_ethernet.c module + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved.

+ * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __APP_ETHERNET_H +#define __APP_ETHERNET_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +#include +/* Exported types ------------------------------------------------------------*/ + +/* Exported constants --------------------------------------------------------*/ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void ethernet_link_status_updated(struct netif *netif); +void ethernet_link_periodic_handle(struct netif *netif); + +void set_lwip_addresses(ip_addr_t* ipaddr, ip_addr_t* netmask, ip_addr_t* gw); + +#ifdef __cplusplus +} +#endif + +#endif /* __APP_ETHERNET_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/stm32h7/networking/ethernetif.c b/stm32h7/networking/ethernetif.c new file mode 100644 index 0000000..d603289 --- /dev/null +++ b/stm32h7/networking/ethernetif.c @@ -0,0 +1,621 @@ +/** + ****************************************************************************** + * @file LwIP/LwIP_UDP_Echo_Client/Src/ethernetif.c + * @author MCD Application Team + * @brief This file implements Ethernet network interface drivers for lwIP + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved.

+ * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "ethernetif.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef FSFW_RTEMS +#include +#endif + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Network interface name */ +#define IFNAME0 's' +#define IFNAME1 't' + +#define DMA_DESCRIPTOR_ALIGNMENT 0x20 + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* +@Note: This interface is implemented to operate in zero-copy mode only: + - Rx buffers are allocated statically and passed directly to the LwIP stack + they will return back to DMA after been processed by the stack. + - Tx Buffers will be allocated from LwIP stack memory heap, + then passed to ETH HAL driver. + +@Notes: + 1.a. ETH DMA Rx descriptors must be contiguous, the default count is 4, + to customize it please redefine ETH_RX_DESC_CNT in stm32xxxx_hal_conf.h + 1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4, + to customize it please redefine ETH_TX_DESC_CNT in stm32xxxx_hal_conf.h + + 2.a. Rx Buffers number must be between ETH_RX_DESC_CNT and 2*ETH_RX_DESC_CNT + 2.b. Rx Buffers must have the same size: ETH_RX_BUFFER_SIZE, this value must + passed to ETH DMA in the init field (EthHandle.Init.RxBuffLen) +*/ + +#if defined ( __ICCARM__ ) /*!< IAR Compiler */ + +#pragma location=0x30040000 +ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */ +#pragma location=0x30040060 +ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */ +#pragma location=0x30040200 +uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; /* Ethernet Receive Buffers */ + +#elif defined ( __CC_ARM ) /* MDK ARM Compiler */ + +__attribute__((section(".RxDecripSection"))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */ +__attribute__((section(".TxDecripSection"))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */ +__attribute__((section(".RxArraySection"))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; /* Ethernet Receive Buffer */ + +#elif defined ( __GNUC__ ) /* GNU Compiler */ + +#ifdef FSFW_RTEMS +/* Put into special RTEMS section and align correctly */ +ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".bsp_nocache"), __aligned__(DMA_DESCRIPTOR_ALIGNMENT))); /* Ethernet Rx DMA Descriptors */ +/* Put into special RTEMS section and align correctly */ +ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".bsp_nocache"), __aligned__(DMA_DESCRIPTOR_ALIGNMENT))); /* Ethernet Tx DMA Descriptors */ +/* Ethernet Receive Buffers. Just place somewhere is BSS instead of explicitely placing it */ +uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; +#elif defined(FSFW_FREERTOS) +/* Placement and alignment specified in linker script here */ +ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */ +ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection"))); /* Ethernet Tx DMA Descriptors */ +uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE] __attribute__((section(".RxArraySection"))); /* Ethernet Receive Buffers */ +#endif /* FSFW_FREERTOS */ + +#endif /* defined ( __GNUC__ ) */ + +/* Global boolean to track ethernet connection */ +bool ethernet_cable_connected; + +struct pbuf_custom rx_pbuf[ETH_RX_DESC_CNT]; +uint32_t current_pbuf_idx =0; + +ETH_HandleTypeDef EthHandle; +ETH_TxPacketConfig TxConfig; + +lan8742_Object_t LAN8742; + +/* Private function prototypes -----------------------------------------------*/ +u32_t sys_now(void); +void pbuf_free_custom(struct pbuf *p); + +int32_t ETH_PHY_IO_Init(void); +int32_t ETH_PHY_IO_DeInit (void); +int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal); +int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal); +int32_t ETH_PHY_IO_GetTick(void); + + +lan8742_IOCtx_t LAN8742_IOCtx = {ETH_PHY_IO_Init, + ETH_PHY_IO_DeInit, + ETH_PHY_IO_WriteReg, + ETH_PHY_IO_ReadReg, + ETH_PHY_IO_GetTick}; +/* Private functions ---------------------------------------------------------*/ +/******************************************************************************* + LL Driver Interface ( LwIP stack --> ETH) +*******************************************************************************/ +/** + * @brief In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void low_level_init(struct netif *netif) +{ + uint32_t idx = 0; + uint8_t macaddress[6]= {ETH_MAC_ADDR0, ETH_MAC_ADDR1, ETH_MAC_ADDR2, ETH_MAC_ADDR3, ETH_MAC_ADDR4, ETH_MAC_ADDR5}; + + EthHandle.Instance = ETH; + EthHandle.Init.MACAddr = macaddress; + EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE; + EthHandle.Init.RxDesc = DMARxDscrTab; + EthHandle.Init.TxDesc = DMATxDscrTab; + EthHandle.Init.RxBuffLen = ETH_RX_BUFFER_SIZE; + + /* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */ + HAL_ETH_Init(&EthHandle); + + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* set MAC hardware address */ + netif->hwaddr[0] = 0x02; + netif->hwaddr[1] = 0x00; + netif->hwaddr[2] = 0x00; + netif->hwaddr[3] = 0x00; + netif->hwaddr[4] = 0x00; + netif->hwaddr[5] = 0x00; + + /* maximum transfer unit */ + netif->mtu = ETH_MAX_PAYLOAD; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; + + for(idx = 0; idx < ETH_RX_DESC_CNT; idx ++) + { + HAL_ETH_DescAssignMemory(&EthHandle, idx, Rx_Buff[idx], NULL); + + /* Set Custom pbuf free function */ + rx_pbuf[idx].custom_free_function = pbuf_free_custom; + } + + /* Set Tx packet config common parameters */ + memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig)); + TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD; + TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC; + TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT; + + /* Set PHY IO functions */ + LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx); + + /* Initialize the LAN8742 ETH PHY */ + LAN8742_Init(&LAN8742); + + ethernet_link_check_state(netif); + +} + +/** + * @brief This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become availale since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ +static err_t low_level_output(struct netif *netif, struct pbuf *p) +{ + uint32_t i=0, framelen = 0; + struct pbuf *q; + err_t errval = ERR_OK; + ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT]; + + for(q = p; q != NULL; q = q->next) + { + if(i >= ETH_TX_DESC_CNT) + return ERR_IF; + + Txbuffer[i].buffer = q->payload; + Txbuffer[i].len = q->len; + framelen += q->len; + + if(i>0) + { + Txbuffer[i-1].next = &Txbuffer[i]; + } + + if(q->next == NULL) + { + Txbuffer[i].next = NULL; + } + + i++; + } + + TxConfig.Length = framelen; + TxConfig.TxBuffer = Txbuffer; + + HAL_StatusTypeDef ret = HAL_ETH_Transmit(&EthHandle, &TxConfig, 20); + + if(ret != HAL_OK) { + printf("low_level_output: Could not transmit ethernet packet, code %d!\n\r", ret); + } + + return errval; +} + +/** + * @brief Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf * low_level_input(struct netif *netif) +{ + struct pbuf *p = NULL; + ETH_BufferTypeDef RxBuff; + uint32_t framelength = 0; + + if (HAL_ETH_IsRxDataAvailable(&EthHandle)) + { + HAL_ETH_GetRxDataBuffer(&EthHandle, &RxBuff); + HAL_ETH_GetRxDataLength(&EthHandle, &framelength); + + /* Invalidate data cache for ETH Rx Buffers */ + SCB_InvalidateDCache_by_Addr((uint32_t *)Rx_Buff, (ETH_RX_DESC_CNT*ETH_RX_BUFFER_SIZE)); + + p = pbuf_alloced_custom(PBUF_RAW, framelength, PBUF_POOL, &rx_pbuf[current_pbuf_idx], RxBuff.buffer, ETH_RX_BUFFER_SIZE); + if(current_pbuf_idx < (ETH_RX_DESC_CNT -1)) + { + current_pbuf_idx++; + } + else + { + current_pbuf_idx = 0; + } + + return p; + } + else + { + return NULL; + } +} + +/** + * @brief This function is the ethernetif_input task, it is processed when a packet + * is ready to be read from the interface. It uses the function low_level_input() + * that should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +void ethernetif_input(struct netif *netif) +{ + err_t err; + struct pbuf *p; + + /* move received packet into a new pbuf */ + p = low_level_input(netif); + + /* no packet could be read, silently ignore this */ + if (p == NULL) return; + + /* entry point to the LwIP stack */ + err = netif->input(p, netif); + + if (err != ERR_OK) + { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + + HAL_ETH_BuildRxDescriptors(&EthHandle); +} + +/** + * @brief Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t ethernetif_init(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ + netif->output = etharp_output; + netif->linkoutput = low_level_output; + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} + +/** + * @brief Custom Rx pbuf free callback + * @param pbuf: pbuf to be freed + * @retval None + */ +void pbuf_free_custom(struct pbuf *p) +{ + if(p != NULL) + { + p->flags = 0; + p->next = NULL; + p->len = p->tot_len = 0; + p->ref = 0; + p->payload = NULL; + } +} + +/** + * @brief Returns the current time in milliseconds + * when LWIP_TIMERS == 1 and NO_SYS == 1 + * @param None + * @retval Current Time value + */ +u32_t sys_now(void) +{ + return HAL_GetTick(); +} + +/******************************************************************************* + Ethernet MSP Routines +*******************************************************************************/ +/** + * @brief Initializes the ETH MSP. + * @param heth: ETH handle + * @retval None +*/ +void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Ethernett MSP init: RMII Mode */ + + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + +/* Ethernet pins configuration ************************************************/ + /* + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> PG2 + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Configure PB13 */ + GPIO_InitStructure.Pin = GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + + /* Configure PG2, PG11, PG13 and PG14 */ + GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + +#if NO_SYS == 0 + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); +#endif + + /* Enable Ethernet clocks */ + __HAL_RCC_ETH1MAC_CLK_ENABLE(); + __HAL_RCC_ETH1TX_CLK_ENABLE(); + __HAL_RCC_ETH1RX_CLK_ENABLE(); +} + +/******************************************************************************* + PHI IO Functions +*******************************************************************************/ +/** + * @brief Initializes the MDIO interface GPIO and clocks. + * @param None + * @retval 0 if OK, -1 if ERROR + */ +int32_t ETH_PHY_IO_Init(void) +{ + /* We assume that MDIO GPIO configuration is already done + in the ETH_MspInit() else it should be done here + */ + + /* Configure the MDIO Clock */ + HAL_ETH_SetMDIOClockRange(&EthHandle); + + return 0; +} + +/** + * @brief De-Initializes the MDIO interface . + * @param None + * @retval 0 if OK, -1 if ERROR + */ +int32_t ETH_PHY_IO_DeInit (void) +{ + return 0; +} + +/** + * @brief Read a PHY register through the MDIO interface. + * @param DevAddr: PHY port address + * @param RegAddr: PHY register address + * @param pRegVal: pointer to hold the register value + * @retval 0 if OK -1 if Error + */ +int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal) +{ + if(HAL_ETH_ReadPHYRegister(&EthHandle, DevAddr, RegAddr, pRegVal) != HAL_OK) + { + return -1; + } + + return 0; +} + +/** + * @brief Write a value to a PHY register through the MDIO interface. + * @param DevAddr: PHY port address + * @param RegAddr: PHY register address + * @param RegVal: Value to be written + * @retval 0 if OK -1 if Error + */ +int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal) +{ + if(HAL_ETH_WritePHYRegister(&EthHandle, DevAddr, RegAddr, RegVal) != HAL_OK) + { + return -1; + } + + return 0; +} + +/** + * @brief Get the time in millisecons used for internal PHY driver process. + * @retval Time value + */ +int32_t ETH_PHY_IO_GetTick(void) +{ + return HAL_GetTick(); +} + +/** + * @brief + * @retval None + */ +void ethernet_link_check_state(struct netif *netif) +{ + ETH_MACConfigTypeDef MACConf; + uint32_t PHYLinkState; + uint32_t linkchanged = 0, speed = 0, duplex =0; + + PHYLinkState = LAN8742_GetLinkState(&LAN8742); + + if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN)) + { + HAL_ETH_Stop(&EthHandle); + netif_set_down(netif); + netif_set_link_down(netif); + } + else if(!netif_is_link_up(netif) && (PHYLinkState > LAN8742_STATUS_LINK_DOWN)) + { + switch (PHYLinkState) + { + case LAN8742_STATUS_100MBITS_FULLDUPLEX: + duplex = ETH_FULLDUPLEX_MODE; + speed = ETH_SPEED_100M; + linkchanged = 1; + break; + case LAN8742_STATUS_100MBITS_HALFDUPLEX: + duplex = ETH_HALFDUPLEX_MODE; + speed = ETH_SPEED_100M; + linkchanged = 1; + break; + case LAN8742_STATUS_10MBITS_FULLDUPLEX: + duplex = ETH_FULLDUPLEX_MODE; + speed = ETH_SPEED_10M; + linkchanged = 1; + break; + case LAN8742_STATUS_10MBITS_HALFDUPLEX: + duplex = ETH_HALFDUPLEX_MODE; + speed = ETH_SPEED_10M; + linkchanged = 1; + break; + default: + break; + } + + if(linkchanged) + { + /* Get MAC Config MAC */ + HAL_ETH_GetMACConfig(&EthHandle, &MACConf); + MACConf.DuplexMode = duplex; + MACConf.Speed = speed; + HAL_ETH_SetMACConfig(&EthHandle, &MACConf); + HAL_ETH_Start(&EthHandle); + netif_set_up(netif); + netif_set_link_up(netif); + } + } +} + +ETH_HandleTypeDef* getEthernetHandle() { + return &EthHandle; +} + +void set_eth_cable_connected(bool status) { + ethernet_cable_connected = status; +} + +bool get_eth_cable_connected() { + return ethernet_cable_connected; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/stm32h7/networking/ethernetif.h b/stm32h7/networking/ethernetif.h new file mode 100644 index 0000000..cc0415a --- /dev/null +++ b/stm32h7/networking/ethernetif.h @@ -0,0 +1,77 @@ +/** + ****************************************************************************** + * @file LwIP/LwIP_HTTP_Server_Netconn_RTOS/Inc/ethernetif.h + * @author MCD Application Team + * @brief Header for ethernetif.c module + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics International N.V. + * All rights reserved.

+ * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of other + * contributors to this software may be used to endorse or promote products + * derived from this software without specific written permission. + * 4. This software, including modifications and/or derivative works of this + * software, must execute solely and exclusively on microcontroller or + * microprocessor devices manufactured by or for STMicroelectronics. + * 5. Redistribution and use of this software other than as permitted under + * this license is void and will automatically terminate your rights under + * this license. + * + * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY + * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT + * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +#ifndef __ETHERNETIF_H__ +#define __ETHERNETIF_H__ + +#include "lwip/err.h" +#include "lwip/netif.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ETH_RX_BUFFER_SIZE (1536UL) + +/* Exported types ------------------------------------------------------------*/ +void set_eth_cable_connected(bool status); +bool get_eth_cable_connected(); + +ETH_HandleTypeDef* getEthernetHandle(); +err_t ethernetif_init(struct netif *netif); +void ethernetif_input(struct netif *netif); +void ethernet_link_check_state(struct netif *netif); + +extern ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; +extern ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; +extern uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; + +#ifdef __cplusplus +} +#endif + +#endif /* __ETHERNETIF_H__ */ diff --git a/stm32h7/networking/udp_config.h b/stm32h7/networking/udp_config.h new file mode 100644 index 0000000..e2e9b65 --- /dev/null +++ b/stm32h7/networking/udp_config.h @@ -0,0 +1,39 @@ +#ifndef COMMON_STM32_NUCLEO_NETWORKING_UDP_CONFIG_H_ +#define COMMON_STM32_NUCLEO_NETWORKING_UDP_CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* UDP local connection port. Client needs to bind to this port */ +#define UDP_SERVER_PORT 7 + +/*Static DEST IP ADDRESS: DEST_IP_ADDR0.DEST_IP_ADDR1.DEST_IP_ADDR2.DEST_IP_ADDR3 */ +#define DEST_IP_ADDR0 ((uint8_t)169U) +#define DEST_IP_ADDR1 ((uint8_t)254U) +#define DEST_IP_ADDR2 ((uint8_t)39U) +#define DEST_IP_ADDR3 ((uint8_t)2U) + +/*Static IP ADDRESS*/ +#define IP_ADDR0 169 +#define IP_ADDR1 254 +#define IP_ADDR2 1 +#define IP_ADDR3 38 + +/*NETMASK*/ +#define NETMASK_ADDR0 255 +#define NETMASK_ADDR1 255 +#define NETMASK_ADDR2 0 +#define NETMASK_ADDR3 0 + +/*Gateway Address*/ +#define GW_ADDR0 192 +#define GW_ADDR1 168 +#define GW_ADDR2 178 +#define GW_ADDR3 1 + +#ifdef __cplusplus +} +#endif + +#endif /* COMMON_STM32_NUCLEO_NETWORKING_UDP_CONFIG_H_ */