diff options
35 files changed, 491 insertions, 240 deletions
diff --git a/Developer-documentation/New ESP8266 WiFi module code for Duet WiFi.odt b/Developer-documentation/New ESP8266 WiFi module code for Duet WiFi.odt Binary files differnew file mode 100644 index 00000000..4285cce9 --- /dev/null +++ b/Developer-documentation/New ESP8266 WiFi module code for Duet WiFi.odt diff --git a/Release/Duet-Ethernet/Edge/DuetWebControl-1.14a.zip b/Release/Duet-0.6-0.8.5/Edge/DuetWebControl-1.15-b2.zip Binary files differindex 18e5ba2c..b9ff2f4a 100644 --- a/Release/Duet-Ethernet/Edge/DuetWebControl-1.14a.zip +++ b/Release/Duet-0.6-0.8.5/Edge/DuetWebControl-1.15-b2.zip diff --git a/Release/Duet-0.6-0.8.5/Edge/RepRapFirmware-1.18beta3.bin b/Release/Duet-0.6-0.8.5/Edge/RepRapFirmware-1.18beta3.bin Binary files differnew file mode 100644 index 00000000..b522c1fa --- /dev/null +++ b/Release/Duet-0.6-0.8.5/Edge/RepRapFirmware-1.18beta3.bin diff --git a/Release/Duet-Ethernet/Edge/DuetEthernetFirmware-1.18alpha2.bin b/Release/Duet-Ethernet/Edge/DuetEthernetFirmware-1.18alpha2.bin Binary files differdeleted file mode 100644 index 718c0bc7..00000000 --- a/Release/Duet-Ethernet/Edge/DuetEthernetFirmware-1.18alpha2.bin +++ /dev/null diff --git a/Release/Duet-Ethernet/Edge/DuetEthernetFirmware-1.18beta3.bin b/Release/Duet-Ethernet/Edge/DuetEthernetFirmware-1.18beta3.bin Binary files differnew file mode 100644 index 00000000..6bd8aa99 --- /dev/null +++ b/Release/Duet-Ethernet/Edge/DuetEthernetFirmware-1.18beta3.bin diff --git a/Release/Duet-Ethernet/Edge/DuetWebControl-1.15-b2.zip b/Release/Duet-Ethernet/Edge/DuetWebControl-1.15-b2.zip Binary files differnew file mode 100644 index 00000000..b9ff2f4a --- /dev/null +++ b/Release/Duet-Ethernet/Edge/DuetWebControl-1.15-b2.zip diff --git a/Release/Duet-WiFi/Edge/DuetWebControl-1.15-b2.bin b/Release/Duet-WiFi/Edge/DuetWebControl-1.15-b2.bin Binary files differnew file mode 100644 index 00000000..aa52cfcd --- /dev/null +++ b/Release/Duet-WiFi/Edge/DuetWebControl-1.15-b2.bin diff --git a/Release/Duet-WiFi/Edge/DuetWiFiFirmware-1.18beta3.bin b/Release/Duet-WiFi/Edge/DuetWiFiFirmware-1.18beta3.bin Binary files differnew file mode 100644 index 00000000..3e440ac3 --- /dev/null +++ b/Release/Duet-WiFi/Edge/DuetWiFiFirmware-1.18beta3.bin diff --git a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17a.bin b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17a.bin Binary files differdeleted file mode 100644 index 52507c43..00000000 --- a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17a.bin +++ /dev/null diff --git a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17b.bin b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17b.bin Binary files differdeleted file mode 100644 index 85feeda5..00000000 --- a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17b.bin +++ /dev/null diff --git a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17c.bin b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17c.bin Binary files differdeleted file mode 100644 index bb3d11de..00000000 --- a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.17c.bin +++ /dev/null diff --git a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18alpha2.bin b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18alpha2.bin Binary files differdeleted file mode 100644 index fd0b872a..00000000 --- a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18alpha2.bin +++ /dev/null diff --git a/Release/RADDS/Edge/RepRapFirmware-1.18beta2.bin b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18beta2.bin Binary files differindex 2dd10462..2dd10462 100644 --- a/Release/RADDS/Edge/RepRapFirmware-1.18beta2.bin +++ b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18beta2.bin diff --git a/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18beta3.bin b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18beta3.bin Binary files differnew file mode 100644 index 00000000..519afe48 --- /dev/null +++ b/Release/RADDS/Edge/RepRapFirmware-RADDS-1.18beta3.bin diff --git a/src/Configuration.h b/src/Configuration.h index dd1dc3e0..8a1dd091 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -44,7 +44,7 @@ const float NEARLY_ABS_ZERO = -273.0; // Celsius const float ROOM_TEMPERATURE = 21.0; // Celsius const float LONG_TIME = 300.0; // Seconds -const float MINIMUM_TOOL_WARNING_INTERVAL = 4.0; // Seconds +const uint32_t MinimumWarningInterval = 4000; // Milliseconds // Comms defaults @@ -114,11 +114,13 @@ const unsigned int DefaultPinWritePwmFreq = 500; // default PWM frequency for M4 // So 16 points need 704 bytes of stack space. #ifdef DUET_NG const size_t MaxGridProbePoints = 441; // 441 allows us to probe e.g. 400x400 at 20mm intervals -const size_t MaxProbePoints = 64; // Maximum number of probe points +const size_t MaxXGridPoints = 41; // Maximum number of grid points in one X row +const size_t MaxProbePoints = 64; // Maximum number of G30 probe points const size_t MaxDeltaCalibrationPoints = 64; // Should a power of 2 for speed #else const size_t MaxGridProbePoints = 121; // 121 allows us to probe 200x200 at 20mm intervals -const size_t MaxProbePoints = 32; // Maximum number of probe points +const size_t MaxXGridPoints = 21; // Maximum number of grid points in one X row +const size_t MaxProbePoints = 32; // Maximum number of G30 probe points const size_t MaxDeltaCalibrationPoints = 32; // Should a power of 2 for speed #endif diff --git a/src/DuetNG/DuetEthernet/Network.cpp b/src/DuetNG/DuetEthernet/Network.cpp index 4bb45f3c..ea27bc86 100644 --- a/src/DuetNG/DuetEthernet/Network.cpp +++ b/src/DuetNG/DuetEthernet/Network.cpp @@ -12,6 +12,10 @@ #include "wizchip_conf.h" #include "Wiznet/Internet/DHCP/dhcp.h" +const size_t HttpProtocolIndex = 0, FtpProtocolIndex = 1, TelnetProtocolIndex = 2; // index of theHTTP service above +const Port DefaultPortNumbers[NumProtocols] = { DefaultHttpPort, DefaultFtpPort, DefaultTelnetPort }; +const char * const ProtocolNames[NumProtocols] = { "HTTP", "FTP", "TELNET" }; + void Network::SetIPAddress(const uint8_t p_ipAddress[], const uint8_t p_netmask[], const uint8_t p_gateway[]) { memcpy(ipAddress, p_ipAddress, sizeof(ipAddress)); @@ -21,8 +25,13 @@ void Network::SetIPAddress(const uint8_t p_ipAddress[], const uint8_t p_netmask[ Network::Network(Platform* p) : platform(p), lastTickMillis(0), - httpPort(DefaultHttpPort), state(NetworkState::disabled), activated(false) + state(NetworkState::disabled), activated(false) { + for (size_t i = 0; i < NumProtocols; ++i) + { + portNumbers[i] = DefaultPortNumbers[i]; + protocolEnabled[i] = (i == HttpProtocolIndex); + } } void Network::Init() @@ -40,6 +49,136 @@ void Network::Init() strcpy(hostname, HOSTNAME); } +void Network::EnableProtocol(int protocol, int port, int secure, StringRef& reply) +{ + if (secure != 0 && secure != -1) + { + reply.copy("Error: this firmware does not support TLS"); + } + else if (protocol >= 0 && protocol < (int)NumProtocols) + { + const Port portToUse = (port < 0) ? DefaultPortNumbers[protocol] : port; + if (portToUse != portNumbers[protocol] && state == NetworkState::active) + { + // We need to shut down and restart the protocol if it is active because the port number has changed + ShutdownProtocol(protocol); + protocolEnabled[protocol] = false; + } + portNumbers[protocol] = portToUse; + if (!protocolEnabled[protocol]) + { + protocolEnabled[protocol] = true; + if (state == NetworkState::active) + { + StartProtocol(protocol); +#if 0 // mdns not implemented yet + if (state == NetworkState::active) + { + DoMdnsAnnounce(); + } +#endif + } + } + ReportOneProtocol(protocol, reply); + } + else + { + reply.copy("Invalid protocol parameter"); + } +} + +void Network::DisableProtocol(int protocol, StringRef& reply) +{ + if (protocol >= 0 && protocol < (int)NumProtocols) + { + if (state == NetworkState::active) + { + ShutdownProtocol(protocol); + } + protocolEnabled[protocol] = false; + ReportOneProtocol(protocol, reply); + } + else + { + reply.copy("Invalid protocol parameter"); + } +} + +void Network::StartProtocol(size_t protocol) +{ + switch(protocol) + { + case HttpProtocolIndex: + for (SocketNumber skt = 0; skt < NumHttpSockets; ++skt) + { + sockets[skt].Init(skt, portNumbers[HttpProtocolIndex]); + } + break; + + case FtpProtocolIndex: + sockets[FtpSocketNumber].Init(FtpSocketNumber, portNumbers[FtpProtocolIndex]); + break; + + case TelnetProtocolIndex: + sockets[TelnetSocketNumber].Init(TelnetSocketNumber, portNumbers[TelnetProtocolIndex]); + break; + + default: + break; + } +} + +void Network::ShutdownProtocol(size_t protocol) +{ + switch(protocol) + { + case HttpProtocolIndex: + for (SocketNumber skt = 0; skt < NumHttpSockets; ++skt) + { + sockets[skt].TerminateAndDisable(); + } + break; + + case FtpProtocolIndex: + sockets[FtpSocketNumber].TerminateAndDisable(); + sockets[FtpDataSocketNumber].TerminateAndDisable(); + break; + + case TelnetProtocolIndex: + sockets[TelnetSocketNumber].TerminateAndDisable(); + break; + + default: + break; + } +} + +// Report the protocols and ports in use +void Network::ReportProtocols(StringRef& reply) const +{ + reply.Clear(); + for (size_t i = 0; i < NumProtocols; ++i) + { + if (i != 0) + { + reply.cat('\n'); + } + ReportOneProtocol(i, reply); + } +} + +void Network::ReportOneProtocol(size_t protocol, StringRef& reply) const +{ + if (protocolEnabled[protocol]) + { + reply.catf("%s is enabled on port %u", ProtocolNames[protocol], portNumbers[protocol]); + } + else + { + reply.catf("%s is disabled", ProtocolNames[protocol]); + } +} + // This is called at the end of config.g processing. // Start the network if it was enabled void Network::Activate() @@ -81,8 +220,8 @@ void Network::Spin(bool full) else { // debugPrintf("Link established, network running\n"); - InitSockets(); state = NetworkState::active; + InitSockets(); } } break; @@ -106,8 +245,8 @@ void Network::Spin(bool full) // Send mDNS announcement so that some routers can perform hostname mapping // if this board is connected via a non-IGMP capable WiFi bridge (like the TP-Link WR701N) //mdns_announce(); - InitSockets(); state = NetworkState::active; + InitSockets(); } } else @@ -241,16 +380,6 @@ const uint8_t *Network::GetIPAddress() const return ipAddress; } -void Network::SetHttpPort(uint16_t port) -{ - httpPort = port; -} - -uint16_t Network::GetHttpPort() const -{ - return httpPort; -} - void Network::SetHostname(const char *name) { size_t i = 0; @@ -333,10 +462,19 @@ NetworkTransaction *Network::GetTransaction(Connection conn) return nullptr; } -void Network::OpenDataPort(Port port) +Port Network::GetHttpPort() const { - sockets[FtpDataSocketNumber].Init(FtpDataSocketNumber, port); - sockets[FtpDataSocketNumber].Poll(false); + return portNumbers[HttpProtocolIndex]; +} + +Port Network::GetFtpPort() const +{ + return portNumbers[FtpProtocolIndex]; +} + +Port Network::GetTelnetPort() const +{ + return portNumbers[TelnetProtocolIndex]; } Port Network::GetDataPort() const @@ -344,6 +482,13 @@ Port Network::GetDataPort() const return sockets[FtpDataSocketNumber].GetLocalPort(); } +void Network::OpenDataPort(Port port) +{ + sockets[FtpDataSocketNumber].Init(FtpDataSocketNumber, port); + delayMicroseconds(100); // give the W5500 time to process the command (not sure we need this) + sockets[FtpDataSocketNumber].Poll(true); +} + // Close FTP data port and purge associated PCB void Network::CloseDataPort() { @@ -366,13 +511,13 @@ bool Network::AcquireTransaction(size_t socketNumber) void Network::InitSockets() { - for (SocketNumber skt = 0; skt < NumHttpSockets; ++skt) + for (size_t i = 0; i < NumProtocols; ++i) { - sockets[skt].Init(skt, httpPort); + if (protocolEnabled[i]) + { + StartProtocol(i); + } } - sockets[FtpSocketNumber].Init(FtpSocketNumber, FTP_PORT); - sockets[FtpDataSocketNumber].Init(FtpDataSocketNumber, 0); // FTP data port is allocated dynamically - sockets[TelnetSocketNumber].Init(TelnetSocketNumber, TELNET_PORT); nextSocketToPoll = currentTransactionSocketNumber = 0; } diff --git a/src/DuetNG/DuetEthernet/Network.h b/src/DuetNG/DuetEthernet/Network.h index 7a847494..f35ab055 100644 --- a/src/DuetNG/DuetEthernet/Network.h +++ b/src/DuetNG/DuetEthernet/Network.h @@ -22,6 +22,8 @@ const SocketNumber TelnetSocketNumber = 6; const size_t NumTcpSockets = 7; const SocketNumber DhcpSocketNumber = 7; // TODO can we allocate this dynamically when required, to allow more http sockets most of the time? +const size_t NumProtocols = 3; // number of network protocols we support + class Platform; // The main network class that drives the network. @@ -40,6 +42,10 @@ public: void Start(); void Stop(); + void EnableProtocol(int protocol, int port, int secure, StringRef& reply); + void DisableProtocol(int protocol, StringRef& reply); + void ReportProtocols(StringRef& reply) const; + bool Lock(); void Unlock(); bool InLwip() const; @@ -48,8 +54,9 @@ public: void Disable(); bool IsEnabled() const; - void SetHttpPort(Port port); Port GetHttpPort() const; + Port GetFtpPort() const; + Port GetTelnetPort() const; void SetHostname(const char *name); @@ -94,6 +101,15 @@ private: bool AcquireTransaction(size_t socketNumber) pre(socketNumber < NumTcpSockets); + void StartProtocol(size_t protocol) + pre(protocol < NumProtocols); + + void ShutdownProtocol(size_t protocol) + pre(protocol < NumProtocols); + + void ReportOneProtocol(size_t protocol, StringRef& reply) const + pre(protocol < NumProtocols); + Platform * const platform; float longWait; uint32_t lastTickMillis; @@ -102,15 +118,17 @@ private: size_t nextSocketToPoll; // next TCP socket number to poll for read/write operations size_t currentTransactionSocketNumber; // the socket number of the last transaction we passed to the web server - Port httpPort; - uint8_t ipAddress[4]; - uint8_t netmask[4]; - uint8_t gateway[4]; - char hostname[16]; // Limit DHCP hostname to 15 characters + terminating 0 + Port portNumbers[NumProtocols]; // port number used for each protocol + bool protocolEnabled[NumProtocols]; // whether each protocol is enabled NetworkState state; bool activated; bool usingDhcp; + + uint8_t ipAddress[4]; + uint8_t netmask[4]; + uint8_t gateway[4]; + char hostname[16]; // Limit DHCP hostname to 15 characters + terminating 0 }; #endif diff --git a/src/DuetNG/DuetEthernet/NetworkBuffer.h b/src/DuetNG/DuetEthernet/NetworkBuffer.h index b7ffcc0a..17b39f79 100644 --- a/src/DuetNG/DuetEthernet/NetworkBuffer.h +++ b/src/DuetNG/DuetEthernet/NetworkBuffer.h @@ -47,6 +47,9 @@ public: // Clear this buffer and release any successors void Empty(); + // Reset the data pointer to the start of the buffer + void ResetPointer() { readPointer = 0; } + // Append a buffer to a list static void AppendToList(NetworkBuffer **list, NetworkBuffer *b); diff --git a/src/DuetNG/DuetEthernet/NetworkDefs.h b/src/DuetNG/DuetEthernet/NetworkDefs.h index e752f96a..ad175ba2 100644 --- a/src/DuetNG/DuetEthernet/NetworkDefs.h +++ b/src/DuetNG/DuetEthernet/NetworkDefs.h @@ -30,8 +30,8 @@ const uint8_t DefaultNetMask[4] = { 255, 255, 255, 0 }; const uint8_t DefaultGateway[4] = { 0, 0, 0, 0 }; const Port DefaultHttpPort = 80; -const Port FTP_PORT = 21; -const Port TELNET_PORT = 23; +const Port DefaultFtpPort = 21; +const Port DefaultTelnetPort = 23; const unsigned int TCP_MSS = 1460; diff --git a/src/DuetNG/DuetEthernet/NetworkTransaction.cpp b/src/DuetNG/DuetEthernet/NetworkTransaction.cpp index 9012f1f8..0a4267a0 100644 --- a/src/DuetNG/DuetEthernet/NetworkTransaction.cpp +++ b/src/DuetNG/DuetEthernet/NetworkTransaction.cpp @@ -254,7 +254,11 @@ void NetworkTransaction::Commit(bool keepConnectionAlive) // void NetworkTransaction::Defer(DeferralMode mode) { - if (mode == DeferralMode::DiscardData) + if (mode == DeferralMode::ResetData) + { + cs->ResetDataPointer(); + } + else if (mode == DeferralMode::DiscardData) { cs->DiscardReceivedData(); // discard the incoming data, because we don't need to process it any more } diff --git a/src/DuetNG/DuetEthernet/Socket.cpp b/src/DuetNG/DuetEthernet/Socket.cpp index b39b4c7e..bfc019dc 100644 --- a/src/DuetNG/DuetEthernet/Socket.cpp +++ b/src/DuetNG/DuetEthernet/Socket.cpp @@ -17,7 +17,7 @@ //*************************************************************************************************** // Socket class -Socket::Socket() : currentTransaction(nullptr), receivedData(nullptr), state(SocketState::inactive) +Socket::Socket() : currentTransaction(nullptr), receivedData(nullptr), state(SocketState::disabled) { } @@ -29,6 +29,12 @@ void Socket::Init(SocketNumber skt, Port serverPort) ReInit(); } +void Socket::TerminateAndDisable() +{ + Terminate(); + state = SocketState::disabled; +} + void Socket::ReInit() { // Discard any received data @@ -66,19 +72,26 @@ void Socket::ReleaseTransaction() // Terminate a connection immediately void Socket::Terminate() { - disconnectNoWait(socketNum); - isTerminated = true; - state = SocketState::inactive; - while (receivedData != nullptr) + if (state != SocketState::disabled) { - receivedData = receivedData->Release(); + disconnectNoWait(socketNum); + isTerminated = true; + state = SocketState::inactive; + while (receivedData != nullptr) + { + receivedData = receivedData->Release(); + } + ReleaseTransaction(); } - ReleaseTransaction(); } // Test whether we have a connection on this socket bool Socket::IsConnected() const { + if (state == SocketState::disabled) + { + return false; + } const uint8_t stat = getSn_SR(socketNum); return stat == SOCK_ESTABLISHED || stat == SOCK_CLOSE_WAIT; } @@ -86,12 +99,20 @@ bool Socket::IsConnected() const // Return true if there is or may soon be more data to read bool Socket::HasMoreDataToRead() const { + if (state == SocketState::disabled) + { + return false; + } return (receivedData != nullptr && receivedData->TotalRemaining() != 0) // already have more data || getSn_SR(socketNum) == SOCK_ESTABLISHED; // still fully connected, so we may receive more } bool Socket::CanWrite() const { + if (state == SocketState::disabled) + { + return false; + } const uint8_t stat = getSn_SR(socketNum); return stat == SOCK_ESTABLISHED || stat == SOCK_CLOSE_WAIT; } @@ -146,151 +167,151 @@ bool Socket::ReadBuffer(const char *&buffer, size_t &len) // Poll a socket to see if it needs to be serviced void Socket::Poll(bool full) { - // The mechanism used by class OutputBuffer and now by NetworkBuffer of marking data taken as soon as we return a pointer to it - // is DANGEROUS and will have to be rewritten for RTOS. We need to recycle empty buffers, otherwise multiple file uploads get stalled. - // However, we MUST NOT do this until the data had DEFINITELY been finished with. Temporarily use this conditional to avoid a bug - // with data corruption when this is not the case. - if (full) + if (state != SocketState::disabled) { - // Recycle any receive buffers that are now empty - while (receivedData != nullptr && receivedData->IsEmpty()) + // The mechanism used by class OutputBuffer and now by NetworkBuffer of marking data taken as soon as we return a pointer to it + // is DANGEROUS and will have to be rewritten for RTOS. We need to recycle empty buffers, otherwise multiple file uploads get stalled. + // However, we MUST NOT do this until the data had DEFINITELY been finished with. Temporarily use this conditional to avoid a bug + // with data corruption when this is not the case. + if (full) { - receivedData = receivedData->Release(); // discard empty buffer at head of chain + // Recycle any receive buffers that are now empty + while (receivedData != nullptr && receivedData->IsEmpty()) + { + receivedData = receivedData->Release(); // discard empty buffer at head of chain + } } - } - switch(getSn_SR(socketNum)) - { - case SOCK_INIT: - // Socket has been initialised but is not listening yet - if (localPort != 0) // localPort for the FTP data socket is 0 until we have decided what port number to use + switch(getSn_SR(socketNum)) { - ExecCommand(socketNum, Sn_CR_LISTEN); - state = SocketState::listening; - } - break; + case SOCK_INIT: + // Socket has been initialised but is not listening yet + if (localPort != 0) // localPort for the FTP data socket is 0 until we have decided what port number to use + { + ExecCommand(socketNum, Sn_CR_LISTEN); + state = SocketState::listening; + } + break; - case SOCK_LISTEN: // Socket is listening but no client has connected to it yet - break; + case SOCK_LISTEN: // Socket is listening but no client has connected to it yet + break; - case SOCK_ESTABLISHED: // A client is connected to this socket - if (getSn_IR(socketNum) & Sn_IR_CON) - { - // New connection, so retrieve the sending IP address and port, and clear the interrupt - getSn_DIPR(socketNum, reinterpret_cast<uint8_t*>(&remoteIPAddress)); - remotePort = getSn_DPORT(socketNum); - setSn_IR(socketNum, Sn_IR_CON); - } + case SOCK_ESTABLISHED: // A client is connected to this socket + if (getSn_IR(socketNum) & Sn_IR_CON) + { + // New connection, so retrieve the sending IP address and port, and clear the interrupt + getSn_DIPR(socketNum, reinterpret_cast<uint8_t*>(&remoteIPAddress)); + remotePort = getSn_DPORT(socketNum); + setSn_IR(socketNum, Sn_IR_CON); + } - if (state == SocketState::listening) // if it is a new connection - { - if (socketNum == FtpSocketNumber || socketNum == FtpDataSocketNumber || socketNum == TelnetSocketNumber) + if (state == SocketState::listening) // if it is a new connection { - // FTP and Telnet protocols need a connection reply, so tell the Webserver module about the new connection - if (currentTransaction == nullptr) + if (socketNum == FtpSocketNumber || socketNum == FtpDataSocketNumber || socketNum == TelnetSocketNumber) { - currentTransaction = NetworkTransaction::Allocate(); - if (currentTransaction != nullptr) + // FTP and Telnet protocols need a connection reply, so tell the Webserver module about the new connection + if (currentTransaction == nullptr) { - currentTransaction->Set(this, TransactionStatus::connected); + currentTransaction = NetworkTransaction::Allocate(); + if (currentTransaction != nullptr) + { + currentTransaction->Set(this, TransactionStatus::connected); + } + } + else + { + // This should not happen +// debugPrintf("ERROR:currentTransation should be null but isn't\n"); } } - else + state = SocketState::connected; + } + + { + // See if the socket has received any data + const uint16_t len = getSn_RX_RSR(socketNum); + if (len != 0) { - // This should not happen -// debugPrintf("ERROR:currentTransation should be null but isn't\n"); +// debugPrintf("%u available\n", len); + // There is data available, so allocate a buffer + //TODO: if there is already a buffer and it is in an appropriate state (i.e. receiving) and it has enough room, we could just append the data + NetworkBuffer * const buf = NetworkBuffer::Allocate(); + if (buf != nullptr) + { + wiz_recv_data(socketNum, buf->Data(), len); + ExecCommand(socketNum, Sn_CR_RECV); + buf->dataLength = (size_t)len; + buf->readPointer = 0; + NetworkBuffer::AppendToList(&receivedData, buf); + } +// else debugPrintf("no buffer\n"); } } - state = SocketState::connected; - } - { - // See if the socket has received any data - const uint16_t len = getSn_RX_RSR(socketNum); - if (len != 0) + if (currentTransaction == nullptr && receivedData != nullptr) { -// debugPrintf("%u available\n", len); - // There is data available, so allocate a buffer - //TODO: if there is already a buffer and it is in an appropriate state (i.e. receiving) and it has enough room, we could just append the data - NetworkBuffer * const buf = NetworkBuffer::Allocate(); - if (buf != nullptr) + currentTransaction = NetworkTransaction::Allocate(); + if (currentTransaction != nullptr) { - wiz_recv_data(socketNum, buf->Data(), len); - ExecCommand(socketNum, Sn_CR_RECV); - buf->dataLength = (size_t)len; - buf->readPointer = 0; - NetworkBuffer::AppendToList(&receivedData, buf); + currentTransaction->Set(this, TransactionStatus::receiving); } -// else debugPrintf("no buffer\n"); } - } - if (currentTransaction == nullptr && receivedData != nullptr) - { - currentTransaction = NetworkTransaction::Allocate(); - if (currentTransaction != nullptr) + // See if we can send any data. + // Currently we don't send if we are being called from hsmci because we don't want to risk releasing a buffer that we may be reading data into. + // We could use a buffer locking mechanism instead. However, the speed of sending is not critical, so we don't do that yet. + if (full && IsSending() && TrySendData()) { - currentTransaction->Set(this, TransactionStatus::receiving); + const bool closeAfterSending = currentTransaction->CloseAfterSending(); + ReleaseTransaction(); + if (closeAfterSending) + { + ExecCommand(socketNum, Sn_CR_DISCON); + state = SocketState::closing; + DiscardReceivedData(); + } } - } + break; - // See if we can send any data. - // Currently we don't send if we are being called from hsmci because we don't want to risk releasing a buffer that we may be reading data into. - // We could use a buffer locking mechanism instead. However, the speed of sending is not critical, so we don't do that yet. - if (full && IsSending() && TrySendData()) - { - const bool closeAfterSending = currentTransaction->CloseAfterSending(); - ReleaseTransaction(); - if (closeAfterSending) + case SOCK_CLOSE_WAIT: // A client has asked to disconnect + state = SocketState::clientDisconnecting; + if (IsSending() && TrySendData()) { - ExecCommand(socketNum, Sn_CR_DISCON); - state = SocketState::closing; - DiscardReceivedData(); + ReleaseTransaction(); // finished sending } - } - break; - - case SOCK_CLOSE_WAIT: // A client has asked to disconnect -#ifdef _HTTPSERVER_DEBUG_ - printf("> HTTPSocket[%d] : ClOSE_WAIT\r\n", socketNum); -#endif - state = SocketState::clientDisconnecting; - if (IsSending() && TrySendData()) - { - ReleaseTransaction(); // finished sending - } - // Although there is a transaction status for a client disconnecting, the webserver module does nothing with those transactions. - // So we don't bother to generate them here. - if (!IsSending() && currentTransaction == nullptr) - { - if (HasMoreDataToRead()) + // Although there is a transaction status for a client disconnecting, the webserver module does nothing with those transactions. + // So we don't bother to generate them here. + if (!IsSending() && currentTransaction == nullptr) { - // We have more received data, so make it available to the webserver to process - currentTransaction = NetworkTransaction::Allocate(); - if (currentTransaction != nullptr) + if (HasMoreDataToRead()) { - currentTransaction->Set(this, TransactionStatus::receiving); + // We have more received data, so make it available to the webserver to process + currentTransaction = NetworkTransaction::Allocate(); + if (currentTransaction != nullptr) + { + currentTransaction->Set(this, TransactionStatus::receiving); + } + } + else + { + ExecCommand(socketNum, Sn_CR_DISCON); + state = SocketState::closing; } } - else + break; + + case SOCK_CLOSED: + if (full) // don't make a call to webserver if we might be in it already { - ExecCommand(socketNum, Sn_CR_DISCON); - state = SocketState::closing; + reprap.GetWebserver()->ConnectionLost(this); // the webserver needs this to be called for both graceful and disgraceful disconnects + ReInit(); } - } - break; + break; - case SOCK_CLOSED: - if (full) // don't make a call to webserver if we might be in it already - { - reprap.GetWebserver()->ConnectionLost(this); // the webserver needs this to be called for both graceful and disgraceful disconnects - ReInit(); + default: + break; } - break; - - default: - break; } } @@ -367,6 +388,14 @@ void Socket::DiscardReceivedData() } } +void Socket::ResetDataPointer() +{ + if (receivedData != nullptr) + { + receivedData->ResetPointer(); + } +} + // The webserver calls this to tell the socket that it needs a transaction, e.g. for sending a Telnet or FTP response. // An empty transaction will do. // Return true if we can do it, false if the connection is closed or closing. diff --git a/src/DuetNG/DuetEthernet/Socket.h b/src/DuetNG/DuetEthernet/Socket.h index 96154a53..a9cc6ee4 100644 --- a/src/DuetNG/DuetEthernet/Socket.h +++ b/src/DuetNG/DuetEthernet/Socket.h @@ -17,6 +17,7 @@ class Socket public: Socket(); void Init(SocketNumber s, Port serverPort); + void TerminateAndDisable(); void Poll(bool full); Port GetLocalPort() const { return localPort; } uint32_t GetRemoteIP() const { return remoteIPAddress; } @@ -34,11 +35,13 @@ public: bool IsPersistentConnection() const { return persistConnection; } bool CanWrite() const; void DiscardReceivedData(); + void ResetDataPointer(); bool AcquireTransaction(); private: enum class SocketState : uint8_t { + disabled, inactive, listening, connected, diff --git a/src/DuetNG/DuetEthernet/Webserver.cpp b/src/DuetNG/DuetEthernet/Webserver.cpp index fa11a56a..6a5b5c6d 100644 --- a/src/DuetNG/DuetEthernet/Webserver.cpp +++ b/src/DuetNG/DuetEthernet/Webserver.cpp @@ -150,26 +150,17 @@ void Webserver::Spin() // Take care of different protocol types here ProtocolInterpreter *interpreter; const uint16_t localPort = currentTransaction->GetLocalPort(); - switch (localPort) + if (localPort == network->GetHttpPort()) { - case FTP_PORT: /* FTP */ - interpreter = ftpInterpreter; - break; - - case TELNET_PORT: /* Telnet */ - interpreter = telnetInterpreter; - break; - - default: /* HTTP and FTP data */ - if (localPort == network->GetHttpPort()) - { - interpreter = httpInterpreter; - } - else - { - interpreter = ftpInterpreter; - } - break; + interpreter = httpInterpreter; + } + else if (localPort == network->GetTelnetPort()) + { + interpreter = telnetInterpreter; + } + else + { + interpreter = ftpInterpreter; } // See if we have to print some debug info @@ -345,28 +336,20 @@ void Webserver::ConnectionLost(Connection conn) // Inform protocol handlers that this connection has been lost const uint16_t localPort = Network::GetLocalPort(conn); ProtocolInterpreter *interpreter; - switch (localPort) + if (localPort == network->GetHttpPort()) + { + interpreter = httpInterpreter; + } + else if (localPort == network->GetFtpPort() || localPort == network->GetDataPort()) { - case FTP_PORT: /* FTP */ interpreter = ftpInterpreter; - break; - - case TELNET_PORT: /* Telnet */ + } + else if (localPort == network->GetTelnetPort()) + { interpreter = telnetInterpreter; - break; - - default: /* HTTP and FTP data */ - if (localPort == network->GetHttpPort()) - { - interpreter = httpInterpreter; - break; - } - else if (localPort == network->GetDataPort()) - { - interpreter = ftpInterpreter; - break; - } - + } + else + { platform->MessageF(GENERIC_MESSAGE, "Error: Webserver should handle disconnect event at local port %d, but no handler was found!\n", localPort); return; } @@ -1956,7 +1939,7 @@ void Webserver::FtpInterpreter::ConnectionEstablished() // Is this a new connection on the data port? NetworkTransaction * const transaction = webserver->currentTransaction; - if (transaction->GetLocalPort() != FTP_PORT) + if (transaction->GetLocalPort() != network->GetFtpPort()) { if (state == waitingForPasvPort) { @@ -1995,7 +1978,7 @@ void Webserver::FtpInterpreter::ConnectionLost(Connection conn) { connectedClients--; - if (Network::GetLocalPort(conn) != FTP_PORT) + if (Network::GetLocalPort(conn) != network->GetFtpPort()) { // Did everything work out? Usually this is only called for uploads if (network->AcquireFTPTransaction()) @@ -2196,7 +2179,7 @@ void Webserver::FtpInterpreter::ProcessLine() const uint8_t * const ip_address = network->GetIPAddress(); /* open random port > 1023 */ - uint16_t pasv_port = random(1024, 65535); + const uint16_t pasv_port = random(1024, 65535); network->OpenDataPort(pasv_port); portOpenTime = millis(); state = waitingForPasvPort; @@ -2327,7 +2310,6 @@ void Webserver::FtpInterpreter::ProcessLine() { webserver->currentTransaction->Defer(DeferralMode::ResetData); } - break; case pasvPortConnected: diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h index 8294ea12..f2a64da7 100644 --- a/src/DuetNG/Pins_DuetNG.h +++ b/src/DuetNG/Pins_DuetNG.h @@ -108,6 +108,8 @@ const Pin PowerMonitor5vDetectPin = 29; // AFE1_AD1/PB3 5V regulator inp const float PowerFailVoltageRange = 11.0 * 3.3; // we use an 11:1 voltage divider +const Pin VssaSensePin = 103; + // Digital pin number to turn the IR LED on (high) or off (low) const Pin Z_PROBE_MOD_PIN = 34; // Digital pin number to turn the IR LED on (high) or off (low) on Duet v0.6 and v1.0 (PB21) diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index e4b734f8..f537eb5c 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -60,7 +60,7 @@ void GCodes::RestorePoint::Init() GCodes::GCodes(Platform* p, Webserver* w) : platform(p), webserver(w), active(false), isFlashing(false), - fileBeingHashed(nullptr) + fileBeingHashed(nullptr), lastWarningMillis(0) { httpGCode = new GCodeBuffer("http", HTTP_MESSAGE); telnetGCode = new GCodeBuffer("telnet", TELNET_MESSAGE); @@ -164,7 +164,7 @@ void GCodes::Reset() lastEndstopStates = platform->GetAllEndstopStates(); firmwareUpdateModuleMap = 0; - cancelWait = isWaiting = false; + cancelWait = isWaiting = displayNoToolWarning = displayDeltaNotHomedWarning = false; for (size_t i = 0; i < NumResources; ++i) { @@ -659,6 +659,23 @@ void GCodes::Spin() nextGcodeSource = 0; } + // Check if we need to display a warning + const uint32_t now = millis(); + if (now - lastWarningMillis >= MinimumWarningInterval) + { + if (displayNoToolWarning) + { + platform->Message(GENERIC_MESSAGE, "Attempting to extrude with no tool selected.\n"); + displayNoToolWarning = false; + lastWarningMillis = now; + } + if (displayDeltaNotHomedWarning) + { + platform->Message(GENERIC_MESSAGE, "Attempt to move the head of a delta printer before homing the towers\n"); + displayDeltaNotHomedWarning = false; + lastWarningMillis = now; + } + } platform->ClassReport(longWait); } @@ -1036,7 +1053,7 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType) Tool* const tool = reprap.GetCurrentTool(); if (tool == nullptr) { - platform->Message(GENERIC_MESSAGE, "Attempting to extrude with no tool selected.\n"); + displayNoToolWarning = true; return false; } const size_t eMoveCount = tool->DriveCount(); @@ -1306,7 +1323,7 @@ int GCodes::SetUpMove(GCodeBuffer& gb, StringRef& reply) // This may be damaging and is almost certainly a user mistake, so ignore the move. But allow extruder-only moves. if (gb.Seen(axisLetters[X_AXIS]) || gb.Seen(axisLetters[Y_AXIS]) || gb.Seen(axisLetters[Z_AXIS])) { - reply.copy("Attempt to move the head of a delta printer before homing the towers"); + displayDeltaNotHomedWarning = true; return 1; } } @@ -2181,7 +2198,7 @@ bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply) } else { - reply.copy("ERROR: Wrong number of X values in M577, need 2"); + reply.copy("Wrong number of X values in M577, need 2"); return true; } } @@ -2195,7 +2212,7 @@ bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply) } else { - reply.copy("ERROR: Wrong number of Y values in M577, need 2"); + reply.copy("Wrong number of Y values in M577, need 2"); return true; } } @@ -2223,14 +2240,14 @@ bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply) if (seenX != seenY) { - reply.copy("ERROR: specify both or neither of X and Y in M577"); + reply.copy("specify both or neither of X and Y in M577"); return true; } if (!seenX && !seenR) { // Must have given just the S parameter - reply.copy("ERROR: specify at least radius or X,Y ranges in M577"); + reply.copy("specify at least radius or X,Y ranges in M577"); return true; } @@ -2245,7 +2262,7 @@ bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply) } else { - reply.copy("ERROR: M577 radius must be positive unless X and Y are specified"); + reply.copy("M577 radius must be positive unless X and Y are specified"); return true; } } @@ -2257,8 +2274,10 @@ bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply) } else { - reply.copy("ERROR: bad grid definition: "); - newGrid.PrintError(reply); + const float xRange = (seenX) ? xValues[1] - xValues[0] : 2 * radius; + const float yRange = (seenX) ? yValues[1] - yValues[0] : 2 * radius; + reply.copy("bad grid definition: "); + newGrid.PrintError(xRange, yRange, reply); return true; } } diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index 5b2e1077..ade82841 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -288,7 +288,6 @@ private: size_t probeCount; // Counts multiple probe points int8_t cannedCycleMoveCount; // Counts through internal (i.e. not macro) canned cycle moves bool cannedCycleMoveQueued; // True if a canned cycle move has been set - float longWait; // Timer for things that happen occasionally (seconds) bool limitAxes; // Don't think outside the box. uint32_t axesHomed; // Bitmap of which axes have been homed float pausedFanValues[NUM_FANS]; // Fan speeds when the print was paused @@ -331,8 +330,12 @@ private: bool AdvanceHash(StringRef &reply); // Misc + float longWait; // Timer for things that happen occasionally (seconds) + uint32_t lastWarningMillis; // When we last sent a warning message for things that can happen very often bool isWaiting; // True if waiting to reach temperature bool cancelWait; // Set true to cancel waiting + bool displayNoToolWarning; // True if we need to display a 'no tool selected' warning + bool displayDeltaNotHomedWarning; // True if we need to display a 'attempt to move before homing on a delta printer' message }; //***************************************************************************************************** diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index 44faf305..023ccbb1 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -1825,7 +1825,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) } else { - reply.printf("Baby stepping offset is %.3d", GetBabyStepOffset()); + reply.printf("Baby stepping offset is %.3fmm", GetBabyStepOffset()); } break; diff --git a/src/Movement/Grid.cpp b/src/Movement/Grid.cpp index 2b86f5e4..87e844b4 100644 --- a/src/Movement/Grid.cpp +++ b/src/Movement/Grid.cpp @@ -26,12 +26,13 @@ GridDefinition::GridDefinition(const float xRange[2], const float yRange[2], flo numX = (xMax - xMin >= MinRange && spacing >= MinSpacing) ? (uint32_t)((xMax - xMin) * recipSpacing) + 1 : 0; numY = (yMax - yMin >= MinRange && spacing >= MinSpacing) ? (uint32_t)((yMax - yMin) * recipSpacing) + 1 : 0; CheckValidity(); - } void GridDefinition::CheckValidity() { - isValid = NumPoints() != 0 && NumPoints() <= MaxGridProbePoints && (radius < 0.0 || radius >= 1.0); + isValid = NumPoints() != 0 && NumPoints() <= MaxGridProbePoints + && (radius < 0.0 || radius >= 1.0) + && NumXpoints() <= MaxXGridPoints; } float GridDefinition::GetXCoordinate(unsigned int xIndex) const @@ -84,7 +85,7 @@ bool GridDefinition::ReadParameters(const StringRef& s) } // Print what is wrong with the grid, appending it to the existing string -void GridDefinition::PrintError(StringRef& r) const +void GridDefinition::PrintError(float originalXrange, float originalYrange, StringRef& r) const { if (spacing < MinSpacing) { @@ -98,9 +99,16 @@ void GridDefinition::PrintError(StringRef& r) const { r.cat("Y range too small"); } - else if (numX > MaxGridProbePoints || numY > MaxGridProbePoints || NumPoints() > MaxGridProbePoints) // check X and Y individually in case X*Y overflows + else if ( numX > MaxXGridPoints + || numX > MaxGridProbePoints || numY > MaxGridProbePoints // check X and Y individually in case X*Y overflows + || NumPoints() > MaxGridProbePoints + ) { - r.catf("Too many grid points (maximum %d, needed %d)", MaxGridProbePoints, NumPoints()); + const float totalRange = originalXrange + originalYrange; + const float area = originalXrange * originalYrange; + const float minSpacing = (totalRange + sqrtf(fsquare(totalRange) + 4.0 * (MaxGridProbePoints - 1) * area))/(2.0 * (MaxGridProbePoints - 1)); + const float minXspacing = originalXrange/(MaxXGridPoints - 1); + r.catf("Too many grid points; suggest increase spacing to %.1fmm", max<float>(minSpacing, minXspacing)); } else { @@ -210,7 +218,7 @@ bool HeightMap::SaveToFile(FileStore *f) const // Load the grid from file, returning true if an error occurred with the error reason appended to the buffer bool HeightMap::LoadFromFile(FileStore *f, StringRef& r) { - const size_t MaxLineLength = 200; // maximum length of a line in the height map file + const size_t MaxLineLength = (MaxXGridPoints * 8) + 2; // maximum length of a line in the height map file, need 8 characters per grid point const char* const readFailureText = "failed to read line from file"; char buffer[MaxLineLength + 1]; StringRef s(buffer, ARRAY_SIZE(buffer)); diff --git a/src/Movement/Grid.h b/src/Movement/Grid.h index 84d8b589..f12fe354 100644 --- a/src/Movement/Grid.h +++ b/src/Movement/Grid.h @@ -34,7 +34,7 @@ public: static bool CheckHeading(const StringRef& s); bool ReadParameters(const StringRef& s); - void PrintError(StringRef& r) const + void PrintError(float originalXrange, float originalYrange, StringRef& r) const pre(!IsValid()); private: diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp index f831c0c3..f95a9d62 100644 --- a/src/Movement/Move.cpp +++ b/src/Movement/Move.cpp @@ -184,10 +184,10 @@ void Move::Spin() // We have a new move if (simulationMode < 2) // in simulation mode 2 and higher, we don't process incoming moves beyond this point { - const bool doMotorMapping = (nextMove.moveType == 0); + const bool doMotorMapping = (nextMove.moveType == 0) || (nextMove.moveType == 1 && !IsDeltaMode()); if (doMotorMapping) { - Transform(nextMove.coords, nextMove.xAxes, true); + Transform(nextMove.coords, nextMove.xAxes, nextMove.moveType == 0); } if (ddaRingAddPointer->Init(nextMove, doMotorMapping)) { diff --git a/src/Platform.cpp b/src/Platform.cpp index 9bd9140a..4658f777 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -207,6 +207,9 @@ bool ZProbeParameters::WriteParameters(FileStore *f, unsigned int probeType) con Platform::Platform() : board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0), auxGCodeReply(nullptr), fileStructureInitialised(false), tickState(0), debugCode(0) +#ifdef DUET_NG + , lastWarningMillis(0) +#endif { // Output auxOutput = new OutputStack(); @@ -403,6 +406,21 @@ void Platform::Init() // Initialise TMC2660 driver module driversPowered = false; TMC2660::Init(ENABLE_PINS, numTMC2660Drivers); + + // Set up the VSSA sense pin. Older Duet WiFis don't have it connected, so we enable the pulldown resistor to keep it inactive. + { + pinMode(VssaSensePin, INPUT_PULLUP); + delayMicroseconds(10); + const bool vssaHighVal = digitalRead(VssaSensePin); + pinMode(VssaSensePin, INPUT_PULLDOWN); + delayMicroseconds(10); + const bool vssaLowVal = digitalRead(VssaSensePin); + vssaSenseWorking = vssaLowVal || !vssaHighVal; + if (vssaSenseWorking) + { + pinMode(VssaSensePin, INPUT); + } + } #endif // Allow extrusion ancilliary PWM to use FAN0 even if FAN0 has not been disabled, for backwards compatibility @@ -786,12 +804,28 @@ bool Platform::MustHomeXYBeforeZ() const // Check the prerequisites for updating the main firmware. Return True if satisfied, else print as message and return false. bool Platform::CheckFirmwareUpdatePrerequisites() { - if (!GetMassStorage()->FileExists(GetSysDir(), IAP_FIRMWARE_FILE)) + FileStore * const firmwareFile = GetFileStore(GetSysDir(), IAP_FIRMWARE_FILE, false); + if (firmwareFile == nullptr) { MessageF(GENERIC_MESSAGE, "Error: Firmware binary \"%s\" not found\n", IAP_FIRMWARE_FILE); return false; } + uint32_t firstDword; + bool ok = firmwareFile->Read(reinterpret_cast<char*>(&firstDword), sizeof(firstDword)) == (int)sizeof(firstDword); + firmwareFile->Close(); + if (!ok || firstDword != +#if (SAM4S || SAM4E) + IRAM_ADDR + IRAM_SIZE +#else + IRAM1_ADDR + IRAM1_SIZE +#endif + ) + { + MessageF(GENERIC_MESSAGE, "Error: Firmware binary \"%s\" is not valid for this electronics\n", IAP_FIRMWARE_FILE); + return false; + } + if (!GetMassStorage()->FileExists(GetSysDir(), IAP_UPDATE_FILE)) { MessageF(GENERIC_MESSAGE, "Error: In-application programming binary \"%s\" not found\n", IAP_UPDATE_FILE); @@ -804,7 +838,7 @@ bool Platform::CheckFirmwareUpdatePrerequisites() // Update the firmware. Prerequisites should be checked before calling this. void Platform::UpdateFirmware() { - FileStore *iapFile = GetFileStore(GetSysDir(), IAP_UPDATE_FILE, false); + FileStore * const iapFile = GetFileStore(GetSysDir(), IAP_UPDATE_FILE, false); if (iapFile == nullptr) { MessageF(FIRMWARE_UPDATE_MESSAGE, "IAP not found\n"); @@ -1225,6 +1259,14 @@ void Platform::Spin() driversPowered = true; } TMC2660::SetDriversPowered(driversPowered); + + // Check for a VSSA fault + const uint32_t now = millis(); + if (vssaSenseWorking && now - lastWarningMillis > MinimumWarningInterval && digitalRead(VssaSensePin)) + { + Message(GENERIC_MESSAGE, "Error: VSSA fault\n"); + lastWarningMillis = now; + } #endif // Update the time diff --git a/src/Platform.h b/src/Platform.h index cb0be103..a54c3b71 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -832,7 +832,9 @@ private: volatile uint16_t currentVin, highestVin, lowestVin; uint32_t numUnderVoltageEvents; volatile uint32_t numOverVoltageEvents; + uint32_t lastWarningMillis; // When we last sent a warning message for things that can happen very often bool driversPowered; + bool vssaSenseWorking; #endif // RTC diff --git a/src/Reprap.cpp b/src/Reprap.cpp index 3eee7bc6..004b620c 100644 --- a/src/Reprap.cpp +++ b/src/Reprap.cpp @@ -27,7 +27,7 @@ extern "C" void hsmciIdle() // Do nothing more in the constructor; put what you want in RepRap:Init() -RepRap::RepRap() : toolList(nullptr), currentTool(nullptr), lastToolWarningTime(0.0), activeExtruders(0), +RepRap::RepRap() : toolList(nullptr), currentTool(nullptr), lastWarningMillis(0), activeExtruders(0), activeToolHeaters(0), ticksInSpinState(0), spinningModule(noModule), debug(0), stopped(false), active(false), resetting(false), processingConfig(true), beepFrequency(0), beepDuration(0) { @@ -180,24 +180,27 @@ void RepRap::Spin() ticksInSpinState = 0; // Check if we need to display a cold extrusion warning - - for (Tool *t = toolList; t != nullptr; t = t->Next()) + const uint32_t now = millis(); + if (now - lastWarningMillis >= MinimumWarningInterval) { - if (t->DisplayColdExtrudeWarning() && ToolWarningsAllowed()) + for (Tool *t = toolList; t != nullptr; t = t->Next()) { - platform->MessageF(GENERIC_MESSAGE, "Warning: Tool %d was not driven because its heater temperatures were not high enough or it has a heater fault\n", t->myNumber); + if (t->DisplayColdExtrudeWarning()) + { + platform->MessageF(GENERIC_MESSAGE, "Warning: Tool %d was not driven because its heater temperatures were not high enough or it has a heater fault\n", t->myNumber); + lastWarningMillis = now; + } } } // Keep track of the loop time - const float t = platform->Time(); const float dt = t - lastTime; - if(dt < fastLoop) + if (dt < fastLoop) { fastLoop = dt; } - if(dt > slowLoop) + if (dt > slowLoop) { slowLoop = dt; } @@ -448,19 +451,6 @@ void RepRap::SetToolVariables(int toolNumber, const float* standbyTemperatures, } } -// chrishamm 02-10-2015: I don't think it's a good idea to write tool warning message after every -// short move, so only print them in a reasonable interval. -bool RepRap::ToolWarningsAllowed() -{ - const float now = platform->Time(); - if (now - lastToolWarningTime > MINIMUM_TOOL_WARNING_INTERVAL) - { - lastToolWarningTime = platform->Time(); - return true; - } - return false; -} - bool RepRap::IsHeaterAssignedToTool(int8_t heater) const { for(Tool *tool = toolList; tool != nullptr; tool = tool->Next()) diff --git a/src/Reprap.h b/src/Reprap.h index 194d869c..a79f4089 100644 --- a/src/Reprap.h +++ b/src/Reprap.h @@ -64,7 +64,6 @@ public: Tool* GetCurrentOrDefaultTool() const; uint32_t GetCurrentXAxes() const; // Get the current axes used as X axes void SetToolVariables(int toolNumber, const float* standbyTemperatures, const float* activeTemperatures); - bool ToolWarningsAllowed(); bool IsHeaterAssignedToTool(int8_t heater) const; unsigned int GetNumberOfContiguousTools() const; @@ -119,7 +118,7 @@ private: Tool* toolList; Tool* currentTool; - float lastToolWarningTime; + uint32_t lastWarningMillis; // When we last sent a warning message for things that can happen very often uint16_t activeExtruders; uint16_t activeToolHeaters; diff --git a/src/Version.h b/src/Version.h index 99ebb10a..ce482ede 100644 --- a/src/Version.h +++ b/src/Version.h @@ -9,11 +9,11 @@ #define SRC_VERSION_H_ #ifndef VERSION -# define VERSION "1.18beta2" +# define VERSION "1.18beta3" #endif #ifndef DATE -# define DATE "2017-03-10" +# define DATE "2017-03-16" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman" |