diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Configuration.h | 4 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/Network.cpp | 20 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/Network.h | 2 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/NetworkTransaction.cpp | 6 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/NetworkTransaction.h | 1 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/Socket.cpp | 126 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/Socket.h | 13 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/Wiznet/Ethernet/socketlib.cpp | 4 | ||||
-rw-r--r-- | src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp | 2 | ||||
-rw-r--r-- | src/DuetNG/DuetWiFi/Webserver.cpp | 12 | ||||
-rw-r--r-- | src/Fan.cpp | 8 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.h | 8 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 39 | ||||
-rw-r--r-- | src/GCodes/GCodes.h | 70 | ||||
-rw-r--r-- | src/GCodes/GCodes2.cpp | 6 | ||||
-rw-r--r-- | src/Platform.cpp | 20 | ||||
-rw-r--r-- | src/RepRapFirmware.h | 1 | ||||
-rw-r--r-- | src/Version.h | 4 | ||||
-rw-r--r-- | src/Webserver/Webserver.cpp | 96 | ||||
-rw-r--r-- | src/Webserver/Webserver.h | 3 |
20 files changed, 268 insertions, 177 deletions
diff --git a/src/Configuration.h b/src/Configuration.h index 06186fdb..14ecfe0d 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -43,10 +43,6 @@ const float ABS_ZERO = -273.15; // Celsius const float NEARLY_ABS_ZERO = -273.0; // Celsius const float ROOM_TEMPERATURE = 21.0; // Celsius -const float INCH_TO_MM = 25.4; -const float MINUTES_TO_SECONDS = 60.0; -const float SECONDS_TO_MINUTES = 1.0 / MINUTES_TO_SECONDS; - const float LONG_TIME = 300.0; // Seconds const float MINIMUM_TOOL_WARNING_INTERVAL = 4.0; // Seconds diff --git a/src/DuetNG/DuetEthernet/Network.cpp b/src/DuetNG/DuetEthernet/Network.cpp index 1a2298d7..db79de62 100644 --- a/src/DuetNG/DuetEthernet/Network.cpp +++ b/src/DuetNG/DuetEthernet/Network.cpp @@ -351,31 +351,17 @@ void Network::CloseDataPort() bool Network::AcquireFTPTransaction() { - return AcquireTransaction(FtpSocketNumber); + return sockets[FtpSocketNumber].AcquireTransaction(); } bool Network::AcquireDataTransaction() { - return AcquireTransaction(FtpDataSocketNumber); + return sockets[FtpDataSocketNumber].AcquireTransaction(); } bool Network::AcquireTelnetTransaction() { - return AcquireTransaction(TelnetSocketNumber); -} - -bool Network::AcquireTransaction(SocketNumber skt) -{ - if ( sockets[skt].GetTransaction() != nullptr - && sockets[skt].GetTransaction()->GetStatus() != TransactionStatus::sending - && sockets[skt].GetTransaction()->GetStatus() != TransactionStatus::finished - ) - { - currentTransactionSocketNumber = skt; - return true; - } - - return false; + return sockets[TelnetSocketNumber].AcquireTransaction(); } void Network::InitSockets() diff --git a/src/DuetNG/DuetEthernet/Network.h b/src/DuetNG/DuetEthernet/Network.h index d6d38555..1a479a40 100644 --- a/src/DuetNG/DuetEthernet/Network.h +++ b/src/DuetNG/DuetEthernet/Network.h @@ -88,8 +88,6 @@ private: active }; - bool AcquireTransaction(SocketNumber skt); - void InitSockets(); void TerminateSockets(); diff --git a/src/DuetNG/DuetEthernet/NetworkTransaction.cpp b/src/DuetNG/DuetEthernet/NetworkTransaction.cpp index eeeb0e90..f6fa3a76 100644 --- a/src/DuetNG/DuetEthernet/NetworkTransaction.cpp +++ b/src/DuetNG/DuetEthernet/NetworkTransaction.cpp @@ -235,11 +235,11 @@ const uint8_t *NetworkTransaction::GetDataToSend(size_t& length) void NetworkTransaction::Commit(bool keepConnectionAlive) { closeAfterSending = !keepConnectionAlive; - status = TransactionStatus::sending; - if (closeAfterSending) + if (sendBuffer == nullptr) { - cs->DiscardReceivedData(); + sendBuffer = sendStack->Pop(); } + status = TransactionStatus::sending; } // Call this to perform some networking tasks while processing deferred requests, diff --git a/src/DuetNG/DuetEthernet/NetworkTransaction.h b/src/DuetNG/DuetEthernet/NetworkTransaction.h index 0dd5c3cc..caacd051 100644 --- a/src/DuetNG/DuetEthernet/NetworkTransaction.h +++ b/src/DuetNG/DuetEthernet/NetworkTransaction.h @@ -47,6 +47,7 @@ public: TransactionStatus GetStatus() const { return status; } bool IsConnected() const; bool IsSending() const; + bool CloseAfterSending() const { return closeAfterSending; } bool HasMoreDataToRead() const; bool Read(char& b); diff --git a/src/DuetNG/DuetEthernet/Socket.cpp b/src/DuetNG/DuetEthernet/Socket.cpp index 045b76a1..feba6b73 100644 --- a/src/DuetNG/DuetEthernet/Socket.cpp +++ b/src/DuetNG/DuetEthernet/Socket.cpp @@ -9,12 +9,15 @@ #include "NetworkTransaction.h" #include "NetworkBuffer.h" +#include "Network.h" +#include "RepRap.h" +#include "Webserver.h" #include "socketlib.h" //*************************************************************************************************** // Socket class -Socket::Socket() : currentTransaction(nullptr), receivedData(nullptr) +Socket::Socket() : currentTransaction(nullptr), receivedData(nullptr), state(SocketState::inactive) { } @@ -38,12 +41,11 @@ void Socket::ReInit() persistConnection = true; isTerminated = false; isSending = false; + needTransaction = false; state = SocketState::inactive; // Re-initialise the socket on the W5500 -//debugPrintf("About to initialise socket %u\n", socketNum); socket(socketNum, Sn_MR_TCP, localPort, 0x00); -//debugPrintf("Initialised socket %u\n", socketNum); } // Close a connection when the last packet has been sent @@ -152,6 +154,7 @@ void Socket::Poll(bool full) 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; @@ -167,40 +170,57 @@ void Socket::Poll(bool full) setSn_IR(socketNum, Sn_IR_CON); } - // See if the socket has received any data + if (state == SocketState::listening) // if it is a new connection { + needTransaction = false; + if (socketNum == FtpSocketNumber || socketNum == TelnetSocketNumber) + { + // FTP and Telnet protocols need a connection reply, so tell the Webserver module about the new connection + if (currentTransaction == nullptr) + { + 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"); + } + } + state = SocketState::connected; + } + + { + // See if the socket has received any data const uint16_t len = getSn_RX_RSR(socketNum); if (len != 0) { // 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) { - const int32_t ret = recv(socketNum, buf->Data(), min<size_t>(len, NetworkBuffer::bufferSize)); -// debugPrintf("ret %d\n", ret); - if (ret > 0) - { - buf->dataLength = (size_t)ret; - buf->readPointer = 0; - NetworkBuffer::AppendToList(&receivedData, buf); - } - else - { - buf->Release(); -// debugPrintf("Bad receive, code = %d\n", ret); - } + 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"); +// else debugPrintf("no buffer\n"); } + } - if (receivedData != nullptr && currentTransaction == nullptr) + if (currentTransaction == nullptr && (receivedData != nullptr || needTransaction)) + { + currentTransaction = NetworkTransaction::Allocate(); + if (currentTransaction != nullptr) { - currentTransaction = NetworkTransaction::Allocate(); - if (currentTransaction != nullptr) - { - currentTransaction->Set(this, TransactionStatus::receiving); - } + currentTransaction->Set(this, (needTransaction) ? TransactionStatus::acquired : TransactionStatus::receiving); + needTransaction = false; } } @@ -209,8 +229,14 @@ void Socket::Poll(bool full) // 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(); - ExecCommand(socketNum, Sn_CR_DISCON); + if (closeAfterSending) + { + ExecCommand(socketNum, Sn_CR_DISCON); + state = SocketState::closing; + DiscardReceivedData(); + } } break; @@ -218,10 +244,30 @@ void Socket::Poll(bool full) #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : ClOSE_WAIT\r\n", socketNum); #endif - if (!IsSending() || TrySendData()) + state = SocketState::clientDisconnecting; + if (IsSending() && TrySendData()) { - ReleaseTransaction(); - ExecCommand(socketNum, Sn_CR_DISCON); + 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()) + { + // 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; + } } break; @@ -229,7 +275,10 @@ void Socket::Poll(bool full) #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : CLOSED\r\n", s); #endif - if (socket(socketNum, Sn_MR_TCP, localPort, 0x00) == socketNum) // Reinitialize the socket + reprap.GetWebserver()->ConnectionLost(this); // the webserver needs this to be called for both graceful and disgraceful disconnects + state = SocketState::inactive; + + if (socket(socketNum, Sn_MR_TCP, localPort, 0x00) == socketNum) // Reinitialize the socket { #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : OPEN\r\n", socketNum); @@ -295,6 +344,7 @@ bool Socket::TrySendData() ptr += (uint16_t)length; sent = true; } + if (sent) { //debugPrintf("Sending data, rp=%04x tp=%04x\n", getSn_TX_RD(socketNum), getSn_TX_WR(socketNum)); @@ -318,4 +368,22 @@ void Socket::DiscardReceivedData() } } +// The webserver calls this to tell the socket that it needs a transaction, e.g. for sending a Telnet os FTP response. +// An empty transaction will do. +// Return true if we can do it, false if the connection is closed or closing. +bool Socket::AcquireTransaction() +{ + if (currentTransaction != nullptr && currentTransaction->GetStatus() == TransactionStatus::acquired) + { + return true; + } + + if (getSn_SR(socketNum) == SOCK_ESTABLISHED) + { + needTransaction = true; + return true; + } + return false; +} + // End diff --git a/src/DuetNG/DuetEthernet/Socket.h b/src/DuetNG/DuetEthernet/Socket.h index 7c6ef596..c37a4e82 100644 --- a/src/DuetNG/DuetEthernet/Socket.h +++ b/src/DuetNG/DuetEthernet/Socket.h @@ -34,16 +34,16 @@ public: bool IsPersistentConnection() const { return persistConnection; } bool CanWrite() const; void DiscardReceivedData(); + bool AcquireTransaction(); private: enum class SocketState : uint8_t { inactive, - idle, - requestInProgress, - requestDone, - responseInProgress, - responseDone + listening, + connected, + clientDisconnecting, + closing }; void ReInit(); @@ -60,7 +60,8 @@ private: bool isTerminated; // Will be true if the connection has gone down unexpectedly (TCP RST) SocketNumber socketNum; // The W5500 socket number we are using SocketState state; - bool isSending; + bool isSending; // True if we have written data to the W5500 to send and have not yet seen success or timeout + bool needTransaction; // True if the web server has asked for a transaction }; #endif /* SRC_DUETNG_DUETETHERNET_SOCKET_H_ */ diff --git a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socketlib.cpp b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socketlib.cpp index b1d60e4b..84b48433 100644 --- a/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socketlib.cpp +++ b/src/DuetNG/DuetEthernet/Wiznet/Ethernet/socketlib.cpp @@ -55,7 +55,7 @@ //***************************************************************************** #include <socketlib.h> -#define _SOCKET_DEBUG_ +//#define _SOCKET_DEBUG_ #ifdef _SOCKET_DEBUG_ extern "C" void debugPrintf(const char *fmt, ...); @@ -65,8 +65,6 @@ extern "C" void delay(uint32_t); # define DEBUG_PRINTF(_fmt, ...) #endif - - #define SOCK_ANY_PORT_NUM 0xC000 static uint16_t sock_any_port = SOCK_ANY_PORT_NUM; diff --git a/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp b/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp index 2d42feb0..c385c68b 100644 --- a/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp +++ b/src/DuetNG/DuetEthernet/Wiznet/Internet/DHCP/dhcp.cpp @@ -55,7 +55,7 @@ /* If you want to display debug & processing message, Define _DHCP_DEBUG_ in dhcp.h */ -#define _DHCP_DEBUG_ +//#define _DHCP_DEBUG_ #ifdef _DHCP_DEBUG_ extern "C" void debugPrintf(const char *fmt, ...); diff --git a/src/DuetNG/DuetWiFi/Webserver.cpp b/src/DuetNG/DuetWiFi/Webserver.cpp index 7d16d3a4..4b290ed9 100644 --- a/src/DuetNG/DuetWiFi/Webserver.cpp +++ b/src/DuetNG/DuetWiFi/Webserver.cpp @@ -661,11 +661,11 @@ bool Webserver::ProcessFirstFragment(HttpSession& session, const char* command, if (StringEquals(command, "move")) { const char* response = "{\"err\":1}"; // assume failure - const char* oldVal = GetKeyValue("old"); - const char* newVal = GetKeyValue("new"); + const char* const oldVal = GetKeyValue("old"); + const char* const newVal = GetKeyValue("new"); if (oldVal != nullptr && newVal != nullptr) { - bool success = platform->GetMassStorage()->Rename(oldVal, newVal); + const bool success = platform->GetMassStorage()->Rename(oldVal, newVal); if (success) { response = "{\"err\":0}"; @@ -756,13 +756,13 @@ bool Webserver::ProcessFirstFragment(HttpSession& session, const char* command, { dir = platform->GetGCodeDir(); } - const char* flagDirsVal = GetKeyValue("flagDirs"); - bool flagDirs = flagDirsVal != nullptr && atoi(flagDirsVal) == 1; + const char* const flagDirsVal = GetKeyValue("flagDirs"); + const bool flagDirs = flagDirsVal != nullptr && atoi(flagDirsVal) == 1; response = reprap.GetFilesResponse(dir, flagDirs); } else if (StringEquals(command, "fileinfo")) { - const char* nameVal = GetKeyValue("name"); + const char* const nameVal = GetKeyValue("name"); if (reprap.GetPrintMonitor()->GetFileInfoResponse(nameVal, response)) { processingDeferredRequest = false; diff --git a/src/Fan.cpp b/src/Fan.cpp index 67206112..bd29b965 100644 --- a/src/Fan.cpp +++ b/src/Fan.cpp @@ -20,7 +20,7 @@ void Fan::Init(Pin p_pin, bool hwInverted) inverted = blipping = false; heatersMonitored = 0; triggerTemperature = HOT_END_FAN_TEMPERATURE; - lastPwm = -1.0; + lastPwm = -1.0; // force a refresh Refresh(); } @@ -62,6 +62,8 @@ void Fan::SetInverted(bool inv) Refresh(); } +// Set the hardware PWM +// If you want make sure that the PWM is definitely updated, set lastPWM negative before calling this void Fan::SetHardwarePwm(float pwmVal) { if (pin != NoPin) @@ -88,6 +90,7 @@ void Fan::SetHardwarePwm(float pwmVal) void Fan::SetPwmFrequency(float p_freq) { freq = (uint16_t)constrain<float>(p_freq, 1.0, 65535.0); + lastPwm = -1.0; // force the PWM to be updated Refresh(); } @@ -97,6 +100,8 @@ void Fan::SetHeatersMonitored(uint16_t h) Refresh(); } +// Refresh the fan PWM +// If you want make sure that the PWM is definitely updated, set lastPWM negative before calling this void Fan::Refresh() { float reqVal = (heatersMonitored == 0) @@ -139,6 +144,7 @@ void Fan::Disable() if (pin != NoPin) { inverted = false; + lastPwm = -1; SetHardwarePwm(0.0); } pin = NoPin; diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h index eec66ebc..76943162 100644 --- a/src/GCodes/GCodeMachineState.h +++ b/src/GCodes/GCodeMachineState.h @@ -66,6 +66,14 @@ public: static GCodeMachineState *Allocate() post(!result.IsLive(); result.state == GCodeState::normal); + // Copy values that may have been altered by config.g into this state record + void CopyStateFrom(const GCodeMachineState& other) + { + drivesRelative = other.drivesRelative; + axesRelative = other.axesRelative; + feedrate = other.feedrate; + } + static void Release(GCodeMachineState *ms); static unsigned int GetNumAllocated() { return numAllocated; } static unsigned int GetNumInUse(); diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 1023b08a..73e4c1e2 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -55,7 +55,7 @@ void GCodes::RestorePoint::Init() { moveCoords[i] = 0.0; } - feedRate = DefaultFeedrate/minutesToSeconds; + feedRate = DefaultFeedrate * secondsToMinutes; } GCodes::GCodes(Platform* p, Webserver* w) : @@ -92,6 +92,7 @@ void GCodes::Init() eofStringCounter = 0; eofStringLength = strlen(eofString); offSetSet = false; + runningConfigFile = false; active = true; longWait = platform->Time(); dwellTime = longWait; @@ -132,7 +133,7 @@ void GCodes::Reset() probeCount = 0; cannedCycleMoveCount = 0; cannedCycleMoveQueued = false; - speedFactor = 1.0 / minutesToSeconds; // default is just to convert from mm/minute to mm/second + speedFactor = secondsToMinutes; // default is just to convert from mm/minute to mm/second for (size_t i = 0; i < MaxExtruders; ++i) { extrusionFactors[i] = 1.0; @@ -184,7 +185,8 @@ float GCodes::FractionOfFilePrinted() const // We use triggerCGode as the source to prevent any triggers being executed until we have finished bool GCodes::RunConfigFile(const char* fileName) { - return DoFileMacro(*daemonGCode, fileName, false); + runningConfigFile = DoFileMacro(*daemonGCode, fileName, false); + return runningConfigFile; } // Return true if the daemon is busy running config.g or a trigger file @@ -193,6 +195,15 @@ bool GCodes::IsDaemonBusy() const return daemonGCode->MachineState().fileState.IsLive(); } +// Copy the feed rate etc. from the daemon to the input channels +void GCodes::CopyConfigFinalValues(GCodeBuffer& gb) +{ + for (size_t i = 0; i < ARRAY_SIZE(gcodeSources); ++i) + { + gcodeSources[i]->MachineState().CopyStateFrom(gb.MachineState()); + } +} + void GCodes::Spin() { if (!active) @@ -333,7 +344,7 @@ void GCodes::Spin() { moveBuffer.coords[drive] = 0.0; } - moveBuffer.feedRate = DefaultFeedrate/minutesToSeconds; // ask for a good feed rate, we may have paused during a slow move + moveBuffer.feedRate = DefaultFeedrate * secondsToMinutes; // ask for a good feed rate, we may have paused during a slow move moveBuffer.moveType = 0; moveBuffer.endStopsToCheck = 0; moveBuffer.usePressureAdvance = false; @@ -741,7 +752,12 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, StringRef& reply) } else { - // Finished a macro + // Finished a macro or finished processing config.g + if (runningConfigFile) + { + CopyConfigFinalValues(gb); + runningConfigFile = false; + } Pop(gb); gb.Init(); if (gb.GetState() == GCodeState::normal) @@ -957,14 +973,17 @@ unsigned int GCodes::LoadMoveBufferFromGCode(GCodeBuffer& gb, int moveType) } // Deal with feed rate - if (gb.Seen(feedrateLetter)) + if (moveType >= 0 && gb.Seen(feedrateLetter)) { - gb.MachineState().feedrate = gb.GetFValue() * distanceScale * speedFactor; + const float rate = gb.GetFValue() * distanceScale; + gb.MachineState().feedrate = (moveType == 0) + ? rate * speedFactor + : rate * secondsToMinutes; // don't apply the speed factor to homing and other special moves } moveBuffer.feedRate = gb.MachineState().feedrate; // First do extrusion, and check, if we are extruding, that we have a tool to extrude with - Tool* tool = reprap.GetCurrentTool(); + Tool* const tool = reprap.GetCurrentTool(); if (gb.Seen(extrudeLetter)) { if (tool == nullptr) @@ -972,7 +991,7 @@ unsigned int GCodes::LoadMoveBufferFromGCode(GCodeBuffer& gb, int moveType) platform->Message(GENERIC_MESSAGE, "Attempting to extrude with no tool selected.\n"); return 0; } - size_t eMoveCount = tool->DriveCount(); + const size_t eMoveCount = tool->DriveCount(); if (eMoveCount > 0) { // Set the drive values for this tool. @@ -1485,7 +1504,7 @@ bool GCodes::OffsetAxes(GCodeBuffer& gb) if (gb.Seen(feedrateLetter)) // Has the user specified a feedrate? { - cannedFeedRate = gb.GetFValue() * distanceScale * SECONDS_TO_MINUTES; + cannedFeedRate = gb.GetFValue() * distanceScale * secondsToMinutes; } else { diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index 5aaea8ce..77252d3f 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -77,36 +77,36 @@ public: bool canPauseAfter; // true if we can pause just after this move and successfully restart }; - GCodes(Platform* p, Webserver* w); - void Spin(); // Called in a tight loop to make this class work - void Init(); // Set it up - void Exit(); // Shut it down - void Reset(); // Reset some parameter to defaults - bool ReadMove(RawMove& m); // Called by the Move class to get a movement set by the last G Code - void ClearMove(); - void QueueFileToPrint(const char* fileName); // Open a file of G Codes to run - void DeleteFile(const char* fileName); // Does what it says - void GetCurrentCoordinates(StringRef& s) const; // Write where we are into a string - bool DoingFileMacro() const; // Or still busy processing a macro file? - float FractionOfFilePrinted() const; // Get fraction of file printed - void Diagnostics(MessageType mtype); // Send helpful information out - - bool RunConfigFile(const char* fileName); // Start running the config file - bool IsDaemonBusy() const; // Return true if the daemon is busy running config.g or a trigger file + GCodes(Platform* p, Webserver* w); + void Spin(); // Called in a tight loop to make this class work + void Init(); // Set it up + void Exit(); // Shut it down + void Reset(); // Reset some parameter to defaults + bool ReadMove(RawMove& m); // Called by the Move class to get a movement set by the last G Code + void ClearMove(); + void QueueFileToPrint(const char* fileName); // Open a file of G Codes to run + void DeleteFile(const char* fileName); // Does what it says + void GetCurrentCoordinates(StringRef& s) const; // Write where we are into a string + bool DoingFileMacro() const; // Or still busy processing a macro file? + float FractionOfFilePrinted() const; // Get fraction of file printed + void Diagnostics(MessageType mtype); // Send helpful information out + + bool RunConfigFile(const char* fileName); // Start running the config file + bool IsDaemonBusy() const; // Return true if the daemon is busy running config.g or a trigger file bool GetAxisIsHomed(unsigned int axis) const // Has the axis been homed? - { return (axesHomed & (1 << axis)) != 0; } - void SetAxisIsHomed(unsigned int axis) // Tell us that the axis is now homed - { axesHomed |= (1 << axis); } - void SetAxisNotHomed(unsigned int axis) // Tell us that the axis is not homed - { axesHomed &= ~(1 << axis); } - - float GetSpeedFactor() const { return speedFactor * minutesToSeconds; } // Return the current speed factor - float GetExtrusionFactor(size_t extruder) { return extrusionFactors[extruder]; } // Return the current extrusion factors - float GetRawExtruderPosition(size_t drive) const; // Get the actual extruder position, after adjusting the extrusion factor - float GetRawExtruderTotalByDrive(size_t extruder) const; // Get the total extrusion since start of print, for one drive - float GetTotalRawExtrusion() const { return rawExtruderTotal; } // Get the total extrusion since start of print, all drives - + { return (axesHomed & (1 << axis)) != 0; } + void SetAxisIsHomed(unsigned int axis) // Tell us that the axis is now homed + { axesHomed |= (1 << axis); } + void SetAxisNotHomed(unsigned int axis) // Tell us that the axis is not homed + { axesHomed &= ~(1 << axis); } + + float GetSpeedFactor() const { return speedFactor * minutesToSeconds; } // Return the current speed factor + float GetExtrusionFactor(size_t extruder) { return extrusionFactors[extruder]; } // Return the current extrusion factors + float GetRawExtruderPosition(size_t drive) const; // Get the actual extruder position, after adjusting the extrusion factor + float GetRawExtruderTotalByDrive(size_t extruder) const; // Get the total extrusion since start of print, for one drive + float GetTotalRawExtrusion() const { return rawExtruderTotal; } // Get the total extrusion since start of print, all drives + bool IsFlashing() const { return isFlashing; } // Is a new firmware binary going to be flashed? bool IsPaused() const; @@ -114,16 +114,16 @@ public: bool IsResuming() const; bool IsRunning() const; - bool AllAxesAreHomed() const; // Return true if all axes are homed + bool AllAxesAreHomed() const; // Return true if all axes are homed - void CancelPrint(); // Cancel the current print + void CancelPrint(); // Cancel the current print - void MoveStoppedByZProbe() { zProbeTriggered = true; } // Called from the step ISR when the Z probe is triggered, causing the move to be aborted + void MoveStoppedByZProbe() { zProbeTriggered = true; } // Called from the step ISR when the Z probe is triggered, causing the move to be aborted - size_t GetNumAxes() const { return numAxes; } - size_t GetNumExtruders() const { return numExtruders; } + size_t GetNumAxes() const { return numAxes; } + size_t GetNumExtruders() const { return numExtruders; } - static const char axisLetters[MAX_AXES]; // 'X', 'Y', 'Z' + static const char axisLetters[MAX_AXES]; // 'X', 'Y', 'Z' private: enum class CannedMoveType : uint8_t { none, relative, absolute }; @@ -219,6 +219,7 @@ private: void ClearHeightMap() const; // Clear the height map bool WriteConfigOverrideFile(StringRef& reply, const char *fileName) const; // Write the config-override file + void CopyConfigFinalValues(GCodeBuffer& gb); // Copy the feed rate etc. from the daemon to the input channels static uint32_t LongArrayToBitMap(const long *arr, size_t numEntries); // Convert an array of longs to a bit map @@ -240,6 +241,7 @@ private: bool active; // Live and running? bool isPaused; // true if the print has been paused bool dwellWaiting; // We are in a dwell + bool runningConfigFile; // We are running config.g during the startup process unsigned int segmentsLeft; // The number of segments left to do in the current move, or 0 if no move available float dwellTime; // How long a pause for a dwell (seconds)? RawMove moveBuffer; // Move details to pass to Move class diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index e8a9131d..efdf175c 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -114,7 +114,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply) { moveBuffer.coords[drive] = 0.0; } - moveBuffer.feedRate = (gb.Seen(feedrateLetter)) ? gb.GetFValue() : gb.MachineState().feedrate; + moveBuffer.feedRate = (gb.Seen(feedrateLetter)) ? gb.GetFValue() * secondsToMinutes : gb.MachineState().feedrate; moveBuffer.filePos = noFilePosition; moveBuffer.usePressureAdvance = false; segmentsLeft = 1; @@ -162,7 +162,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply) break; case 20: // Inches (which century are we living in, here?) - distanceScale = INCH_TO_MM; + distanceScale = InchToMm; break; case 21: // mm @@ -1673,7 +1673,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply) case 220: // Set/report speed factor override percentage if (gb.Seen('S')) { - float newSpeedFactor = (gb.GetFValue() / 100.0) * secondsToMinutes; // include the conversion from mm/minute to mm/second + float newSpeedFactor = (gb.GetFValue() * 0.01) * secondsToMinutes; // include the conversion from mm/minute to mm/second if (newSpeedFactor > 0.0) { gb.MachineState().feedrate *= newSpeedFactor / speedFactor; diff --git a/src/Platform.cpp b/src/Platform.cpp index 3e9cd452..17d97f76 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -1351,9 +1351,9 @@ void Platform::Diagnostics(MessageType mtype) MessageF(mtype, "Recycled dynamic ram: %d\n", mi.fordblks); uint32_t currentStack, maxStack, neverUsed; GetStackUsage(¤tStack, &maxStack, &neverUsed); - MessageF(mtype, "Current stack ram used: %d\n", currentStack); - MessageF(mtype, "Maximum stack ram used: %d\n", maxStack); - MessageF(mtype, "Never used ram: %d\n", neverUsed); + MessageF(mtype, "Current stack ram used: %u\n", currentStack); + MessageF(mtype, "Maximum stack ram used: %u\n", maxStack); + MessageF(mtype, "Never used ram: %u\n", neverUsed); // Show the up time and reason for the last reset const uint32_t now = (uint32_t)Time(); // get up time in seconds @@ -1404,6 +1404,11 @@ void Platform::Diagnostics(MessageType mtype) // Show the current error codes MessageF(mtype, "Error status: %u\n", errorCodeBits); + //***TEMPORARY show the maximum PWM loop count, which should never exceed 1 + extern uint32_t maxPwmLoopCount; + MessageF(mtype, "Max PWM loop count %u\n", maxPwmLoopCount); + maxPwmLoopCount = 0; + // Show the number of free entries in the file table unsigned int numFreeFiles = 0; for (size_t i = 0; i < MAX_FILES; i++) @@ -1524,15 +1529,12 @@ void Platform::DiagnosticTest(int d) } } +extern "C" uint32_t _estack; // this is defined in the linker script + // Return the stack usage and amount of memory that has never been used, in bytes void Platform::GetStackUsage(uint32_t* currentStack, uint32_t* maxStack, uint32_t* neverUsed) const { - const char * const ramend = (const char *) -#if SAM4E - IRAM_ADDR + IRAM_SIZE; -#else - IRAM0_ADDR + IRAM_SIZE; -#endif + const char * const ramend = (const char *)&_estack; register const char * stack_ptr asm ("sp"); const char * const heapend = sbrk(0); const char * stack_lwm = heapend; diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h index 03783fb6..1b866008 100644 --- a/src/RepRapFirmware.h +++ b/src/RepRapFirmware.h @@ -93,6 +93,7 @@ const float minutesToSeconds = 60.0; const float secondsToMinutes = 1.0/minutesToSeconds; const float SecondsToMillis = 1000.0; const float MillisToSeconds = 0.001; +const float InchToMm = 25.4; // Type of an offset in a file typedef uint32_t FilePosition; diff --git a/src/Version.h b/src/Version.h index 98641268..7d12aff2 100644 --- a/src/Version.h +++ b/src/Version.h @@ -9,11 +9,11 @@ #define SRC_VERSION_H_ #ifndef VERSION -# define VERSION "1.17+2" +# define VERSION "1.17a" #endif #ifndef DATE -# define DATE "2016-12-29" +# define DATE "2017-01-02" #endif #define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman" diff --git a/src/Webserver/Webserver.cpp b/src/Webserver/Webserver.cpp index 72e62ca2..9c11c4bc 100644 --- a/src/Webserver/Webserver.cpp +++ b/src/Webserver/Webserver.cpp @@ -621,7 +621,7 @@ void Webserver::HttpInterpreter::DoFastUpload() // Write data in sector-aligned chunks. This also means that the buffer in fatfs is only used to hold the FAT. // Buffer size must be a multiple of the 512b sector size. #ifdef DUET_NG - static const size_t writeBufLength = 4096; + static const size_t writeBufLength = 8192; #else static const size_t writeBufLength = 2048; #endif @@ -754,13 +754,8 @@ void Webserver::HttpInterpreter::SendFile(const char* nameOfFileToSend, bool isW fileToSend = platform->GetFileStore(FS_PREFIX, nameOfFileToSend, false); if (fileToSend == nullptr) { - nameOfFileToSend = FOUR04_PAGE_FILE; - fileToSend = platform->GetFileStore(platform->GetWebDir(), nameOfFileToSend, false); - if (fileToSend == nullptr) - { - RejectMessage("not found", 404); - return; - } + RejectMessage("not found", 404); + return; } transaction->SetFileToWrite(fileToSend); } @@ -914,11 +909,11 @@ void Webserver::HttpInterpreter::SendJsonResponse(const char* command) bool mayKeepOpen; if (numQualKeys == 0) { - GetJsonResponse(command, jsonResponse, "", "", 0, mayKeepOpen); + GetJsonResponse(command, jsonResponse, mayKeepOpen); } else { - GetJsonResponse(command, jsonResponse, qualifiers[0].key, qualifiers[0].value, qualifiers[1].key - qualifiers[0].value - 1, mayKeepOpen); + GetJsonResponse(command, jsonResponse, mayKeepOpen); } // Check special cases of deferred requests (rr_fileinfo) and rejected messages @@ -963,13 +958,13 @@ void Webserver::HttpInterpreter::SendJsonResponse(const char* command) // Get the Json response for this command. // 'value' is null-terminated, but we also pass its length in case it contains embedded nulls, which matters when uploading files. -void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuffer *&response, const char* key, const char* value, size_t valueLength, bool& keepOpen) +void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuffer *&response, bool& keepOpen) { keepOpen = false; // assume we don't want to persist the connection - if (StringEquals(request, "connect") && StringEquals(key, "password")) + if (StringEquals(request, "connect") && GetKeyValue("password") != nullptr) { - if (IsAuthenticated() || reprap.CheckPassword(value)) + if (IsAuthenticated() || reprap.CheckPassword(GetKeyValue("password"))) { // Password OK if (Authenticate()) @@ -1012,10 +1007,10 @@ void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuff else if (StringEquals(request, "status")) { int type = 0; - if (StringEquals(key, "type")) + if (GetKeyValue("type") != nullptr) { // New-style JSON status responses - type = atoi(value); + type = atoi(GetKeyValue("type")); if (type < 1 || type > 3) { type = 1; @@ -1031,36 +1026,34 @@ void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuff response = reprap.GetLegacyStatusResponse(1, 0); } } - else if (StringEquals(request, "gcode") && StringEquals(key, "gcode")) + else if (StringEquals(request, "gcode") && GetKeyValue("gcode") != nullptr) { - LoadGcodeBuffer(value); + LoadGcodeBuffer(GetKeyValue("gcode")); response->printf("{\"buff\":%u}", GetGCodeBufferSpace()); } else if (StringEquals(request, "upload")) { response->printf("{\"err\":%d}", (uploadedBytes == postFileLength) ? 0 : 1); } - else if (StringEquals(request, "delete") && StringEquals(key, "name")) + else if (StringEquals(request, "delete") && GetKeyValue("name") != nullptr) { - bool ok = platform->GetMassStorage()->Delete(FS_PREFIX, value); + bool ok = platform->GetMassStorage()->Delete(FS_PREFIX, GetKeyValue("name")); response->printf("{\"err\":%d}", (ok) ? 0 : 1); } - else if (StringEquals(request, "filelist")) + else if (StringEquals(request, "filelist") && GetKeyValue("dir") != nullptr) { OutputBuffer::Release(response); - response = reprap.GetFilelistResponse(value); + response = reprap.GetFilelistResponse(GetKeyValue("dir")); } else if (StringEquals(request, "files")) { - const char* dir = (StringEquals(key, "dir")) ? value : platform->GetGCodeDir(); - bool flagDirs = false; - if (numQualKeys >= 2) + const char* dir = GetKeyValue("dir"); + if (dir == nullptr) { - if (StringEquals(qualifiers[1].key, "flagDirs")) - { - flagDirs = StringEquals(qualifiers[1].value, "1"); - } + dir = platform->GetGCodeDir(); } + const char* const flagDirsVal = GetKeyValue("flagDirs"); + const bool flagDirs = flagDirsVal != nullptr && atoi(flagDirsVal) == 1; OutputBuffer::Release(response); response = reprap.GetFilesResponse(dir, flagDirs); } @@ -1073,10 +1066,11 @@ void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuff } else { - if (StringEquals(qualifiers[0].key, "name")) + const char* const nameVal = GetKeyValue("name"); + if (nameVal != nullptr) { // Regular rr_fileinfo?name=xxx call - strncpy(filenameBeingProcessed, value, ARRAY_SIZE(filenameBeingProcessed)); + strncpy(filenameBeingProcessed, nameVal, ARRAY_SIZE(filenameBeingProcessed)); filenameBeingProcessed[ARRAY_UPB(filenameBeingProcessed)] = 0; } else @@ -1091,26 +1085,24 @@ void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuff } else if (StringEquals(request, "move")) { - if (numQualKeys >= 2) + const char* const oldVal = GetKeyValue("old"); + const char* const newVal = GetKeyValue("new"); + bool success = false; + if (oldVal != nullptr && newVal != nullptr) { - if (StringEquals(key, "old") && StringEquals(qualifiers[1].key, "new")) - { - response->printf("{\"err\":%d}", platform->GetMassStorage()->Rename(value, qualifiers[1].value) ? 0 : 1); - } - else - { - response->printf("{\"err\":1}"); - } - } - else - { - response->printf("{\"err\":1}"); + success = platform->GetMassStorage()->Rename(oldVal, newVal); } + response->printf("{\"err\":%d}", (success) ? 0 : 1); } - else if (StringEquals(request, "mkdir") && StringEquals(key, "dir")) + else if (StringEquals(request, "mkdir")) { - bool ok = (platform->GetMassStorage()->MakeDirectory(value)); - response->printf("{\"err\":%d}", (ok) ? 0 : 1); + const char* dirVal = GetKeyValue("dir"); + bool success = false; + if (dirVal != nullptr) + { + success = (platform->GetMassStorage()->MakeDirectory(dirVal)); + } + response->printf("{\"err\":%d}", (success) ? 0 : 1); } else if (StringEquals(request, "config")) { @@ -1123,6 +1115,18 @@ void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuff } } +const char* Webserver::HttpInterpreter::GetKeyValue(const char *key) const +{ + for (size_t i = 0; i < numQualKeys; ++i) + { + if (StringEquals(qualifiers[i].key, key)) + { + return qualifiers[i].value; + } + } + return nullptr; +} + void Webserver::HttpInterpreter::ResetState() { clientPointer = 0; diff --git a/src/Webserver/Webserver.h b/src/Webserver/Webserver.h index ef14bcab..3e4f2c30 100644 --- a/src/Webserver/Webserver.h +++ b/src/Webserver/Webserver.h @@ -199,7 +199,7 @@ protected: void SendFile(const char* nameOfFileToSend, bool isWebFile); void SendGCodeReply(); void SendJsonResponse(const char* command); - void GetJsonResponse(const char* request, OutputBuffer *&response, const char* key, const char* value, size_t valueLength, bool& keepOpen); + void GetJsonResponse(const char* request, OutputBuffer *&response, bool& keepOpen); bool ProcessMessage(); bool RejectMessage(const char* s, unsigned int code = 500); @@ -232,6 +232,7 @@ protected: bool IsAuthenticated() const; void UpdateAuthentication(); bool RemoveAuthentication(); + const char* GetKeyValue(const char *key) const; // return the value of the specified key, or nullptr if not present // Deal with incoming G-Codes |