diff options
31 files changed, 505 insertions, 392 deletions
@@ -1352,7 +1352,7 @@ <listOptionValue builtIn="false" value="__SAME70Q20B__"/> <listOptionValue builtIn="false" value="RTOS"/> <listOptionValue builtIn="false" value="DUET3_V06"/> - <listOptionValue builtIn="false" value="LWIP_GMAC_TASK=0"/> + <listOptionValue builtIn="false" value="LWIP_GMAC_TASK=1"/> </option> <option id="gnu.c.compiler.option.dialect.std.1738681846" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.default" valueType="enumerated"/> <option id="gnu.c.compiler.option.dialect.flags.1952106689" name="Other dialect flags" superClass="gnu.c.compiler.option.dialect.flags" useByScannerDiscovery="true" value="-std=gnu99" valueType="string"/> @@ -1419,7 +1419,7 @@ <listOptionValue builtIn="false" value="__SAME70Q20B__"/> <listOptionValue builtIn="false" value="RTOS"/> <listOptionValue builtIn="false" value="DUET3_V06"/> - <listOptionValue builtIn="false" value="LWIP_GMAC_TASK=0"/> + <listOptionValue builtIn="false" value="LWIP_GMAC_TASK=1"/> <listOptionValue builtIn="false" value="_XOPEN_SOURCE"/> </option> <option id="gnu.cpp.compiler.option.dialect.std.1240779290" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.cpp.compiler.dialect.default" valueType="enumerated"/> @@ -1532,6 +1532,8 @@ <listOptionValue builtIn="false" value="__SAME70Q20B__"/> <listOptionValue builtIn="false" value="RTOS"/> <listOptionValue builtIn="false" value="DUET3_V06"/> + <listOptionValue builtIn="false" value="LWIP_GMAC_TASK=1"/> + <listOptionValue builtIn="false" value="DEBUG"/> </option> <option id="gnu.c.compiler.option.dialect.std.1475182191" name="Language standard" superClass="gnu.c.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.c.compiler.dialect.default" valueType="enumerated"/> <option id="gnu.c.compiler.option.dialect.flags.879019933" name="Other dialect flags" superClass="gnu.c.compiler.option.dialect.flags" useByScannerDiscovery="true" value="-std=gnu99" valueType="string"/> @@ -1599,6 +1601,8 @@ <listOptionValue builtIn="false" value="RTOS"/> <listOptionValue builtIn="false" value="DUET3_V06"/> <listOptionValue builtIn="false" value="_XOPEN_SOURCE"/> + <listOptionValue builtIn="false" value="LWIP_GMAC_TASK=1"/> + <listOptionValue builtIn="false" value="DEBUG"/> </option> <option id="gnu.cpp.compiler.option.dialect.std.1952551090" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.cpp.compiler.dialect.default" valueType="enumerated"/> <option id="gnu.cpp.compiler.option.dialect.flags.832664520" name="Other dialect flags" superClass="gnu.cpp.compiler.option.dialect.flags" useByScannerDiscovery="true" value="-std=gnu++17" valueType="string"/> diff --git a/src/Endstops/SwitchEndstop.h b/src/Endstops/SwitchEndstop.h index cd4492be..5fb2f623 100644 --- a/src/Endstops/SwitchEndstop.h +++ b/src/Endstops/SwitchEndstop.h @@ -46,7 +46,7 @@ private: inline bool IsTriggered(size_t index) const { #if SUPPORT_CAN_EXPANSION - return (boardNumbers[index] == CanId::MasterAddress) ? ports[index].Read() : states[index] != activeLow; + return (boardNumbers[index] == CanId::MasterAddress) ? ports[index].Read() != activeLow : states[index] != activeLow; #else return ports[index].Read(); #endif diff --git a/src/Hardware/IoPorts.cpp b/src/Hardware/IoPorts.cpp index 7672356d..daf1c54f 100644 --- a/src/Hardware/IoPorts.cpp +++ b/src/Hardware/IoPorts.cpp @@ -197,23 +197,20 @@ bool IoPort::Allocate(const char *pn, const StringRef& reply, PinUsedBy neededFo const char *const fullPinName = pn; // the full pin name less the inversion and pullup flags #if defined(DUET3) - uint32_t expansionNumber; if (isdigit(*pn)) { - expansionNumber = SafeStrtoul(pn, &pn); + const uint32_t expansionNumber = SafeStrtoul(pn, &pn); if (*pn != '.') { reply.printf("Bad pin name '%s'", fullPinName); return false; } + if (expansionNumber != 0) + { + reply.printf("Pin '%s': only main board pins allowed here", fullPinName); + return false; + } } - else - { - expansionNumber = 0; - } - - //TODO use expansionNumber as part of the logical pin number - (void)expansionNumber; #endif LogicalPin lp; diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.cpp b/src/Networking/ESP8266WiFi/WiFiInterface.cpp index 95ff18eb..d1024a9e 100644 --- a/src/Networking/ESP8266WiFi/WiFiInterface.cpp +++ b/src/Networking/ESP8266WiFi/WiFiInterface.cpp @@ -469,13 +469,12 @@ void WiFiInterface::Stop() } } -void WiFiInterface::Spin(bool full) +void WiFiInterface::Spin() { // Main state machine. switch (state) { case NetworkState::starting1: - if (full) { // The ESP toggles CS before it has finished starting up, so don't look at the CS signal too soon const uint32_t now = millis(); @@ -488,7 +487,6 @@ void WiFiInterface::Spin(bool full) break; case NetworkState::starting2: - if (full) { // See if the ESP8266 has kept its pins at their stable values for long enough const uint32_t now = millis(); @@ -533,93 +531,90 @@ void WiFiInterface::Spin(bool full) break; case NetworkState::disabled: - if (full && uploader != nullptr) + if (uploader != nullptr) { uploader->Spin(); } break; case NetworkState::active: - if (full) + if (espStatusChanged && digitalRead(EspDataReadyPin)) { - if (espStatusChanged && digitalRead(EspDataReadyPin)) + if (reprap.Debug(moduleNetwork)) { - if (reprap.Debug(moduleNetwork)) - { - debugPrintf("ESP reported status change\n"); - } - GetNewStatus(); + debugPrintf("ESP reported status change\n"); } - else if ( currentMode != requestedMode - && currentMode != WiFiState::connecting - && currentMode != WiFiState::reconnecting - && currentMode != WiFiState::autoReconnecting - ) + GetNewStatus(); + } + else if ( currentMode != requestedMode + && currentMode != WiFiState::connecting + && currentMode != WiFiState::reconnecting + && currentMode != WiFiState::autoReconnecting + ) + { + // Tell the wifi module to change mode + int32_t rslt = ResponseUnknownError; + if (currentMode != WiFiState::idle) { - // Tell the wifi module to change mode - int32_t rslt = ResponseUnknownError; - if (currentMode != WiFiState::idle) - { - // We must set WiFi module back to idle before changing to the new state - rslt = SendCommand(NetworkCommand::networkStop, 0, 0, nullptr, 0, nullptr, 0); - } - else if (requestedMode == WiFiState::connected) - { - rslt = SendCommand(NetworkCommand::networkStartClient, 0, 0, requestedSsid, SsidLength, nullptr, 0); - } - else if (requestedMode == WiFiState::runningAsAccessPoint) - { - rslt = SendCommand(NetworkCommand::networkStartAccessPoint, 0, 0, nullptr, 0, nullptr, 0); - } + // We must set WiFi module back to idle before changing to the new state + rslt = SendCommand(NetworkCommand::networkStop, 0, 0, nullptr, 0, nullptr, 0); + } + else if (requestedMode == WiFiState::connected) + { + rslt = SendCommand(NetworkCommand::networkStartClient, 0, 0, requestedSsid, SsidLength, nullptr, 0); + } + else if (requestedMode == WiFiState::runningAsAccessPoint) + { + rslt = SendCommand(NetworkCommand::networkStartAccessPoint, 0, 0, nullptr, 0, nullptr, 0); + } - if (rslt >= 0) - { - state = NetworkState::changingMode; - } - else - { - Stop(); - platform.MessageF(NetworkInfoMessage, "Failed to change WiFi mode (code %" PRIi32 ")\n", rslt); - } + if (rslt >= 0) + { + state = NetworkState::changingMode; } - else if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint) + else + { + Stop(); + platform.MessageF(NetworkInfoMessage, "Failed to change WiFi mode (code %" PRIi32 ")\n", rslt); + } + } + else if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint) + { + // Find the next socket to poll + const size_t startingSocket = currentSocket; + do { - // Find the next socket to poll - const size_t startingSocket = currentSocket; - do + if (sockets[currentSocket]->NeedsPolling()) { - if (sockets[currentSocket]->NeedsPolling()) - { - break; - } - ++currentSocket; - if (currentSocket == NumWiFiTcpSockets) - { - currentSocket = 0; - } - } while (currentSocket != startingSocket); - - // Either the current socket needs polling, or no sockets do but we must still poll one of them to get notified of any new connections - sockets[currentSocket]->Poll(full); + break; + } ++currentSocket; if (currentSocket == NumWiFiTcpSockets) { currentSocket = 0; } + } while (currentSocket != startingSocket); + + // Either the current socket needs polling, or no sockets do but we must still poll one of them to get notified of any new connections + sockets[currentSocket]->Poll(); + ++currentSocket; + if (currentSocket == NumWiFiTcpSockets) + { + currentSocket = 0; + } - // Check if the data port needs to be closed - if (closeDataPort) + // Check if the data port needs to be closed + if (closeDataPort) + { + for (WiFiSocket *s : sockets) { - for (WiFiSocket *s : sockets) + if (s->GetProtocol() == FtpDataProtocol) { - if (s->GetProtocol() == FtpDataProtocol) + if (!s->IsClosing()) { - if (!s->IsClosing()) - { - TerminateDataPort(); - } - break; + TerminateDataPort(); } + break; } } } @@ -628,7 +623,7 @@ void WiFiInterface::Spin(bool full) case NetworkState::changingMode: // Here when we have asked the ESP to change mode. Don't leave this state until we have a new status report from the ESP. - if (full && espStatusChanged && digitalRead(EspDataReadyPin)) + if (espStatusChanged && digitalRead(EspDataReadyPin)) { GetNewStatus(); switch (currentMode) @@ -695,19 +690,16 @@ void WiFiInterface::Spin(bool full) } } - if (full) + // Check for debug info received from the WiFi module + if (debugPrintPending) { - // Check for debug info received from the WiFi module - if (debugPrintPending) + if (reprap.Debug(moduleWiFi)) { - if (reprap.Debug(moduleWiFi)) - { - debugMessageBuffer[debugMessageChars] = 0; - debugPrintf("WiFi: %s\n", debugMessageBuffer); - } - debugMessageChars = 0; - debugPrintPending = false; + debugMessageBuffer[debugMessageChars] = 0; + debugPrintf("WiFi: %s\n", debugMessageBuffer); } + debugMessageChars = 0; + debugPrintPending = false; } } diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.h b/src/Networking/ESP8266WiFi/WiFiInterface.h index 6656967a..7b7bbc72 100644 --- a/src/Networking/ESP8266WiFi/WiFiInterface.h +++ b/src/Networking/ESP8266WiFi/WiFiInterface.h @@ -42,7 +42,7 @@ public: void Init() override; void Activate() override; void Exit() override; - void Spin(bool full) override; + void Spin() override; void Diagnostics(MessageType mtype) override; void Start(); void Stop(); diff --git a/src/Networking/ESP8266WiFi/WiFiSocket.cpp b/src/Networking/ESP8266WiFi/WiFiSocket.cpp index 5fbe6d45..16cfb26b 100644 --- a/src/Networking/ESP8266WiFi/WiFiSocket.cpp +++ b/src/Networking/ESP8266WiFi/WiFiSocket.cpp @@ -114,7 +114,7 @@ void WiFiSocket::Taken(size_t len) } // Poll a socket to see if it needs to be serviced -void WiFiSocket::Poll(bool full) +void WiFiSocket::Poll() { // Get the socket status Receiver<ConnStatusResponse> resp; @@ -161,7 +161,7 @@ void WiFiSocket::Poll(bool full) // no break case ConnState::connected: - if (full && state != SocketState::connected) + if (state != SocketState::connected) { // It's a new connection if (reprap.Debug(moduleNetwork)) diff --git a/src/Networking/ESP8266WiFi/WiFiSocket.h b/src/Networking/ESP8266WiFi/WiFiSocket.h index 02b87948..d9fb953c 100644 --- a/src/Networking/ESP8266WiFi/WiFiSocket.h +++ b/src/Networking/ESP8266WiFi/WiFiSocket.h @@ -21,7 +21,7 @@ public: WiFiSocket(NetworkInterface *iface); void Init(SocketNumber n); int State() const { return (int)state; } // used only for reporting debug info, hence the 'int' return - void Poll(bool full); + void Poll(); void Close(); bool IsClosing() const { return (state == SocketState::closing); } void Terminate(); diff --git a/src/Networking/LwipEthernet/GMAC/ethernet_sam.cpp b/src/Networking/LwipEthernet/GMAC/ethernet_sam.cpp index a1ac7db8..e706a153 100644 --- a/src/Networking/LwipEthernet/GMAC/ethernet_sam.cpp +++ b/src/Networking/LwipEthernet/GMAC/ethernet_sam.cpp @@ -59,8 +59,6 @@ extern "C" { #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/tcp.h" -#include "lwip/tcp.h" -#include "lwip/tcpip.h" #include "netif/etharp.h" /* Global variable containing MAC Config (hw addr, IP, GW, ...) */ @@ -223,6 +221,7 @@ void ethernet_task(void) ethernet_timers_update(); } +#if !LWIP_GMAC_TASK /* * \brief Sets the EMAC RX callback. It will be called when a new packet * can be processed and should be called with a NULL parameter inside @@ -234,6 +233,7 @@ void ethernet_set_rx_callback(gmac_dev_tx_cb_t callback) { ethernetif_set_rx_callback(callback); } +#endif /* * \brief Returns the current IP address diff --git a/src/Networking/LwipEthernet/GMAC/ethernet_sam.h b/src/Networking/LwipEthernet/GMAC/ethernet_sam.h index 0532dc88..23266cf3 100644 --- a/src/Networking/LwipEthernet/GMAC/ethernet_sam.h +++ b/src/Networking/LwipEthernet/GMAC/ethernet_sam.h @@ -72,11 +72,12 @@ void ethernet_timers_update(void); // Reads all stored network packets and processes them void ethernet_task(void); +#if !LWIP_GMAC_TASK // Set the RX callback for incoming network packets void ethernet_set_rx_callback(gmac_dev_tx_cb_t callback); +#endif // Returns the network interface's current IPv4 address void ethernet_get_ipaddress(IPAddress& ipAddress, IPAddress& netMask, IPAddress& gateWay); - #endif /* ETHERNET_SAM_H_INCLUDED */ diff --git a/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp b/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp index 12f070c8..895f7d22 100644 --- a/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp +++ b/src/Networking/LwipEthernet/GMAC/same70_gmac.cpp @@ -3,39 +3,29 @@ * * \brief GMAC (Gigabit MAC) driver for lwIP. * - * Copyright (c) 2015-2016 Atmel Corporation. All rights reserved. + * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. * * \asf_license_start * * \page License * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. * - * 1. Redistributions 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. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. * * \asf_license_stop * @@ -48,29 +38,40 @@ extern "C" { #include "ethernet_phy.h" +#include "lwip/opt.h" +#include "lwip/sys.h" #include "lwip/def.h" #include "lwip/mem.h" -#include "lwip/opt.h" #include "lwip/pbuf.h" -#include "lwip/snmp.h" #include "lwip/stats.h" -#include "lwip/sys.h" +#include "lwip/snmp.h" #include "netif/etharp.h" } #define __nocache __attribute__((section(".ram_nocache"))) +extern void delay(uint32_t ms); + #if LWIP_GMAC_TASK // We can't #include RepRapFirmware.h here because that leads to a duplicate definition of ERR_TIMEOUT #include <RTOSIface/RTOSIface.h> #include <TaskPriorities.h> -constexpr size_t EthernetTaskStackWords = 200; +extern Mutex lwipMutex; + +constexpr size_t EthernetTaskStackWords = 250; static Task<EthernetTaskStackWords> ethernetTask; #endif +// Error counters +unsigned int rxErrorCount; +unsigned int rxBuffersNotFullyPopulatedCount; +unsigned int txErrorCount; +unsigned int txBufferNotFreeCount; +unsigned int txBufferTooShortCount; + /** Network interface identifier. */ #define IFNAME0 'e' #define IFNAME1 'n' @@ -123,9 +124,9 @@ struct gmac_device { * of the address shall be set to 0. */ /** Pointer to Rx descriptor list (must be 8-byte aligned). */ - gmac_rx_descriptor_t rx_desc[GMAC_RX_BUFFERS]; + volatile gmac_rx_descriptor_t rx_desc[GMAC_RX_BUFFERS]; /** Pointer to Tx descriptor list (must be 8-byte aligned). */ - gmac_tx_descriptor_t tx_desc[GMAC_TX_BUFFERS]; + volatile gmac_tx_descriptor_t tx_desc[GMAC_TX_BUFFERS]; /** RX pbuf pointer list. */ struct pbuf *rx_pbuf[GMAC_RX_BUFFERS]; /** TX buffers. */ @@ -158,6 +159,8 @@ static uint8_t gs_uc_mac_address[] = ETHERNET_CONF_ETHADDR5 }; +static bool rxPbufsFullyPopulated = false; + #if LWIP_STATS /** Used to compute lwIP bandwidth. */ uint32_t lwip_tx_count = 0; @@ -166,7 +169,9 @@ uint32_t lwip_tx_rate = 0; uint32_t lwip_rx_rate = 0; #endif -static gmac_dev_tx_cb_t gmac_rx_cb = NULL; +#if !LWIP_GMAC_TASK +static gmac_dev_tx_cb_t gmac_rx_cb = nullptr; +#endif /** * \brief GMAC interrupt handler. @@ -190,7 +195,7 @@ void GMAC_Handler(void) ul_isr = gmac_get_interrupt_status(GMAC); /* RX interrupts. */ - if ((ul_isr & GMAC_INT_GROUP) != 0 && gmac_rx_cb != NULL) + if ((ul_isr & GMAC_INT_GROUP) != 0 && gmac_rx_cb != nullptr) { gmac_rx_cb(ul_isr); } @@ -207,21 +212,25 @@ void GMAC_Handler(void) * (since the lsb are used as status bits by GMAC). * * \param p_gmac_dev Pointer to driver data structure. + * \param startAt The index to start populating from */ -static void gmac_rx_populate_queue(struct gmac_device *p_gmac_dev) +static void gmac_rx_populate_queue(struct gmac_device *p_gmac_dev, uint32_t startAt) { - uint32_t ul_index = 0; - struct pbuf *p = 0; + uint32_t ul_index = startAt; /* Set up the RX descriptors. */ - for (ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++) { - if (p_gmac_dev->rx_pbuf[ul_index] == 0) { - + do + { + if (p_gmac_dev->rx_pbuf[ul_index] == nullptr) + { /* Allocate a new pbuf with the maximum size. */ - p = pbuf_alloc(PBUF_RAW, (u16_t) GMAC_FRAME_LENTGH_MAX, PBUF_POOL); - if (p == NULL) { + pbuf * const p = pbuf_alloc(PBUF_RAW, (u16_t) GMAC_FRAME_LENTGH_MAX, PBUF_POOL); + if (p == nullptr) + { LWIP_DEBUGF(NETIF_DEBUG, ("gmac_rx_populate_queue: pbuf allocation failure\n")); - break; + rxPbufsFullyPopulated = false; + ++rxBuffersNotFullyPopulatedCount; + return; } /* Make sure lwIP is well configured so one pbuf can contain the maximum packet size. */ @@ -231,22 +240,35 @@ static void gmac_rx_populate_queue(struct gmac_device *p_gmac_dev) LWIP_ASSERT("gmac_rx_populate_queue: unaligned p->payload buffer address", (((uint32_t)p->payload & 0xFFFFFFFC) == (uint32_t)p->payload)); - if (ul_index == GMAC_RX_BUFFERS - 1) - p_gmac_dev->rx_desc[ul_index].addr.val = (u32_t) p->payload | GMAC_RXD_WRAP; - else - p_gmac_dev->rx_desc[ul_index].addr.val = (u32_t) p->payload; - + // dc42 do this first to avoid a race condition with DMA, because writing addr.val transfers ownership back to the GMAC, so it should be the last thing we do /* Reset status value. */ p_gmac_dev->rx_desc[ul_index].status.val = 0; /* Save pbuf pointer to be sent to lwIP upper layer. */ p_gmac_dev->rx_pbuf[ul_index] = p; + if (ul_index == GMAC_RX_BUFFERS - 1) + { + p_gmac_dev->rx_desc[ul_index].addr.val = (u32_t) p->payload | GMAC_RXD_WRAP; + } + else + { + p_gmac_dev->rx_desc[ul_index].addr.val = (u32_t) p->payload; + } + LWIP_DEBUGF(NETIF_DEBUG, ("gmac_rx_populate_queue: new pbuf allocated: %p [idx=%u]\n", p, ul_index)); } - } + + ++ul_index; + if (ul_index == GMAC_RX_BUFFERS) + { + ul_index = 0; + } + } while (ul_index != startAt); + + rxPbufsFullyPopulated = true; } /** @@ -264,15 +286,16 @@ static void gmac_rx_init(struct gmac_device *ps_gmac_dev) ps_gmac_dev->us_rx_idx = 0; /* Set up the RX descriptors. */ - for (ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++) { - ps_gmac_dev->rx_pbuf[ul_index] = 0; - ps_gmac_dev->rx_desc[ul_index].addr.val = 0; + for (ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++) + { + ps_gmac_dev->rx_pbuf[ul_index] = nullptr; + ps_gmac_dev->rx_desc[ul_index].addr.val = GMAC_RXD_OWNERSHIP; // mark it as not free for hardware to use, until we have allocated the pbuf ps_gmac_dev->rx_desc[ul_index].status.val = 0; } ps_gmac_dev->rx_desc[ul_index - 1].addr.val |= GMAC_RXD_WRAP; /* Build RX buffer and descriptors. */ - gmac_rx_populate_queue(ps_gmac_dev); + gmac_rx_populate_queue(ps_gmac_dev, 0); /* Set receive buffer queue base address pointer. */ gmac_set_rx_queue(GMAC, (uint32_t) &ps_gmac_dev->rx_desc[0]); @@ -293,8 +316,9 @@ static void gmac_tx_init(struct gmac_device *ps_gmac_dev) ps_gmac_dev->us_tx_idx = 0; /* Set up the TX descriptors. */ - for (ul_index = 0; ul_index < GMAC_TX_BUFFERS; ul_index++) { - ps_gmac_dev->tx_desc[ul_index].addr = (uint32_t)&ps_gmac_dev->tx_buf[ul_index][0]; + for (ul_index = 0; ul_index < GMAC_TX_BUFFERS; ul_index++) + { + ps_gmac_dev->tx_desc[ul_index].addr = reinterpret_cast<uint32_t>(&ps_gmac_dev->tx_buf[ul_index][0]); ps_gmac_dev->tx_desc[ul_index].status.val = GMAC_TXD_USED | GMAC_TXD_LAST; } ps_gmac_dev->tx_desc[ul_index - 1].status.val |= GMAC_TXD_WRAP; @@ -378,14 +402,14 @@ static void gmac_low_level_init(struct netif *netif) * \return ERR_OK if the packet could be sent. * an err_t value if the packet couldn't be sent. */ -static err_t gmac_low_level_output(struct netif *netif, struct pbuf *p) +static err_t gmac_low_level_output(netif *p_netif, struct pbuf *p) { - struct gmac_device *ps_gmac_dev = static_cast<gmac_device *>(netif->state); - struct pbuf *q = NULL; - uint8_t *buffer = 0; + gmac_device *const ps_gmac_dev = static_cast<gmac_device *>(p_netif->state); /* Handle GMAC underrun or AHB errors. */ - if (gmac_get_tx_status(GMAC) & GMAC_TX_ERRORS) { + if (gmac_get_tx_status(GMAC) & GMAC_TX_ERRORS) + { + ++txErrorCount; LWIP_DEBUGF(NETIF_DEBUG, ("gmac_low_level_output: GMAC ERROR, reinit TX...\n")); gmac_enable_transmit(GMAC, false); @@ -402,20 +426,36 @@ static err_t gmac_low_level_output(struct netif *netif, struct pbuf *p) gmac_enable_transmit(GMAC, true); } - //TODO check buffer is free!!! - //TODO what if message is too long? - - buffer = (uint8_t*)ps_gmac_dev->tx_desc[ps_gmac_dev->us_tx_idx].addr; + while ((ps_gmac_dev->tx_desc[ps_gmac_dev->us_tx_idx].status.val & GMAC_TXD_USED) == 0) + { + ++txBufferNotFreeCount; + delay(1); + } - /* Copy pbuf chain into TX buffer. */ - for (q = p; q != NULL; q = q->next) { - memcpy(buffer, q->payload, q->len); - buffer += q->len; + // Copy pbuf chain into TX buffer + { + uint8_t *buffer = reinterpret_cast<uint8_t*>(ps_gmac_dev->tx_desc[ps_gmac_dev->us_tx_idx].addr); + size_t totalLength = 0; + for (const pbuf *q = p; q != NULL; q = q->next) + { + totalLength += q->len; + if (totalLength > GMAC_TX_UNITSIZE) + { + ++txBufferTooShortCount; + return ERR_BUF; + } + memcpy(buffer, q->payload, q->len); + buffer += q->len; + } } - /* Set len and mark the buffer to be sent by GMAC. */ - ps_gmac_dev->tx_desc[ps_gmac_dev->us_tx_idx].status.bm.b_len = p->tot_len; - ps_gmac_dev->tx_desc[ps_gmac_dev->us_tx_idx].status.bm.b_used = 0; + // Set length and mark the buffer to be sent by GMAC + uint32_t txStat = p->tot_len | GMAC_TXD_LAST; + if (ps_gmac_dev->us_tx_idx == GMAC_TX_BUFFERS - 1) + { + txStat |= GMAC_TXD_WRAP; + } + ps_gmac_dev->tx_desc[ps_gmac_dev->us_tx_idx].status.val = txStat; LWIP_DEBUGF(NETIF_DEBUG, ("gmac_low_level_output: DMA buffer sent, size=%d [idx=%u]\n", @@ -442,50 +482,56 @@ static err_t gmac_low_level_output(struct netif *netif, struct pbuf *p) * \return a pbuf filled with the received packet (including MAC header). * 0 on memory error. */ -static struct pbuf *gmac_low_level_input(struct netif *netif) +static pbuf *gmac_low_level_input(struct netif *netif) { - struct gmac_device *ps_gmac_dev = static_cast<gmac_device *>(netif->state); - struct pbuf *p = 0; - uint32_t length = 0; - uint32_t ul_index = 0; - gmac_rx_descriptor_t *p_rx = &ps_gmac_dev->rx_desc[ps_gmac_dev->us_rx_idx]; - - /* Handle GMAC overrun or AHB errors. */ - if (gmac_get_rx_status(GMAC) & GMAC_RX_ERRORS) { + gmac_device *ps_gmac_dev = static_cast<gmac_device *>(netif->state); + if (gmac_get_rx_status(GMAC) & GMAC_RX_ERRORS) + { + // Handle GMAC overrun or AHB errors + ++rxErrorCount; gmac_enable_receive(GMAC, false); LINK_STATS_INC(link.err); LINK_STATS_INC(link.drop); /* Free all RX pbufs. */ - for (ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++) { - if (ps_gmac_dev->rx_pbuf[ul_index] != 0) { + for (uint32_t ul_index = 0; ul_index < GMAC_RX_BUFFERS; ul_index++) + { + if (ps_gmac_dev->rx_pbuf[ul_index] != 0) + { pbuf_free(ps_gmac_dev->rx_pbuf[ul_index]); - ps_gmac_dev->rx_pbuf[ul_index] = 0; + ps_gmac_dev->rx_pbuf[ul_index] = nullptr; } } - /* Reinit TX descriptors. */ + /* Reinit RX descriptors. */ gmac_rx_init(ps_gmac_dev); /* Clear error status. */ gmac_clear_rx_status(GMAC, GMAC_RX_ERRORS); gmac_enable_receive(GMAC, true); + return nullptr; } - /* Check that a packet has been received and processed by GMAC. */ - if ((p_rx->addr.val & GMAC_RXD_OWNERSHIP) == GMAC_RXD_OWNERSHIP) { + volatile gmac_rx_descriptor_t * const p_rx = &ps_gmac_dev->rx_desc[ps_gmac_dev->us_rx_idx]; + pbuf * const p = ((p_rx->addr.val & GMAC_RXD_OWNERSHIP) == GMAC_RXD_OWNERSHIP) + ? ps_gmac_dev->rx_pbuf[ps_gmac_dev->us_rx_idx] + : nullptr; + + /* Check if a packet has been received and processed by GMAC. */ + if (p != nullptr) + { /* Packet is a SOF since packet size is set to maximum. */ - length = p_rx->status.val & GMAC_RXD_LEN_MASK; + const uint32_t length = p_rx->status.val & GMAC_RXD_LEN_MASK; /* Fetch pre-allocated pbuf. */ - p = ps_gmac_dev->rx_pbuf[ps_gmac_dev->us_rx_idx]; p->len = length; - /* Remove this pbuf from its desriptor. */ - ps_gmac_dev->rx_pbuf[ps_gmac_dev->us_rx_idx] = 0; + /* Remove this pbuf from its descriptor. */ + ps_gmac_dev->rx_pbuf[ps_gmac_dev->us_rx_idx] = nullptr; + rxPbufsFullyPopulated = false; LWIP_DEBUGF(NETIF_DEBUG, ("gmac_low_level_input: DMA buffer %p received, size=%u [idx=%u]\n", @@ -495,12 +541,6 @@ static struct pbuf *gmac_low_level_input(struct netif *netif) p->tot_len = length; LINK_STATS_INC(link.recv); - /* Fill empty descriptors with new pbufs. */ - gmac_rx_populate_queue(ps_gmac_dev); - - /* Mark the descriptor ready for transfer. */ - p_rx->addr.val &= ~(GMAC_RXD_OWNERSHIP); - ps_gmac_dev->us_rx_idx = (ps_gmac_dev->us_rx_idx + 1) % GMAC_RX_BUFFERS; #if LWIP_STATS @@ -508,6 +548,12 @@ static struct pbuf *gmac_low_level_input(struct netif *netif) #endif } + /* Fill empty descriptors with new pbufs. */ + if (!rxPbufsFullyPopulated) + { + gmac_rx_populate_queue(ps_gmac_dev, ps_gmac_dev->us_rx_idx); + } + return p; } @@ -519,16 +565,21 @@ static struct pbuf *gmac_low_level_input(struct netif *netif) * * \param pvParameters A pointer to the gmac_device instance. */ -extern "C" void gmac_task(void *pvParameters) +extern "C" [[noreturn]] void gmac_task(void *pvParameters) { gmac_device * const ps_gmac_dev = static_cast<gmac_device*>(pvParameters); + netif * const p_netif = ps_gmac_dev->netif; - while (1) { - /* Process the incoming packets */ - while (ethernetif_input(ps_gmac_dev->netif)) { } + while (1) + { + // Process the incoming packets + { + MutexLocker lock(lwipMutex); + while (ethernetif_input(p_netif)) { } + } - /* Wait for the RX notification from the ISR */ - TaskBase::Take(); + // Wait for the RX notification from the ISR + TaskBase::Take((rxPbufsFullyPopulated) ? 1000 : 20); } } #endif @@ -549,7 +600,7 @@ bool ethernetif_input(struct netif *netif) /* Move received packet into a new pbuf. */ p = gmac_low_level_input(netif); - if (p == NULL) + if (p == nullptr) { return false; } @@ -760,10 +811,12 @@ bool ethernetif_link_established(void) return true; } +#if !LWIP_GMAC_TASK void ethernetif_set_rx_callback(gmac_dev_tx_cb_t callback) { gmac_rx_cb = callback; } +#endif void ethernetif_set_mac_address(const uint8_t macAddress[]) { @@ -777,7 +830,7 @@ void ethernetif_set_mac_address(const uint8_t macAddress[]) extern "C" u32_t millis(); -u32_t sys_now(void) +extern "C" u32_t sys_now(void) { return millis(); } diff --git a/src/Networking/LwipEthernet/GMAC/same70_gmac.h b/src/Networking/LwipEthernet/GMAC/same70_gmac.h index fe263623..7c676ff7 100644 --- a/src/Networking/LwipEthernet/GMAC/same70_gmac.h +++ b/src/Networking/LwipEthernet/GMAC/same70_gmac.h @@ -67,8 +67,10 @@ bool ethernetif_establish_link(void); // attempts to establish link and retu bool ethernetif_link_established(void); // asks the PHY if the link is still up +#if !LWIP_GMAC_TASK typedef void (*gmac_dev_tx_cb_t) (uint32_t ul_status); // copied from gmac_raw.h void ethernetif_set_rx_callback(gmac_dev_tx_cb_t callback); +#endif void ethernetif_set_mac_address(const uint8_t macAddress[]); @@ -78,4 +80,11 @@ void ethernetif_set_mac_address(const uint8_t macAddress[]); } #endif +// Error counters +extern unsigned int rxErrorCount; +extern unsigned int rxBuffersNotFullyPopulatedCount; +extern unsigned int txErrorCount; +extern unsigned int txBufferNotFreeCount; +extern unsigned int txBufferTooShortCount; + #endif /* ETHERNETIF_H_INCLUDED */ diff --git a/src/Networking/LwipEthernet/Lwip/lwipopts.h b/src/Networking/LwipEthernet/Lwip/lwipopts.h index 367f37c8..c2c683c6 100644 --- a/src/Networking/LwipEthernet/Lwip/lwipopts.h +++ b/src/Networking/LwipEthernet/Lwip/lwipopts.h @@ -56,11 +56,8 @@ * use lwIP facilities. * Uses Raw API only. */ -#ifndef LWIP_GMAC_TASK -# error LWIP_GMAC_TASK must be defined in compiler settings -#endif -#define NO_SYS (!LWIP_GMAC_TASK) +#define NO_SYS 1 /** * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface @@ -136,7 +133,7 @@ * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for * reassembly (whole packets, not fragments!) */ -#define MEMP_NUM_REASSDATA 2 +#define MEMP_NUM_REASSDATA 5 /** * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent @@ -167,9 +164,9 @@ #define MEMP_NUM_NETCONN 0 /** - * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. Needs to be enough for IP packet reassembly. */ -#define PBUF_POOL_SIZE (GMAC_RX_BUFFERS + 4) +#define PBUF_POOL_SIZE (GMAC_RX_BUFFERS + GMAC_TX_BUFFERS + 12) /** * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp index c9e14533..f32bf251 100644 --- a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp +++ b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp @@ -46,86 +46,91 @@ const unsigned int MdnsTtl = 10 * 60; // same value as on the Duet 0.6/0.8.5 static LwipEthernetInterface *ethernetInterface; -extern "C" -{ -static volatile bool lwipLocked = false; +#if LWIP_GMAC_TASK + +# include <RTOSIface/RTOSIface.h> +Mutex lwipMutex; -#if !LWIP_GMAC_TASK -static volatile bool resetCallback = false; #endif -// Lock functions for LwIP (LwIP isn't thread-safe when working with the raw API) -bool LockLWIP() +extern "C" { - if (lwipLocked) - { - return false; - } - lwipLocked = true; - return true; -} +#if !LWIP_GMAC_TASK -void UnlockLWIP() -{ - lwipLocked = false; -} + static volatile bool lwipLocked = false; + static volatile bool resetCallback = false; -// Callback functions for the GMAC driver and for LwIP + // Lock functions for LwIP (LwIP isn't thread-safe when working with the raw API) + bool LockLWIP() + { + if (lwipLocked) + { + return false; + } -#if !LWIP_GMAC_TASK + lwipLocked = true; + return true; + } -// Called from ISR -static void ethernet_rx_callback(uint32_t ul_status) -{ - // Because the LWIP stack can become corrupted if we work with it in parallel, - // we may have to wait for the next Spin() call to read the next packet. - if (LockLWIP()) + void UnlockLWIP() { - ethernet_task(); - UnlockLWIP(); + lwipLocked = false; } - else + + // Callback functions for the GMAC driver and for LwIP + + // Called from ISR + static void ethernet_rx_callback(uint32_t ul_status) { - ethernet_set_rx_callback(nullptr); - resetCallback = true; + // Because the LWIP stack can become corrupted if we work with it in parallel, + // we may have to wait for the next Spin() call to read the next packet. + if (LockLWIP()) + { + ethernet_task(); + UnlockLWIP(); + } + else + { + ethernet_set_rx_callback(nullptr); + resetCallback = true; + } } -} -#endif + #endif -// Task function to keep the GMAC and LwIP running -void DoEthernetTask() -{ - ethernet_task(); + // Task function to keep the GMAC and LwIP running + void DoEthernetTask() + { + ethernet_task(); #if !LWIP_GMAC_TASK - if (resetCallback) - { - resetCallback = false; - ethernet_set_rx_callback(ðernet_rx_callback); - } + if (resetCallback) + { + resetCallback = false; + ethernet_set_rx_callback(ðernet_rx_callback); + } #endif -} + } -// Callback functions for LWIP (may be called from ISR) + // Callback functions for LWIP (may be called from ISR) -static err_t conn_accept(void *arg, tcp_pcb *pcb, err_t err) -{ - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(err); - - if (ethernetInterface->ConnectionEstablished(pcb)) + static err_t conn_accept(void *arg, tcp_pcb *pcb, err_t err) { - // A socket has accepted this connection and will deal with it - return ERR_OK; - } + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); - tcp_abort(pcb); - return ERR_ABRT; -} + if (ethernetInterface->ConnectionEstablished(pcb)) + { + // A socket has accepted this connection and will deal with it + return ERR_OK; + } -} + tcp_abort(pcb); + return ERR_ABRT; + } + +} // end extern "C" /*-----------------------------------------------------------------------------------*/ @@ -172,9 +177,13 @@ DEFINE_GET_OBJECT_MODEL_TABLE(LwipEthernetInterface) void LwipEthernetInterface::Init() { - interfaceMutex.Create("Lwip"); + interfaceMutex.Create("LwipIface"); //TODO we don't yet use this mutex anywhere! +#if LWIP_GMAC_TASK + lwipMutex.Create("LwipCore"); +#endif + // Clear the PCBs for (size_t i = 0; i < NumTcpPorts; ++i) { @@ -368,7 +377,7 @@ GCodeResult LwipEthernetInterface::GetNetworkState(const StringRef& reply) void LwipEthernetInterface::Start() { #if defined(DUET3) - digitalWrite(PhyResetPin, true); // being the Ethernet Phy out of reset + digitalWrite(PhyResetPin, true); // bring the Ethernet Phy out of reset #endif if (initialised) @@ -409,8 +418,8 @@ void LwipEthernetInterface::Stop() netif_set_down(&gs_net_if); #if !LWIP_GMAC_TASK resetCallback = false; -#endif ethernet_set_rx_callback(nullptr); +#endif #if defined(DUET3) pinMode(PhyResetPin, OUTPUT_LOW); // hold the Ethernet Phy chip in reset @@ -420,10 +429,14 @@ void LwipEthernetInterface::Stop() } // Main spin loop. If 'full' is true then we are being called from the main spin loop. If false then we are being called during HSMCI idle time. -void LwipEthernetInterface::Spin(bool full) +void LwipEthernetInterface::Spin() { +#if LWIP_GMAC_TASK + MutexLocker lock(lwipMutex); +#else if (LockLWIP()) // basically we can't do anything if we can't interact with LWIP { +#endif switch(state) { case NetworkState::enabled: @@ -456,28 +469,25 @@ void LwipEthernetInterface::Spin(bool full) break; case NetworkState::obtainingIP: - if (full) + if (ethernet_link_established()) { - if (ethernet_link_established()) + // Check for incoming packets + DoEthernetTask(); + + // Have we obtained an IP address yet? + ethernet_get_ipaddress(ipAddress, netmask, gateway); + if (!ipAddress.IsNull()) { - // Check for incoming packets - DoEthernetTask(); - - // Have we obtained an IP address yet? - ethernet_get_ipaddress(ipAddress, netmask, gateway); - if (!ipAddress.IsNull()) - { - // Notify the mDNS responder about this - state = NetworkState::connected; + // Notify the mDNS responder about this + state = NetworkState::connected; // debugPrintf("IP address obtained, network running\n"); - } } - else - { + } + else + { // debugPrintf("Lost phy link\n"); - TerminateSockets(); - state = NetworkState::establishingLink; - } + TerminateSockets(); + state = NetworkState::establishingLink; } break; @@ -487,14 +497,11 @@ void LwipEthernetInterface::Spin(bool full) dhcp_stop(&gs_net_if); } - if (full) - { - InitSockets(); - RebuildMdnsServices(); - ethernet_get_ipaddress(ipAddress, netmask, gateway); - platform.MessageF(NetworkInfoMessage, "Ethernet running, IP address = %s\n", IP4String(ipAddress).c_str()); - state = NetworkState::active; - } + InitSockets(); + RebuildMdnsServices(); + ethernet_get_ipaddress(ipAddress, netmask, gateway); + platform.MessageF(NetworkInfoMessage, "Ethernet running, IP address = %s\n", IP4String(ipAddress).c_str()); + state = NetworkState::active; break; case NetworkState::active: @@ -505,7 +512,7 @@ void LwipEthernetInterface::Spin(bool full) DoEthernetTask(); // Poll the next TCP socket - sockets[nextSocketToPoll]->Poll(full); + sockets[nextSocketToPoll]->Poll(); // Move on to the next TCP socket for next time ++nextSocketToPoll; @@ -520,7 +527,7 @@ void LwipEthernetInterface::Spin(bool full) TerminateDataPort(); } } - else if (full) + else { // debugPrintf("Lost phy link\n"); TerminateSockets(); @@ -528,8 +535,10 @@ void LwipEthernetInterface::Spin(bool full) } break; } +#if !LWIP_GMAC_TASK UnlockLWIP(); } +#endif } void LwipEthernetInterface::Interrupt() @@ -547,6 +556,7 @@ void LwipEthernetInterface::Diagnostics(MessageType mtype) { platform.Message(mtype, "- Ethernet -\n"); platform.MessageF(mtype, "State: %d\n", (int)state); + platform.MessageF(mtype, "Error counts: %u %u %u %u %u\n", rxErrorCount, rxBuffersNotFullyPopulatedCount, txErrorCount, txBufferNotFreeCount, txBufferTooShortCount); platform.Message(mtype, "Socket states:"); for (LwipSocket *s : sockets) { @@ -594,7 +604,11 @@ int LwipEthernetInterface::EnableState() const bool LwipEthernetInterface::InNetworkStack() const { +#if LWIP_GMAC_TASK + return false; +#else return lwipLocked; +#endif } bool LwipEthernetInterface::ConnectionEstablished(tcp_pcb *pcb) diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.h b/src/Networking/LwipEthernet/LwipEthernetInterface.h index 7eacbc29..94ec30e0 100644 --- a/src/Networking/LwipEthernet/LwipEthernetInterface.h +++ b/src/Networking/LwipEthernet/LwipEthernetInterface.h @@ -33,7 +33,7 @@ public: void Init() override; void Activate() override; void Exit() override; - void Spin(bool full) override; + void Spin() override; void Interrupt() override; void Diagnostics(MessageType mtype) override; diff --git a/src/Networking/LwipEthernet/LwipSocket.cpp b/src/Networking/LwipEthernet/LwipSocket.cpp index 786a2db0..69d7bab5 100644 --- a/src/Networking/LwipEthernet/LwipSocket.cpp +++ b/src/Networking/LwipEthernet/LwipSocket.cpp @@ -12,6 +12,9 @@ #include "Networking/NetworkBuffer.h" #include "RepRap.h" +#if LWIP_GMAC_TASK +extern Mutex lwipMutex; +#endif //*************************************************************************************************** @@ -63,8 +66,10 @@ static err_t conn_sent(void *arg, tcp_pcb *pcb, u16_t len) return ERR_OK; } +#if !LWIP_GMAC_TASK extern bool LockLWIP(); extern void UnlockLWIP(); +#endif } @@ -203,6 +208,9 @@ void LwipSocket::Close() { if (state != SocketState::disabled && state != SocketState::listening) { +#if LWIP_GMAC_TASK + MutexLocker lock(lwipMutex); +#endif DiscardReceivedData(); state = SocketState::closing; whenClosed = millis(); @@ -219,6 +227,9 @@ void LwipSocket::Terminate() { if (state != SocketState::disabled) { +#if LWIP_GMAC_TASK + MutexLocker lock(lwipMutex); +#endif if (connectionPcb != nullptr) { tcp_err(connectionPcb, nullptr); @@ -251,11 +262,14 @@ bool LwipSocket::ReadChar(char& c) { if (receivedData != nullptr) { - const char *data = (char *)receivedData->payload; + const char * const data = (const char *)receivedData->payload; c = data[readIndex++]; if (readIndex >= receivedData->len) { +#if LWIP_GMAC_TASK + MutexLocker lock(lwipMutex); +#endif // We've processed one more pbuf if (connectionPcb != nullptr) { @@ -282,7 +296,7 @@ bool LwipSocket::ReadBuffer(const uint8_t *&buffer, size_t &len) { if (receivedData != nullptr) { - const uint8_t *data = (const uint8_t *)receivedData->payload; + const uint8_t * const data = (const uint8_t *)receivedData->payload; buffer = &data[readIndex]; len = receivedData->len - readIndex; return true; @@ -299,6 +313,9 @@ void LwipSocket::Taken(size_t len) readIndex += len; if (readIndex >= receivedData->len) { +#if LWIP_GMAC_TASK + MutexLocker lock(lwipMutex); +#endif // Notify LwIP if (connectionPcb != nullptr) { @@ -316,7 +333,7 @@ void LwipSocket::Taken(size_t len) } // Poll a socket to see if it needs to be serviced -void LwipSocket::Poll(bool full) +void LwipSocket::Poll() { switch (state) { @@ -327,27 +344,24 @@ void LwipSocket::Poll(bool full) case SocketState::connected: // A connection has been established, but no responder has been found yet // See if we can assign this socket - if (full) + if (responderFound) { - if (responderFound) + // Are we still waiting for data to be written? + if (whenWritten != 0 && millis() - whenWritten >= MaxWriteTime) { - // Are we still waiting for data to be written? - if (whenWritten != 0 && millis() - whenWritten >= MaxWriteTime) - { - Terminate(); - } + Terminate(); } - else + } + else + { + // Try to find a responder to deal with this connection + if (reprap.GetNetwork().FindResponder(this, protocol)) { - // Try to find a responder to deal with this connection - if (reprap.GetNetwork().FindResponder(this, protocol)) - { - responderFound = true; - } - else if (millis() - whenConnected >= FindResponderTimeout) - { - Terminate(); - } + responderFound = true; + } + else if (millis() - whenConnected >= FindResponderTimeout) + { + Terminate(); } } break; @@ -356,28 +370,25 @@ void LwipSocket::Poll(bool full) case SocketState::closing: // The connection is being closed, but we may be waiting for sent data to be ACKed // or for the received data to be processed by a NetworkResponder - if (full) + if (unAcked == 0 || millis() - whenClosed > MaxAckTime) { - if (unAcked == 0 || millis() - whenClosed > MaxAckTime) + if (connectionPcb != nullptr) { - if (connectionPcb != nullptr) + tcp_err(connectionPcb, nullptr); + tcp_recv(connectionPcb, nullptr); + tcp_sent(connectionPcb, nullptr); + if (unAcked == 0) { - tcp_err(connectionPcb, nullptr); - tcp_recv(connectionPcb, nullptr); - tcp_sent(connectionPcb, nullptr); - if (unAcked == 0) - { - tcp_close(connectionPcb); - } - else - { - tcp_abort(connectionPcb); - } - connectionPcb = nullptr; + tcp_close(connectionPcb); } - - state = (localPort == 0) ? SocketState::disabled : SocketState::listening; + else + { + tcp_abort(connectionPcb); + } + connectionPcb = nullptr; } + + state = (localPort == 0) ? SocketState::disabled : SocketState::listening; } break; @@ -401,13 +412,19 @@ void LwipSocket::DiscardReceivedData() // Send the data, returning the length buffered size_t LwipSocket::Send(const uint8_t *data, size_t length) { +#if LWIP_GMAC_TASK + MutexLocker lock(lwipMutex); +#else // This is always called outside the EthernetInterface::Spin method. Wait for pending ISRs to finish while (!LockLWIP()) { } +#endif if (!CanSend()) { // Don't bother if we cannot send anything at all+ +#if !LWIP_GMAC_TASK UnlockLWIP(); +#endif return 0; } @@ -429,7 +446,9 @@ size_t LwipSocket::Send(const uint8_t *data, size_t length) if (ERR_IS_FATAL(err)) { Terminate(); +#if !LWIP_GMAC_TASK UnlockLWIP(); +#endif return 0; } else if (err == ERR_MEM) @@ -438,7 +457,9 @@ size_t LwipSocket::Send(const uint8_t *data, size_t length) { // The buffers are full - try again later tcp_output(connectionPcb); +#if !LWIP_GMAC_TASK UnlockLWIP(); +#endif return 0; } bytesToSend /= 2; @@ -450,7 +471,9 @@ size_t LwipSocket::Send(const uint8_t *data, size_t length) if (ERR_IS_FATAL(tcp_output(connectionPcb))) { Terminate(); +#if !LWIP_GMAC_TASK UnlockLWIP(); +#endif return 0; } @@ -458,11 +481,15 @@ size_t LwipSocket::Send(const uint8_t *data, size_t length) whenWritten = millis(); unAcked += bytesToSend; +#if !LWIP_GMAC_TASK UnlockLWIP(); +#endif return bytesToSend; } +#if !LWIP_GMAC_TASK UnlockLWIP(); +#endif return 0; } diff --git a/src/Networking/LwipEthernet/LwipSocket.h b/src/Networking/LwipEthernet/LwipSocket.h index 31c5d794..5f9b1f0f 100644 --- a/src/Networking/LwipEthernet/LwipSocket.h +++ b/src/Networking/LwipEthernet/LwipSocket.h @@ -34,7 +34,7 @@ public: // Inherited members of the Socket class void Init(SocketNumber s, Port serverPort, NetworkProtocol p); void TerminateAndDisable() override; - void Poll(bool full) override; + void Poll() override; void Close() override; bool IsClosing() const { return (state == SocketState::closing); } void Terminate() override; diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp index feae781b..038078a4 100644 --- a/src/Networking/Network.cpp +++ b/src/Networking/Network.cpp @@ -307,7 +307,7 @@ extern "C" [[noreturn]]void NetworkLoop(void *) { for (;;) { - reprap.GetNetwork().Spin(true); + reprap.GetNetwork().Spin(); RTOSIface::Yield(); } } @@ -366,32 +366,29 @@ bool Network::IsWiFiInterface(unsigned int interface) const } // Main spin loop. If 'full' is true then we are being called from the main spin loop. If false then we are being called during HSMCI idle time. -void Network::Spin(bool full) +void Network::Spin() { const uint32_t lastTime = StepTimer::GetTimerTicks(); // Keep the network modules running for (NetworkInterface *iface : interfaces) { - iface->Spin(full); + iface->Spin(); } // Poll the responders - if (full) + NetworkResponder *nr = nextResponderToPoll; + bool doneSomething = false; + do { - NetworkResponder *nr = nextResponderToPoll; - bool doneSomething = false; - do + if (nr == nullptr) { - if (nr == nullptr) - { - nr = responders; // 'responders' can't be null at this point - } - doneSomething = nr->Spin(); - nr = nr->GetNext(); - } while (!doneSomething && nr != nextResponderToPoll); - nextResponderToPoll = nr; - } + nr = responders; // 'responders' can't be null at this point + } + doneSomething = nr->Spin(); + nr = nr->GetNext(); + } while (!doneSomething && nr != nextResponderToPoll); + nextResponderToPoll = nr; HttpResponder::CheckSessions(); // time out any sessions that have gone away diff --git a/src/Networking/Network.h b/src/Networking/Network.h index a0b21561..403e65cb 100644 --- a/src/Networking/Network.h +++ b/src/Networking/Network.h @@ -58,7 +58,7 @@ public: void Init(); void Activate(); void Exit(); - void Spin(bool full); + void Spin(); void Interrupt(); void Diagnostics(MessageType mtype); bool InNetworkStack() const; diff --git a/src/Networking/NetworkInterface.h b/src/Networking/NetworkInterface.h index ba417d05..335041d6 100644 --- a/src/Networking/NetworkInterface.h +++ b/src/Networking/NetworkInterface.h @@ -17,7 +17,7 @@ public: virtual void Init() = 0; virtual void Activate() = 0; virtual void Exit() = 0; - virtual void Spin(bool full) = 0; + virtual void Spin() = 0; virtual void Interrupt() { }; virtual void Diagnostics(MessageType mtype) = 0; diff --git a/src/Networking/Socket.h b/src/Networking/Socket.h index 5a0b22ce..c866e770 100644 --- a/src/Networking/Socket.h +++ b/src/Networking/Socket.h @@ -30,7 +30,7 @@ public: Port GetRemotePort() const { return remotePort; } NetworkProtocol GetProtocol() const { return protocol; } - virtual void Poll(bool full) = 0; + virtual void Poll() = 0; virtual void Close() = 0; virtual void Terminate() = 0; virtual void TerminateAndDisable() = 0; diff --git a/src/Networking/W5500Ethernet/W5500Interface.cpp b/src/Networking/W5500Ethernet/W5500Interface.cpp index 0afe772d..f6379a89 100644 --- a/src/Networking/W5500Ethernet/W5500Interface.cpp +++ b/src/Networking/W5500Ethernet/W5500Interface.cpp @@ -247,8 +247,8 @@ void W5500Interface::Stop() } } -// Main spin loop. If 'full' is true then we are being called from the main spin loop. If false then we are being called during HSMCI idle time. -void W5500Interface::Spin(bool full) +// Main spin loop +void W5500Interface::Spin() { switch(state) { @@ -262,7 +262,7 @@ void W5500Interface::Spin(bool full) { MutexLocker lock(interfaceMutex); - if (full && wizphy_getphylink() == PHY_LINK_ON) + if (wizphy_getphylink() == PHY_LINK_ON) { usingDhcp = ipAddress.IsNull(); if (usingDhcp) @@ -283,7 +283,6 @@ void W5500Interface::Spin(bool full) break; case NetworkState::obtainingIP: - if (full) { MutexLocker lock(interfaceMutex); @@ -314,13 +313,10 @@ void W5500Interface::Spin(bool full) break; case NetworkState::connected: - if (full) - { - InitSockets(); - platform.MessageF(NetworkInfoMessage, "Network running, IP address = %s\n", IP4String(ipAddress).c_str()); - mdnsResponder->Announce(); - state = NetworkState::active; - } + InitSockets(); + platform.MessageF(NetworkInfoMessage, "Network running, IP address = %s\n", IP4String(ipAddress).c_str()); + mdnsResponder->Announce(); + state = NetworkState::active; break; case NetworkState::active: @@ -331,7 +327,7 @@ void W5500Interface::Spin(bool full) if (wizphy_getphylink() == PHY_LINK_ON) { // Maintain DHCP - if (full && usingDhcp) + if (usingDhcp) { const uint32_t now = millis(); if (now - lastTickMillis >= 1000) @@ -349,14 +345,11 @@ void W5500Interface::Spin(bool full) } // Poll the next TCP socket - sockets[nextSocketToPoll]->Poll(full); + sockets[nextSocketToPoll]->Poll(); // Keep mDNS alive - mdnsSocket->Poll(full); - if (full) - { - mdnsResponder->Spin(); - } + mdnsSocket->Poll(); + mdnsResponder->Spin(); // Move on to the next TCP socket for next time ++nextSocketToPoll; @@ -365,7 +358,7 @@ void W5500Interface::Spin(bool full) nextSocketToPoll = 0; } } - else if (full) + else { // debugPrintf("Lost phy link\n"); if (usingDhcp) diff --git a/src/Networking/W5500Ethernet/W5500Interface.h b/src/Networking/W5500Ethernet/W5500Interface.h index 870fa7dc..d191c492 100644 --- a/src/Networking/W5500Ethernet/W5500Interface.h +++ b/src/Networking/W5500Ethernet/W5500Interface.h @@ -37,7 +37,7 @@ public: void Init() override; void Activate() override; void Exit() override; - void Spin(bool full) override; + void Spin() override; void Diagnostics(MessageType mtype) override; GCodeResult EnableInterface(int mode, const StringRef& ssid, const StringRef& reply) override; // enable or disable the network diff --git a/src/Networking/W5500Ethernet/W5500Socket.cpp b/src/Networking/W5500Ethernet/W5500Socket.cpp index e07ce8ce..6dd7a133 100644 --- a/src/Networking/W5500Ethernet/W5500Socket.cpp +++ b/src/Networking/W5500Ethernet/W5500Socket.cpp @@ -172,7 +172,7 @@ void W5500Socket::Taken(size_t len) } // Poll a socket to see if it needs to be serviced -void W5500Socket::Poll(bool full) +void W5500Socket::Poll() { if (state != SocketState::disabled) { @@ -205,7 +205,7 @@ void W5500Socket::Poll(bool full) whenConnected = millis(); } - if (full && state == SocketState::listening) // if it is a new connection + if (state == SocketState::listening) // if it is a new connection { if (reprap.GetNetwork().FindResponder(this, protocol)) { diff --git a/src/Networking/W5500Ethernet/W5500Socket.h b/src/Networking/W5500Ethernet/W5500Socket.h index bc00827f..c0750289 100644 --- a/src/Networking/W5500Ethernet/W5500Socket.h +++ b/src/Networking/W5500Ethernet/W5500Socket.h @@ -19,7 +19,7 @@ public: W5500Socket(NetworkInterface *iface); void Init(SocketNumber s, Port serverPort, NetworkProtocol p); - void Poll(bool full) override; + void Poll() override; void Close() override; void Terminate() override; void TerminateAndDisable() override; diff --git a/src/Platform.cpp b/src/Platform.cpp index a19e4695..1b66e040 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -564,10 +564,10 @@ void Platform::Init() // If MISO from a MAX31856 board breaks after initialising the MAX31856 then if MISO floats low and reads as all zeros, this looks like a temperature of 0C and no error. // Enable the pullup resistor, with luck this will make it float high instead. -#if defined(APIN_USART_SSPI_MISO) - pinMode(APIN_USART_SSPI_MISO, INPUT_PULLUP); -#elif defined(APIN_SHARED_SPI_MISO) +#if SAM3XA pinMode(APIN_SHARED_SPI_MISO, INPUT_PULLUP); +#else + pinMode(APIN_USART_SSPI_MISO, INPUT_PULLUP); #endif #ifdef PCCB @@ -1951,7 +1951,8 @@ void Platform::Diagnostics(MessageType mtype) MessageF(mtype, "Last software reset %s, reason: %s%s, spinning module %s, available RAM %" PRIu32 " bytes (slot %d)\n", scratchString.c_str(), (srdBuf[slot].resetReason & (uint32_t)SoftwareResetReason::deliberate) ? "deliberate " : "", - reasonText, moduleName[srdBuf[slot].resetReason & 0x1F], srdBuf[slot].neverUsedRam, slot); + reasonText, + GetModuleName(srdBuf[slot].resetReason & 0x1F), srdBuf[slot].neverUsedRam, slot); // Our format buffer is only 256 characters long, so the next 2 lines must be written separately MessageF(mtype, "Software reset code 0x%04x HFSR 0x%08" PRIx32 " CFSR 0x%08" PRIx32 " ICSR 0x%08" PRIx32 " BFAR 0x%08" PRIx32 " SP 0x%08" PRIx32 " Task 0x%08" PRIx32 "\n", diff --git a/src/RepRap.cpp b/src/RepRap.cpp index 940a22b5..299bab24 100644 --- a/src/RepRap.cpp +++ b/src/RepRap.cpp @@ -579,7 +579,7 @@ void RepRap::PrintDebug(MessageType mt) { if ((debug & (1u << i)) != 0) { - platform->MessageF((MessageType)(mt | PushFlag), " %s(%u)", moduleName[i], i); + platform->MessageF((MessageType)(mt | PushFlag), " %s(%u)", GetModuleName(i), i); } } @@ -588,7 +588,7 @@ void RepRap::PrintDebug(MessageType mt) { if ((debug & (1u << i)) == 0) { - platform->MessageF((MessageType)(mt | PushFlag), " %s(%u)", moduleName[i], i); + platform->MessageF((MessageType)(mt | PushFlag), " %s(%u)", GetModuleName(i), i); } } platform->Message(mt, "\n"); diff --git a/src/RepRapFirmware.cpp b/src/RepRapFirmware.cpp index cf171c7d..48cd1517 100644 --- a/src/RepRapFirmware.cpp +++ b/src/RepRapFirmware.cpp @@ -172,7 +172,7 @@ Licence: GPL RepRap reprap; -const char * const moduleName[] = +static const char * const moduleName[] = { "Platform", "Network", @@ -196,6 +196,11 @@ const char * const moduleName[] = static_assert(ARRAY_SIZE(moduleName) == Module::numModules + 1); +const char *GetModuleName(uint8_t module) +{ + return (module < ARRAY_SIZE(moduleName)) ? moduleName[module] : "unknown"; +} + // class MillisTimer members // Start or restart the timer diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h index 3d1ed488..ef6c0f59 100644 --- a/src/RepRapFirmware.h +++ b/src/RepRapFirmware.h @@ -194,10 +194,10 @@ enum Module : uint8_t moduleDisplay = 15, moduleLinuxInterface = 16, numModules = 17, // make this one greater than the last real module number - noModule = 18 + noModule = numModules }; -extern const char * const moduleName[]; +const char *GetModuleName(uint8_t module); // Warn of what's to come, so we can use pointers and references to classes without including the entire header files class Network; diff --git a/src/Storage/CRC32.cpp b/src/Storage/CRC32.cpp index 1d563def..a69df0fe 100644 --- a/src/Storage/CRC32.cpp +++ b/src/Storage/CRC32.cpp @@ -53,17 +53,39 @@ CRC32::CRC32() Reset(); } -inline void CRC32::Update(char c) +void CRC32::Update(char c) { crc = (CRC_32_TAB[(crc ^ c) & 0xFF] ^ (crc >> 8)); } -void CRC32::Update(const char *c, size_t len) +void CRC32::Update(const char *s, size_t len) { - for (size_t i = 0; i < len; ++i) + // The speed of this function affects the speed of file uploads, so make it as fast as possible. Sadly the SAME70 doesn't do hardware CRC calculation. + // Work on a local copy of the crc to avoid storing it all the time + uint32_t locCrc = crc; + const char * const end = s + len; + + // Process any bytes at the start until we reach a dword boundary + while ((reinterpret_cast<uint32_t>(s) & 3) != 0 && s != end) + { + locCrc = (CRC_32_TAB[(locCrc ^ *s++) & 0xFF] ^ (locCrc >> 8)); + } + + const char * const endAligned = s + ((end - s) & ~3); + while (s != endAligned) + { + uint32_t data = *reinterpret_cast<const uint32_t*>(s); + s += 4; + locCrc = (CRC_32_TAB[(locCrc ^ data) & 0xFF] ^ (locCrc >> 8)); + locCrc = (CRC_32_TAB[(locCrc ^ (data >> 8)) & 0xFF] ^ (locCrc >> 8)); + locCrc = (CRC_32_TAB[(locCrc ^ (data >> 16)) & 0xFF] ^ (locCrc >> 8)); + locCrc = (CRC_32_TAB[(locCrc ^ (data >> 24)) & 0xFF] ^ (locCrc >> 8)); + } + while (s != end) { - Update(c[i]); + locCrc = (CRC_32_TAB[(locCrc ^ *s++) & 0xFF] ^ (locCrc >> 8)); } + crc = locCrc; } void CRC32::Reset() diff --git a/src/Tasks.cpp b/src/Tasks.cpp index 396fd6e9..57f81e60 100644 --- a/src/Tasks.cpp +++ b/src/Tasks.cpp @@ -8,7 +8,6 @@ #include "Tasks.h" #include "RepRap.h" #include "Platform.h" -#include "Storage/CRC32.h" #include "Hardware/Cache.h" #include <TaskPriorities.h> @@ -89,6 +88,7 @@ extern "C" [[noreturn]] void AppMain() { pinMode(DiagPin, OUTPUT_LOW); // set up diag LED for debugging and turn it off +#ifndef DEBUG // don't check the CRC of a debug build because debugger breakpoints mess up the CRC // Check the integrity of the firmware by checking the firmware CRC { #ifdef IFLASH_ADDR @@ -111,6 +111,7 @@ extern "C" [[noreturn]] void AppMain() } } } +#endif // Fill the free memory with a pattern so that we can check for stack usage and memory corruption char* heapend = sbrk(0); diff --git a/src/Version.h b/src/Version.h index b984fb0c..e60bf4bc 100644 --- a/src/Version.h +++ b/src/Version.h @@ -20,7 +20,7 @@ #endif #ifndef DATE -# define DATE "2019-11-27b2" +# define DATE "2019-12-01b1" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d" |