Release 1.19alpha
First working release of new WiFi code Axes moving other than X (possibly mapped), Y and Z are not taken to be part of the feed rate Introduced SafeStrncpy and SafeStrncat
This commit is contained in:
parent
9d4c15c5db
commit
384d1d3ad4
25 changed files with 219 additions and 111 deletions
BIN
Release/Duet-Ethernet/Edge/DuetEthernetFirmware.bin
Normal file
BIN
Release/Duet-Ethernet/Edge/DuetEthernetFirmware.bin
Normal file
Binary file not shown.
BIN
Release/Duet-Ethernet/Edge/DuetWebControl-1.15b+1.zip
Normal file
BIN
Release/Duet-Ethernet/Edge/DuetWebControl-1.15b+1.zip
Normal file
Binary file not shown.
BIN
Release/Duet-WiFi/Edge/DuetWebControl-1.15b+2.zip
Normal file
BIN
Release/Duet-WiFi/Edge/DuetWebControl-1.15b+2.zip
Normal file
Binary file not shown.
BIN
Release/Duet-WiFi/Edge/DuetWiFiFirmware.bin
Normal file
BIN
Release/Duet-WiFi/Edge/DuetWiFiFirmware.bin
Normal file
Binary file not shown.
BIN
Release/Duet-WiFi/Edge/DuetWiFiServer.bin
Normal file
BIN
Release/Duet-WiFi/Edge/DuetWiFiServer.bin
Normal file
Binary file not shown.
|
@ -107,7 +107,8 @@ Network::Network(Platform* p) : platform(p), nextResponderToPoll(nullptr), uploa
|
||||||
responders = new HttpResponder(responders);
|
responders = new HttpResponder(responders);
|
||||||
}
|
}
|
||||||
|
|
||||||
wiFiServerVersion[0] = 0;
|
strcpy(ssid, "(unknown)");
|
||||||
|
strcpy(wiFiServerVersion, "(unknown)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::Init()
|
void Network::Init()
|
||||||
|
@ -131,7 +132,7 @@ void Network::Init()
|
||||||
currentSocket = 0;
|
currentSocket = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::EnableProtocol(int protocol, int port, bool secure, StringRef& reply)
|
void Network::EnableProtocol(int protocol, int port, int secure, StringRef& reply)
|
||||||
{
|
{
|
||||||
if (secure != 0 && secure != -1)
|
if (secure != 0 && secure != -1)
|
||||||
{
|
{
|
||||||
|
@ -153,7 +154,7 @@ void Network::EnableProtocol(int protocol, int port, bool secure, StringRef& rep
|
||||||
if (state == NetworkState::active)
|
if (state == NetworkState::active)
|
||||||
{
|
{
|
||||||
StartProtocol(protocol);
|
StartProtocol(protocol);
|
||||||
#if 0 // mdns not implemented yet
|
#if 0 // mdns not implemented yet, if we are going to implement it then we need to send the WiFi module a command to do it here and pass the protocol set
|
||||||
if (state == NetworkState::active)
|
if (state == NetworkState::active)
|
||||||
{
|
{
|
||||||
DoMdnsAnnounce();
|
DoMdnsAnnounce();
|
||||||
|
@ -305,6 +306,10 @@ bool Network::GetNetworkState(StringRef& reply)
|
||||||
case NetworkState::active:
|
case NetworkState::active:
|
||||||
reply.copy("WiFi module is ");
|
reply.copy("WiFi module is ");
|
||||||
reply.cat(TranslateWiFiState(currentMode));
|
reply.cat(TranslateWiFiState(currentMode));
|
||||||
|
if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint)
|
||||||
|
{
|
||||||
|
reply.cat(ssid);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
reply.copy("Unknown network state");
|
reply.copy("Unknown network state");
|
||||||
|
@ -403,6 +408,13 @@ void Network::Spin(bool full)
|
||||||
SetupSpi(); // set up the SPI subsystem
|
SetupSpi(); // set up the SPI subsystem
|
||||||
state = NetworkState::active;
|
state = NetworkState::active;
|
||||||
currentMode = WiFiState::idle; // wifi module is running but inactive
|
currentMode = WiFiState::idle; // wifi module is running but inactive
|
||||||
|
|
||||||
|
// Read the status to get the WiFi server version
|
||||||
|
Receiver<NetworkStatusResponse> status;
|
||||||
|
if (SendCommand(NetworkCommand::networkGetStatus, 0, 0, nullptr, 0, status) > 0)
|
||||||
|
{
|
||||||
|
SafeStrncpy(wiFiServerVersion, status.Value().versionText, ARRAY_SIZE(wiFiServerVersion));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -455,7 +467,22 @@ void Network::Spin(bool full)
|
||||||
}
|
}
|
||||||
else if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint)
|
else if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint)
|
||||||
{
|
{
|
||||||
// Poll the next socket
|
// Find the next socket to poll
|
||||||
|
const size_t startingSocket = currentSocket;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (sockets[currentSocket].NeedsPolling())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++currentSocket;
|
||||||
|
if (currentSocket == NumTcpSockets)
|
||||||
|
{
|
||||||
|
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);
|
sockets[currentSocket].Poll(full);
|
||||||
++currentSocket;
|
++currentSocket;
|
||||||
if (currentSocket == NumTcpSockets)
|
if (currentSocket == NumTcpSockets)
|
||||||
|
@ -498,12 +525,31 @@ void Network::Spin(bool full)
|
||||||
GetNewStatus();
|
GetNewStatus();
|
||||||
if (currentMode != WiFiState::connecting)
|
if (currentMode != WiFiState::connecting)
|
||||||
{
|
{
|
||||||
requestedMode = currentMode; // don't keep repeating the request
|
requestedMode = currentMode; // don't keep repeating the request if it failed
|
||||||
state = NetworkState::active;
|
state = NetworkState::active;
|
||||||
platform->MessageF(HOST_MESSAGE, "Wifi module is %s\n", TranslateWiFiState(currentMode));
|
|
||||||
if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint)
|
if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint)
|
||||||
{
|
{
|
||||||
|
// Get our IP address, this needs to be correct for FTP to work
|
||||||
|
Receiver<NetworkStatusResponse> status;
|
||||||
|
if (SendCommand(NetworkCommand::networkGetStatus, 0, 0, nullptr, 0, status) > 0)
|
||||||
|
{
|
||||||
|
uint32_t ip = status.Value().ipAddress;
|
||||||
|
for (size_t i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
ipAddress[i] = (uint8_t)(ip & 255);
|
||||||
|
ip >>= 8;
|
||||||
|
}
|
||||||
|
SafeStrncpy(ssid, status.Value().ssid, SsidLength);
|
||||||
|
}
|
||||||
InitSockets();
|
InitSockets();
|
||||||
|
platform->MessageF(HOST_MESSAGE, "Wifi module is %s%s, IP address %u.%u.%u.%u\n",
|
||||||
|
TranslateWiFiState(currentMode),
|
||||||
|
ssid,
|
||||||
|
ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
platform->MessageF(HOST_MESSAGE, "Wifi module is %s\n", TranslateWiFiState(currentMode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,6 +687,8 @@ int Network::EnableState() const
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate the wifi state to text.
|
||||||
|
// The 'connected' and 'runningAsAccessPoint' states include a space at the end because the caller is expected to append the access point name.
|
||||||
/*static*/ const char* Network::TranslateWiFiState(WiFiState w)
|
/*static*/ const char* Network::TranslateWiFiState(WiFiState w)
|
||||||
{
|
{
|
||||||
switch (w)
|
switch (w)
|
||||||
|
@ -648,8 +696,8 @@ int Network::EnableState() const
|
||||||
case WiFiState::disabled: return "disabled";
|
case WiFiState::disabled: return "disabled";
|
||||||
case WiFiState::idle: return "idle";
|
case WiFiState::idle: return "idle";
|
||||||
case WiFiState::connecting: return "trying to connect";
|
case WiFiState::connecting: return "trying to connect";
|
||||||
case WiFiState::connected: return "connected to an access point";
|
case WiFiState::connected: return "connected to access point ";
|
||||||
case WiFiState::runningAsAccessPoint: return "providing an access point";
|
case WiFiState::runningAsAccessPoint: return "providing access point ";
|
||||||
default: return "in an unknown state";
|
default: return "in an unknown state";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -725,6 +773,18 @@ void Network::TerminateSockets(Port port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is called to tell the network which sockets are active
|
||||||
|
void Network::UpdateSocketStatus(uint16_t connectedSockets, uint16_t otherEndClosedSockets)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < NumTcpSockets; ++i)
|
||||||
|
{
|
||||||
|
if (((connectedSockets | otherEndClosedSockets) & (1u << i)) != 0)
|
||||||
|
{
|
||||||
|
sockets[i].SetNeedsPolling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find a responder to process a new connection
|
// Find a responder to process a new connection
|
||||||
bool Network::FindResponder(Socket *skt, Port localPort)
|
bool Network::FindResponder(Socket *skt, Port localPort)
|
||||||
{
|
{
|
||||||
|
@ -758,7 +818,7 @@ void Network::CloseDataPort()
|
||||||
if (ftpDataPort != 0)
|
if (ftpDataPort != 0)
|
||||||
{
|
{
|
||||||
SendListenCommand(ftpDataPort, 0);
|
SendListenCommand(ftpDataPort, 0);
|
||||||
TerminateSockets(ftpDataPort); // if the FTP responder want to close the socket cleanly, it should have closed it itself
|
TerminateSockets(ftpDataPort); // if the FTP responder wants to close the socket cleanly, it should have closed it itself
|
||||||
ftpDataPort = 0;
|
ftpDataPort = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
void Start();
|
void Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
void EnableProtocol(int protocol, int port, bool secure, StringRef& reply);
|
void EnableProtocol(int protocol, int port, int secure, StringRef& reply);
|
||||||
void DisableProtocol(int protocol, StringRef& reply);
|
void DisableProtocol(int protocol, StringRef& reply);
|
||||||
void ReportProtocols(StringRef& reply) const;
|
void ReportProtocols(StringRef& reply) const;
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ public:
|
||||||
|
|
||||||
void SpiInterrupt();
|
void SpiInterrupt();
|
||||||
void EspRequestsTransfer();
|
void EspRequestsTransfer();
|
||||||
|
void UpdateSocketStatus(uint16_t connectedSockets, uint16_t otherEndClosedSockets);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class NetworkState
|
enum class NetworkState
|
||||||
|
@ -150,6 +151,7 @@ private:
|
||||||
uint8_t netmask[4];
|
uint8_t netmask[4];
|
||||||
uint8_t gateway[4];
|
uint8_t gateway[4];
|
||||||
char hostname[16]; // Limit DHCP hostname to 15 characters + terminating 0
|
char hostname[16]; // Limit DHCP hostname to 15 characters + terminating 0
|
||||||
|
char ssid[SsidLength + 1];
|
||||||
|
|
||||||
uint32_t spiTxUnderruns;
|
uint32_t spiTxUnderruns;
|
||||||
uint32_t spiRxOverruns;
|
uint32_t spiRxOverruns;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
const uint32_t FindResponderTimeout = 2000; // how long we wait for a responder to become available
|
const uint32_t FindResponderTimeout = 2000; // how long we wait for a responder to become available
|
||||||
const unsigned int MaxBuffersPerSocket = 4;
|
const unsigned int MaxBuffersPerSocket = 4;
|
||||||
|
|
||||||
Socket::Socket() : localPort(0), receivedData(nullptr), state(SocketState::inactive)
|
Socket::Socket() : localPort(0), receivedData(nullptr), state(SocketState::inactive), needsPolling(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,8 +118,9 @@ void Socket::Taken(size_t len)
|
||||||
void Socket::Poll(bool full)
|
void Socket::Poll(bool full)
|
||||||
{
|
{
|
||||||
// Get the socket status
|
// Get the socket status
|
||||||
|
Network * const network = reprap.GetNetwork();
|
||||||
Receiver<ConnStatusResponse> resp;
|
Receiver<ConnStatusResponse> resp;
|
||||||
const int32_t ret = reprap.GetNetwork()->SendCommand(NetworkCommand::connGetStatus, socketNum, 0, nullptr, 0, resp);
|
const int32_t ret = network->SendCommand(NetworkCommand::connGetStatus, socketNum, 0, nullptr, 0, resp);
|
||||||
if (ret != (int32_t)resp.Size())
|
if (ret != (int32_t)resp.Size())
|
||||||
{
|
{
|
||||||
// We can't do much here other than disable and restart wifi, or hope the next status call succeeds
|
// We can't do much here other than disable and restart wifi, or hope the next status call succeeds
|
||||||
|
@ -130,6 +131,10 @@ void Socket::Poll(bool full)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// As well as getting the status for the socket we asked about, we also received bitmaps of connected sockets.
|
||||||
|
// Pass these to the Network module so that it can avoid polling idle sockets.
|
||||||
|
network->UpdateSocketStatus(resp.Value().connectedSockets, resp.Value().otherEndClosedSockets);
|
||||||
|
|
||||||
switch (resp.Value().state)
|
switch (resp.Value().state)
|
||||||
{
|
{
|
||||||
case ConnState::connected:
|
case ConnState::connected:
|
||||||
|
@ -148,7 +153,7 @@ void Socket::Poll(bool full)
|
||||||
{
|
{
|
||||||
whenConnected = millis();
|
whenConnected = millis();
|
||||||
}
|
}
|
||||||
if (reprap.GetNetwork()->FindResponder(this, localPort))
|
if (network->FindResponder(this, localPort))
|
||||||
{
|
{
|
||||||
state = SocketState::connected;
|
state = SocketState::connected;
|
||||||
if (reprap.Debug(moduleNetwork))
|
if (reprap.Debug(moduleNetwork))
|
||||||
|
@ -204,6 +209,8 @@ void Socket::Poll(bool full)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
needsPolling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to receive more incoming data from the socket
|
// Try to receive more incoming data from the socket
|
||||||
|
@ -281,4 +288,10 @@ void Socket::Send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if we need to poll this socket
|
||||||
|
bool Socket::NeedsPolling() const
|
||||||
|
{
|
||||||
|
return state != SocketState::inactive || needsPolling;
|
||||||
|
}
|
||||||
|
|
||||||
// End
|
// End
|
||||||
|
|
|
@ -29,6 +29,8 @@ public:
|
||||||
bool CanSend() const;
|
bool CanSend() const;
|
||||||
size_t Send(const uint8_t *data, size_t length);
|
size_t Send(const uint8_t *data, size_t length);
|
||||||
void Send();
|
void Send();
|
||||||
|
void SetNeedsPolling() { needsPolling = true; }
|
||||||
|
bool NeedsPolling() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class SocketState : uint8_t
|
enum class SocketState : uint8_t
|
||||||
|
@ -53,8 +55,7 @@ private:
|
||||||
uint16_t txBufferSpace; // How much free transmit buffer space the WiFi mofule reported
|
uint16_t txBufferSpace; // How much free transmit buffer space the WiFi mofule reported
|
||||||
SocketNumber socketNum; // The WiFi socket number we are using
|
SocketNumber socketNum; // The WiFi socket number we are using
|
||||||
SocketState state;
|
SocketState state;
|
||||||
bool sendOutstanding; // True if we have written data to the socket but not flushed it
|
bool needsPolling;
|
||||||
bool isSending; // True if we have written data to send and have not yet seen success or timeout
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SRC_DUETNG_DUETWIFI_SOCKET_H_ */
|
#endif /* SRC_DUETNG_DUETWIFI_SOCKET_H_ */
|
||||||
|
|
|
@ -619,8 +619,7 @@ void FtpResponder::ProcessLine()
|
||||||
{
|
{
|
||||||
filename = GetPlatform()->GetMassStorage()->CombineName(currentDirectory, filename);
|
filename = GetPlatform()->GetMassStorage()->CombineName(currentDirectory, filename);
|
||||||
}
|
}
|
||||||
strncpy(fileToMove, filename, FILENAME_LENGTH);
|
SafeStrncpy(fileToMove, filename, ARRAY_SIZE(fileToMove));
|
||||||
fileToMove[FILENAME_LENGTH - 1] = 0;
|
|
||||||
|
|
||||||
if (GetPlatform()->GetMassStorage()->FileExists(fileToMove))
|
if (GetPlatform()->GetMassStorage()->FileExists(fileToMove))
|
||||||
{
|
{
|
||||||
|
@ -802,8 +801,7 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
||||||
// Prepare the new directory path
|
// Prepare the new directory path
|
||||||
if (newDirectory[0] == '/') // Absolute path
|
if (newDirectory[0] == '/') // Absolute path
|
||||||
{
|
{
|
||||||
strncpy(combinedPath, newDirectory, FILENAME_LENGTH);
|
SafeStrncpy(combinedPath, newDirectory, ARRAY_SIZE(combinedPath));
|
||||||
combinedPath[FILENAME_LENGTH - 1] = 0;
|
|
||||||
}
|
}
|
||||||
else // Relative path
|
else // Relative path
|
||||||
{
|
{
|
||||||
|
@ -818,8 +816,7 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
// No - find the parent directory
|
// No - find the parent directory
|
||||||
strncpy(combinedPath, currentDirectory, FILENAME_LENGTH);
|
SafeStrncpy(combinedPath, currentDirectory, ARRAY_SIZE(combinedPath));
|
||||||
combinedPath[ARRAY_UPB(combinedPath)] = 0;
|
|
||||||
for(int i = strlen(combinedPath) - 2; i >= 0; i--)
|
for(int i = strlen(combinedPath) - 2; i >= 0; i--)
|
||||||
{
|
{
|
||||||
if (combinedPath[i] == '/')
|
if (combinedPath[i] == '/')
|
||||||
|
@ -831,13 +828,12 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
||||||
}
|
}
|
||||||
else // Go to child directory
|
else // Go to child directory
|
||||||
{
|
{
|
||||||
strncpy(combinedPath, currentDirectory, FILENAME_LENGTH);
|
SafeStrncpy(combinedPath, currentDirectory, ARRAY_SIZE(combinedPath));
|
||||||
if (!StringEndsWith(combinedPath, "/") && strlen(combinedPath) > 1)
|
if (!StringEndsWith(combinedPath, "/") && strlen(combinedPath) > 1)
|
||||||
{
|
{
|
||||||
strncat(combinedPath, "/", FILENAME_LENGTH);
|
SafeStrncat(combinedPath, "/", ARRAY_SIZE(combinedPath));
|
||||||
}
|
}
|
||||||
strncat(combinedPath, newDirectory, FILENAME_LENGTH);
|
SafeStrncat(combinedPath, newDirectory, ARRAY_SIZE(combinedPath));
|
||||||
combinedPath[ARRAY_UPB(combinedPath)] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,7 +846,7 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
||||||
// Verify the final path and change it if possible
|
// Verify the final path and change it if possible
|
||||||
if (GetPlatform()->GetMassStorage()->DirectoryExists(combinedPath))
|
if (GetPlatform()->GetMassStorage()->DirectoryExists(combinedPath))
|
||||||
{
|
{
|
||||||
strncpy(currentDirectory, combinedPath, FILENAME_LENGTH);
|
SafeStrncpy(currentDirectory, combinedPath, ARRAY_SIZE(currentDirectory));
|
||||||
outBuf->copy("250 Directory successfully changed.\r\n");
|
outBuf->copy("250 Directory successfully changed.\r\n");
|
||||||
Commit(responderState);
|
Commit(responderState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,8 +543,7 @@ bool HttpResponder::GetJsonResponse(const char* request, OutputBuffer *&response
|
||||||
if (nameVal != nullptr)
|
if (nameVal != nullptr)
|
||||||
{
|
{
|
||||||
// Regular rr_fileinfo?name=xxx call
|
// Regular rr_fileinfo?name=xxx call
|
||||||
strncpy(filenameBeingProcessed, nameVal, ARRAY_SIZE(filenameBeingProcessed));
|
SafeStrncpy(filenameBeingProcessed, nameVal, ARRAY_SIZE(filenameBeingProcessed));
|
||||||
filenameBeingProcessed[ARRAY_UPB(filenameBeingProcessed)] = 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -867,8 +866,7 @@ void HttpResponder::SendJsonResponse(const char* command)
|
||||||
{
|
{
|
||||||
const char *configPath = GetPlatform()->GetMassStorage()->CombineName(GetPlatform()->GetSysDir(), GetPlatform()->GetConfigFile());
|
const char *configPath = GetPlatform()->GetMassStorage()->CombineName(GetPlatform()->GetSysDir(), GetPlatform()->GetConfigFile());
|
||||||
char fileName[FILENAME_LENGTH];
|
char fileName[FILENAME_LENGTH];
|
||||||
strncpy(fileName, configPath, FILENAME_LENGTH);
|
SafeStrncpy(fileName, configPath, ARRAY_SIZE(fileName));
|
||||||
|
|
||||||
SendFile(fileName, false);
|
SendFile(fileName, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ const Port DefaultTelnetPort = 23;
|
||||||
|
|
||||||
const unsigned int TCP_MSS = 1460;
|
const unsigned int TCP_MSS = 1460;
|
||||||
|
|
||||||
const size_t NetworkBufferCount = 16; // number of 2K or 3K network buffers
|
const size_t NetworkBufferCount = 8; // number of 2K network buffers
|
||||||
|
|
||||||
// Define the following to use 3K buffers on the W5500 for the HTTP sockets and smaller buffers for everything else
|
// Define the following to use 3K buffers on the W5500 for the HTTP sockets and smaller buffers for everything else
|
||||||
// It doesn't seem to work, the chip keeps telling us that 1 byte is available.
|
// It doesn't seem to work, the chip keeps telling us that 1 byte is available.
|
||||||
|
|
|
@ -195,8 +195,7 @@ void NetworkResponder::ConnectionLost()
|
||||||
void NetworkResponder::StartUpload(FileStore *file, const char *fileName)
|
void NetworkResponder::StartUpload(FileStore *file, const char *fileName)
|
||||||
{
|
{
|
||||||
fileBeingUploaded.Set(file);
|
fileBeingUploaded.Set(file);
|
||||||
strncpy(filenameBeingUploaded, fileName, ARRAY_SIZE(filenameBeingUploaded));
|
SafeStrncpy(filenameBeingUploaded, fileName, ARRAY_SIZE(filenameBeingUploaded));
|
||||||
filenameBeingUploaded[ARRAY_UPB(filenameBeingUploaded)] = 0;
|
|
||||||
responderState = ResponderState::uploading;
|
responderState = ResponderState::uploading;
|
||||||
uploadError = false;
|
uploadError = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,8 +95,7 @@ bool GCodeQueue::QueueCode(GCodeBuffer &gb, uint32_t segmentsLeft)
|
||||||
// No - we've run out of free items. Run the first outstanding code
|
// No - we've run out of free items. Run the first outstanding code
|
||||||
queueCode = false;
|
queueCode = false;
|
||||||
codeToRunLength = strlen(queuedItems->code);
|
codeToRunLength = strlen(queuedItems->code);
|
||||||
strncpy(codeToRun, queuedItems->code, codeToRunLength);
|
SafeStrncpy(codeToRun, queuedItems->code, ARRAY_SIZE(codeToRun));
|
||||||
codeToRun[ARRAY_UPB(codeToRun)] = 0;
|
|
||||||
|
|
||||||
// Release the first queued item so that it can be reused later
|
// Release the first queued item so that it can be reused later
|
||||||
QueuedCode *item = queuedItems;
|
QueuedCode *item = queuedItems;
|
||||||
|
@ -106,7 +105,7 @@ bool GCodeQueue::QueueCode(GCodeBuffer &gb, uint32_t segmentsLeft)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlink a free element and assign gb's code to it
|
// Unlink a free element and assign gb's code to it
|
||||||
QueuedCode *code = freeItems;
|
QueuedCode * const code = freeItems;
|
||||||
freeItems = code->next;
|
freeItems = code->next;
|
||||||
code->AssignFrom(gb);
|
code->AssignFrom(gb);
|
||||||
code->executeAtMove = scheduledMoves;
|
code->executeAtMove = scheduledMoves;
|
||||||
|
@ -223,8 +222,7 @@ void GCodeQueue::Diagnostics(MessageType mtype)
|
||||||
void QueuedCode::AssignFrom(GCodeBuffer &gb)
|
void QueuedCode::AssignFrom(GCodeBuffer &gb)
|
||||||
{
|
{
|
||||||
toolNumberAdjust = gb.GetToolNumberAdjust();
|
toolNumberAdjust = gb.GetToolNumberAdjust();
|
||||||
strncpy(code, gb.Buffer(), GCODE_LENGTH);
|
SafeStrncpy(code, gb.Buffer(), ARRAY_SIZE(code));
|
||||||
code[ARRAY_UPB(code)] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueuedCode::AssignTo(GCodeBuffer *gb)
|
void QueuedCode::AssignTo(GCodeBuffer *gb)
|
||||||
|
|
|
@ -40,11 +40,11 @@
|
||||||
|
|
||||||
const char GCodes::axisLetters[MAX_AXES] = { 'X', 'Y', 'Z', 'U', 'V', 'W' };
|
const char GCodes::axisLetters[MAX_AXES] = { 'X', 'Y', 'Z', 'U', 'V', 'W' };
|
||||||
|
|
||||||
const char* PAUSE_G = "pause.g";
|
const char* const PAUSE_G = "pause.g";
|
||||||
const char* HomingFileNames[MAX_AXES] = { "homex.g", "homey.g", "homez.g", "homeu.g", "homev.g", "homew.g" };
|
const char* const HomingFileNames[MAX_AXES] = { "homex.g", "homey.g", "homez.g", "homeu.g", "homev.g", "homew.g" };
|
||||||
const char* HOME_ALL_G = "homeall.g";
|
const char* const HOME_ALL_G = "homeall.g";
|
||||||
const char* HOME_DELTA_G = "homedelta.g";
|
const char* const HOME_DELTA_G = "homedelta.g";
|
||||||
const char* DefaultHeightMapFile = "heightmap.csv";
|
const char* const DefaultHeightMapFile = "heightmap.csv";
|
||||||
|
|
||||||
const size_t gcodeReplyLength = 2048; // long enough to pass back a reasonable number of files in response to M20
|
const size_t gcodeReplyLength = 2048; // long enough to pass back a reasonable number of files in response to M20
|
||||||
|
|
||||||
|
@ -366,7 +366,10 @@ void GCodes::Spin()
|
||||||
if (LockMovementAndWaitForStandstill(gb))
|
if (LockMovementAndWaitForStandstill(gb))
|
||||||
{
|
{
|
||||||
gb.SetState(GCodeState::pausing2);
|
gb.SetState(GCodeState::pausing2);
|
||||||
DoFileMacro(gb, PAUSE_G, true);
|
if (AllAxesAreHomed())
|
||||||
|
{
|
||||||
|
DoFileMacro(gb, PAUSE_G, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -511,7 +514,7 @@ void GCodes::Spin()
|
||||||
moveBuffer.coords[Y_AXIS] = y - platform->GetCurrentZProbeParameters().yOffset;
|
moveBuffer.coords[Y_AXIS] = y - platform->GetCurrentZProbeParameters().yOffset;
|
||||||
moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
|
moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
|
||||||
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
|
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
|
||||||
moveBuffer.xAxes = 0;
|
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||||
segmentsLeft = 1;
|
segmentsLeft = 1;
|
||||||
gb.AdvanceState();
|
gb.AdvanceState();
|
||||||
}
|
}
|
||||||
|
@ -551,7 +554,7 @@ void GCodes::Spin()
|
||||||
moveBuffer.filePos = noFilePosition;
|
moveBuffer.filePos = noFilePosition;
|
||||||
moveBuffer.coords[Z_AXIS] = -platform->GetZProbeDiveHeight();
|
moveBuffer.coords[Z_AXIS] = -platform->GetZProbeDiveHeight();
|
||||||
moveBuffer.feedRate = platform->GetCurrentZProbeParameters().probeSpeed;
|
moveBuffer.feedRate = platform->GetCurrentZProbeParameters().probeSpeed;
|
||||||
moveBuffer.xAxes = 0;
|
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||||
segmentsLeft = 1;
|
segmentsLeft = 1;
|
||||||
gb.SetState(GCodeState::gridProbing3);
|
gb.SetState(GCodeState::gridProbing3);
|
||||||
}
|
}
|
||||||
|
@ -579,7 +582,7 @@ void GCodes::Spin()
|
||||||
moveBuffer.filePos = noFilePosition;
|
moveBuffer.filePos = noFilePosition;
|
||||||
moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
|
moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
|
||||||
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
|
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
|
||||||
moveBuffer.xAxes = 0;
|
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||||
segmentsLeft = 1;
|
segmentsLeft = 1;
|
||||||
gb.SetState(GCodeState::gridProbing4);
|
gb.SetState(GCodeState::gridProbing4);
|
||||||
}
|
}
|
||||||
|
@ -1300,7 +1303,7 @@ int GCodes::SetUpMove(GCodeBuffer& gb, StringRef& reply)
|
||||||
if (ival == 1 || ival == 2)
|
if (ival == 1 || ival == 2)
|
||||||
{
|
{
|
||||||
moveBuffer.moveType = ival;
|
moveBuffer.moveType = ival;
|
||||||
moveBuffer.xAxes = 0; // don't do bed compensation
|
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ival == 1)
|
if (ival == 1)
|
||||||
|
@ -1686,7 +1689,7 @@ bool GCodes::DoCannedCycleMove(GCodeBuffer& gb, EndstopChecks ce)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moveBuffer.feedRate = cannedFeedRate;
|
moveBuffer.feedRate = cannedFeedRate;
|
||||||
moveBuffer.xAxes = 0;
|
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||||
moveBuffer.endStopsToCheck = ce;
|
moveBuffer.endStopsToCheck = ce;
|
||||||
moveBuffer.filePos = noFilePosition;
|
moveBuffer.filePos = noFilePosition;
|
||||||
moveBuffer.usePressureAdvance = false;
|
moveBuffer.usePressureAdvance = false;
|
||||||
|
|
|
@ -22,19 +22,16 @@
|
||||||
|
|
||||||
#ifdef DUET_NG
|
#ifdef DUET_NG
|
||||||
# include "FirmwareUpdater.h"
|
# include "FirmwareUpdater.h"
|
||||||
# ifdef DUET_WIFI
|
|
||||||
# include "MessageFormats.h"
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* BED_EQUATION_G = "bed.g";
|
const char* const BED_EQUATION_G = "bed.g";
|
||||||
const char* RESUME_G = "resume.g";
|
const char* const RESUME_G = "resume.g";
|
||||||
const char* CANCEL_G = "cancel.g";
|
const char* const CANCEL_G = "cancel.g";
|
||||||
const char* STOP_G = "stop.g";
|
const char* const STOP_G = "stop.g";
|
||||||
const char* SLEEP_G = "sleep.g";
|
const char* const SLEEP_G = "sleep.g";
|
||||||
const char* CONFIG_OVERRIDE_G = "config-override.g";
|
const char* const CONFIG_OVERRIDE_G = "config-override.g";
|
||||||
const char* DEPLOYPROBE_G = "deployprobe.g";
|
const char* const DEPLOYPROBE_G = "deployprobe.g";
|
||||||
const char* RETRACTPROBE_G = "retractprobe.g";
|
const char* const RETRACTPROBE_G = "retractprobe.g";
|
||||||
|
|
||||||
const float MinServoPulseWidth = 544.0, MaxServoPulseWidth = 2400.0;
|
const float MinServoPulseWidth = 544.0, MaxServoPulseWidth = 2400.0;
|
||||||
const uint16_t ServoRefreshFrequency = 50;
|
const uint16_t ServoRefreshFrequency = 50;
|
||||||
|
@ -324,13 +321,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
if (wasPaused)
|
if (wasPaused)
|
||||||
{
|
{
|
||||||
reply.copy("Print cancelled");
|
reply.copy("Print cancelled");
|
||||||
// If we are cancelling a paused print with M0 and cancel.g exists then run it and do nothing else
|
// If we are cancelling a paused print with M0 and we are homed and cancel.g exists then run it and do nothing else
|
||||||
if (code == 0)
|
if (code == 0 && AllAxesAreHomed() && DoFileMacro(gb, CANCEL_G, false))
|
||||||
{
|
{
|
||||||
if (DoFileMacro(gb, CANCEL_G, false))
|
break;
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -551,7 +545,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
||||||
if (isPaused)
|
if (isPaused)
|
||||||
{
|
{
|
||||||
gb.SetState(GCodeState::resuming1);
|
gb.SetState(GCodeState::resuming1);
|
||||||
DoFileMacro(gb, RESUME_G, true);
|
if (AllAxesAreHomed())
|
||||||
|
{
|
||||||
|
DoFileMacro(gb, RESUME_G, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!fileToPrint.IsLive())
|
else if (!fileToPrint.IsLive())
|
||||||
{
|
{
|
||||||
|
|
|
@ -216,7 +216,8 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
isPrintingMove = false;
|
isPrintingMove = false;
|
||||||
bool realMove = false, xyMoving = false, xyzMoving = false;
|
bool realMove = false, xyzMoving = false;
|
||||||
|
xyMoving = false;
|
||||||
const bool isSpecialDeltaMove = (move->IsDeltaMode() && !doMotorMapping);
|
const bool isSpecialDeltaMove = (move->IsDeltaMode() && !doMotorMapping);
|
||||||
float accelerations[DRIVES];
|
float accelerations[DRIVES];
|
||||||
const float * const normalAccelerations = reprap.GetPlatform()->Accelerations();
|
const float * const normalAccelerations = reprap.GetPlatform()->Accelerations();
|
||||||
|
@ -239,10 +240,13 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
||||||
directionVector[drive] = positionDelta;
|
directionVector[drive] = positionDelta;
|
||||||
if (positionDelta != 0)
|
if (positionDelta != 0)
|
||||||
{
|
{
|
||||||
xyzMoving = true;
|
if (drive == Z_AXIS)
|
||||||
if (drive != Z_AXIS)
|
|
||||||
{
|
{
|
||||||
xyMoving = true;
|
xyzMoving = true;
|
||||||
|
}
|
||||||
|
else if (drive == Y_AXIS || ((1 << drive) & nextMove.xAxes) != 0)
|
||||||
|
{
|
||||||
|
xyMoving = xyzMoving = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dm.state = (isDeltaMovement || delta != 0)
|
dm.state = (isDeltaMovement || delta != 0)
|
||||||
|
@ -287,6 +291,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Store some values
|
// 3. Store some values
|
||||||
|
xAxes = nextMove.xAxes;
|
||||||
endStopsToCheck = nextMove.endStopsToCheck;
|
endStopsToCheck = nextMove.endStopsToCheck;
|
||||||
canPauseAfter = nextMove.canPauseAfter;
|
canPauseAfter = nextMove.canPauseAfter;
|
||||||
filePos = nextMove.filePos;
|
filePos = nextMove.filePos;
|
||||||
|
@ -309,7 +314,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
||||||
directionVector[Z_AXIS] += (directionVector[X_AXIS] * dparams.GetXTilt()) + (directionVector[Y_AXIS] * dparams.GetYTilt());
|
directionVector[Z_AXIS] += (directionVector[X_AXIS] * dparams.GetXTilt()) + (directionVector[Y_AXIS] * dparams.GetYTilt());
|
||||||
}
|
}
|
||||||
|
|
||||||
totalDistance = Normalise(directionVector, DRIVES, numAxes);
|
totalDistance = NormaliseXYZ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -527,13 +532,13 @@ void DDA::AdvanceBabyStepping(float amount)
|
||||||
while(cdda != this)
|
while(cdda != this)
|
||||||
{
|
{
|
||||||
float babySteppingToDo = 0.0;
|
float babySteppingToDo = 0.0;
|
||||||
if (amount != 0.0)
|
if (amount != 0.0 && cdda->xyMoving)
|
||||||
{
|
{
|
||||||
// Limit the babystepping Z speed to the lower of 0.1 times the original XYZ speed and 0.5 times the Z jerk
|
// Limit the babystepping Z speed to the lower of 0.1 times the original XYZ speed and 0.5 times the Z jerk
|
||||||
const float maxBabySteppingAmount = cdda->totalDistance * min<float>(0.1, 0.5 * reprap.GetPlatform()->ConfiguredInstantDv(Z_AXIS)/cdda->topSpeed);
|
const float maxBabySteppingAmount = cdda->totalDistance * min<float>(0.1, 0.5 * reprap.GetPlatform()->ConfiguredInstantDv(Z_AXIS)/cdda->topSpeed);
|
||||||
babySteppingToDo = constrain<float>(amount, -maxBabySteppingAmount, maxBabySteppingAmount);
|
babySteppingToDo = constrain<float>(amount, -maxBabySteppingAmount, maxBabySteppingAmount);
|
||||||
cdda->directionVector[Z_AXIS] += babySteppingToDo/cdda->totalDistance;
|
cdda->directionVector[Z_AXIS] += babySteppingToDo/cdda->totalDistance;
|
||||||
cdda->totalDistance *= Normalise(cdda->directionVector, DRIVES, reprap.GetGCodes()->GetNumAxes());
|
cdda->totalDistance *= cdda->NormaliseXYZ();
|
||||||
cdda->RecalculateMove();
|
cdda->RecalculateMove();
|
||||||
babySteppingDone += babySteppingToDo;
|
babySteppingDone += babySteppingToDo;
|
||||||
amount -= babySteppingToDo;
|
amount -= babySteppingToDo;
|
||||||
|
@ -991,7 +996,7 @@ void DDA::Prepare()
|
||||||
|
|
||||||
// Take a unit positive-hyperquadrant vector, and return the factor needed to obtain
|
// Take a unit positive-hyperquadrant vector, and return the factor needed to obtain
|
||||||
// length of the vector as projected to touch box[].
|
// length of the vector as projected to touch box[].
|
||||||
float DDA::VectorBoxIntersection(const float v[], const float box[], size_t dimensions)
|
/*static*/ float DDA::VectorBoxIntersection(const float v[], const float box[], size_t dimensions)
|
||||||
{
|
{
|
||||||
// Generate a vector length that is guaranteed to exceed the size of the box
|
// Generate a vector length that is guaranteed to exceed the size of the box
|
||||||
const float biggerThanBoxDiagonal = 2.0*Magnitude(box, dimensions);
|
const float biggerThanBoxDiagonal = 2.0*Magnitude(box, dimensions);
|
||||||
|
@ -1011,9 +1016,9 @@ float DDA::VectorBoxIntersection(const float v[], const float box[], size_t dime
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalise a vector with dim1 dimensions so that it is unit in the first dim2 dimensions, and also return its previous magnitude in dim2 dimensions
|
// Normalise a vector with dim1 dimensions so that it is unit in the first dim2 dimensions, and also return its previous magnitude in dim2 dimensions
|
||||||
float DDA::Normalise(float v[], size_t dim1, size_t dim2)
|
/*static*/ float DDA::Normalise(float v[], size_t dim1, size_t dim2)
|
||||||
{
|
{
|
||||||
float magnitude = Magnitude(v, dim2);
|
const float magnitude = Magnitude(v, dim2);
|
||||||
if (magnitude <= 0.0)
|
if (magnitude <= 0.0)
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
@ -1022,8 +1027,37 @@ float DDA::Normalise(float v[], size_t dim1, size_t dim2)
|
||||||
return magnitude;
|
return magnitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make the direction vector unit-normal in XYZ and return the previous magnitude
|
||||||
|
float DDA::NormaliseXYZ()
|
||||||
|
{
|
||||||
|
// First calculate the magnitude of the vector. If there is more than one X axis, take an average of their movements (they should be equal).
|
||||||
|
float magSquared = 0.0;
|
||||||
|
unsigned int numXaxes = 0;
|
||||||
|
for (size_t d = 0; d < MAX_AXES; ++d)
|
||||||
|
{
|
||||||
|
if (((1 << d) & xAxes) != 0)
|
||||||
|
{
|
||||||
|
magSquared += fsquare(directionVector[d]);
|
||||||
|
++numXaxes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numXaxes != 0)
|
||||||
|
{
|
||||||
|
magSquared /= numXaxes;
|
||||||
|
}
|
||||||
|
const float magnitude = sqrtf(magSquared + fsquare(directionVector[Y_AXIS]) + fsquare(directionVector[Z_AXIS]));
|
||||||
|
if (magnitude <= 0.0)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now normalise it
|
||||||
|
Scale(directionVector, 1.0/magnitude, DRIVES);
|
||||||
|
return magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the magnitude of a vector
|
// Return the magnitude of a vector
|
||||||
float DDA::Magnitude(const float v[], size_t dimensions)
|
/*static*/ float DDA::Magnitude(const float v[], size_t dimensions)
|
||||||
{
|
{
|
||||||
float magnitude = 0.0;
|
float magnitude = 0.0;
|
||||||
for (size_t d = 0; d < dimensions; d++)
|
for (size_t d = 0; d < dimensions; d++)
|
||||||
|
@ -1034,18 +1068,18 @@ float DDA::Magnitude(const float v[], size_t dimensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply a vector by a scalar
|
// Multiply a vector by a scalar
|
||||||
void DDA::Scale(float v[], float scale, size_t dimensions)
|
/*static*/ void DDA::Scale(float v[], float scale, size_t dimensions)
|
||||||
{
|
{
|
||||||
for(size_t d = 0; d < dimensions; d++)
|
for (size_t d = 0; d < dimensions; d++)
|
||||||
{
|
{
|
||||||
v[d] = scale*v[d];
|
v[d] *= scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move a vector into the positive hyperquadrant
|
// Move a vector into the positive hyperquadrant
|
||||||
void DDA::Absolute(float v[], size_t dimensions)
|
/*static*/ void DDA::Absolute(float v[], size_t dimensions)
|
||||||
{
|
{
|
||||||
for(size_t d = 0; d < dimensions; d++)
|
for (size_t d = 0; d < dimensions; d++)
|
||||||
{
|
{
|
||||||
v[d] = fabsf(v[d]);
|
v[d] = fabsf(v[d]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ private:
|
||||||
void DebugPrintVector(const char *name, const float *vec, size_t len) const;
|
void DebugPrintVector(const char *name, const float *vec, size_t len) const;
|
||||||
void CheckEndstops(Platform *platform);
|
void CheckEndstops(Platform *platform);
|
||||||
void AdvanceBabyStepping(float amount); // Try to push babystepping earlier in the move queue
|
void AdvanceBabyStepping(float amount); // Try to push babystepping earlier in the move queue
|
||||||
|
float NormaliseXYZ(); // Make the direction vector unit-normal in XYZ
|
||||||
|
|
||||||
static void DoLookahead(DDA *laDDA); // Try to smooth out moves in the queue
|
static void DoLookahead(DDA *laDDA); // Try to smooth out moves in the queue
|
||||||
static float Normalise(float v[], size_t dim1, size_t dim2); // Normalise a vector of dim1 dimensions to unit length in the first dim1 dimensions
|
static float Normalise(float v[], size_t dim1, size_t dim2); // Normalise a vector of dim1 dimensions to unit length in the first dim1 dimensions
|
||||||
|
@ -119,7 +120,7 @@ private:
|
||||||
DDA* next; // The next one in the ring
|
DDA* next; // The next one in the ring
|
||||||
DDA *prev; // The previous one in the ring
|
DDA *prev; // The previous one in the ring
|
||||||
|
|
||||||
volatile DDAState state; // what state this DDA is in
|
volatile DDAState state; // What state this DDA is in
|
||||||
uint8_t endCoordinatesValid : 1; // True if endCoordinates can be relied on
|
uint8_t endCoordinatesValid : 1; // True if endCoordinates can be relied on
|
||||||
uint8_t isDeltaMovement : 1; // True if this is a delta printer movement
|
uint8_t isDeltaMovement : 1; // True if this is a delta printer movement
|
||||||
uint8_t canPauseAfter : 1; // True if we can pause at the end of this move
|
uint8_t canPauseAfter : 1; // True if we can pause at the end of this move
|
||||||
|
@ -127,10 +128,12 @@ private:
|
||||||
uint8_t isPrintingMove : 1; // True if this move includes XY movement and extrusion
|
uint8_t isPrintingMove : 1; // True if this move includes XY movement and extrusion
|
||||||
uint8_t usePressureAdvance : 1; // True if pressure advance should be applied to any forward extrusion
|
uint8_t usePressureAdvance : 1; // True if pressure advance should be applied to any forward extrusion
|
||||||
uint8_t hadLookaheadUnderrun : 1; // True if the lookahead queue was not long enough to optimise this move
|
uint8_t hadLookaheadUnderrun : 1; // True if the lookahead queue was not long enough to optimise this move
|
||||||
|
uint8_t xyMoving : 1; // True if we have movement along an X axis or the Y axis
|
||||||
|
|
||||||
EndstopChecks endStopsToCheck; // Which endstops we are checking on this move
|
EndstopChecks endStopsToCheck; // Which endstops we are checking on this move
|
||||||
|
uint32_t xAxes; // Which axes are behaving as X axes
|
||||||
|
|
||||||
FilePosition filePos; // The position in the SD card file after this move was read, or zero if not read fro SD card
|
FilePosition filePos; // The position in the SD card file after this move was read, or zero if not read from SD card
|
||||||
|
|
||||||
int32_t endPoint[DRIVES]; // Machine coordinates of the endpoint
|
int32_t endPoint[DRIVES]; // Machine coordinates of the endpoint
|
||||||
float endCoordinates[DRIVES]; // The Cartesian coordinates at the end of the move plus extrusion amounts
|
float endCoordinates[DRIVES]; // The Cartesian coordinates at the end of the move plus extrusion amounts
|
||||||
|
|
|
@ -167,8 +167,7 @@ float PrintMonitor::GetWarmUpDuration() const
|
||||||
void PrintMonitor::StartingPrint(const char* filename)
|
void PrintMonitor::StartingPrint(const char* filename)
|
||||||
{
|
{
|
||||||
printingFileParsed = GetFileInfo(platform->GetGCodeDir(), filename, printingFileInfo);
|
printingFileParsed = GetFileInfo(platform->GetGCodeDir(), filename, printingFileInfo);
|
||||||
strncpy(filenameBeingPrinted, filename, ARRAY_SIZE(filenameBeingPrinted));
|
SafeStrncpy(filenameBeingPrinted, filename, ARRAY_SIZE(filenameBeingPrinted));
|
||||||
filenameBeingPrinted[ARRAY_UPB(filenameBeingPrinted)] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell this class that the file set for printing is now actually processed
|
// Tell this class that the file set for printing is now actually processed
|
||||||
|
@ -296,8 +295,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod
|
||||||
}
|
}
|
||||||
|
|
||||||
// File has been opened, let's start now
|
// File has been opened, let's start now
|
||||||
strncpy(filenameBeingParsed, fileName, ARRAY_SIZE(filenameBeingParsed));
|
SafeStrncpy(filenameBeingParsed, fileName, ARRAY_SIZE(filenameBeingParsed));
|
||||||
filenameBeingParsed[ARRAY_UPB(filenameBeingParsed)] = 0;
|
|
||||||
fileOverlapLength = 0;
|
fileOverlapLength = 0;
|
||||||
|
|
||||||
// Set up the info struct
|
// Set up the info struct
|
||||||
|
|
|
@ -1323,8 +1323,7 @@ OutputBuffer *RepRap::GetFilesResponse(const char *dir, bool flagsDirs)
|
||||||
// Get the long filename if possible
|
// Get the long filename if possible
|
||||||
if (flagsDirs && fileInfo.isDirectory)
|
if (flagsDirs && fileInfo.isDirectory)
|
||||||
{
|
{
|
||||||
strncpy(filename + sizeof(char), fileInfo.fileName, FILENAME_LENGTH - 1);
|
SafeStrncpy(filename + 1, fileInfo.fileName, ARRAY_SIZE(fileInfo.fileName) - 1);
|
||||||
filename[FILENAME_LENGTH - 1] = 0;
|
|
||||||
fname = filename;
|
fname = filename;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1447,8 +1446,7 @@ void RepRap::Beep(int freq, int ms)
|
||||||
// Send a short message. We send it to both PanelDue and the web interface.
|
// Send a short message. We send it to both PanelDue and the web interface.
|
||||||
void RepRap::SetMessage(const char *msg)
|
void RepRap::SetMessage(const char *msg)
|
||||||
{
|
{
|
||||||
strncpy(message, msg, MESSAGE_LENGTH);
|
SafeStrncpy(message, msg, ARRAY_SIZE(message));
|
||||||
message[MESSAGE_LENGTH] = 0;
|
|
||||||
|
|
||||||
if (platform->HaveAux())
|
if (platform->HaveAux())
|
||||||
{
|
{
|
||||||
|
|
|
@ -271,4 +271,20 @@ int StringContains(const char* string, const char* match)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Version of strncpy that ensures the result is null terminated
|
||||||
|
void SafeStrncpy(char *dst, const char *src, size_t length)
|
||||||
|
{
|
||||||
|
strncpy(dst, src, length);
|
||||||
|
dst[length - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version of strcat that takes the original buffer size as the limit and ensures the result is null terminated
|
||||||
|
void SafeStrncat(char *dst, const char *src, size_t length)
|
||||||
|
{
|
||||||
|
dst[length - 1] = 0;
|
||||||
|
const size_t index = strlen(dst);
|
||||||
|
strncat(dst + index, src, length - index);
|
||||||
|
dst[length - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// End
|
// End
|
||||||
|
|
|
@ -78,6 +78,8 @@ bool StringEndsWith(const char* string, const char* ending);
|
||||||
bool StringStartsWith(const char* string, const char* starting);
|
bool StringStartsWith(const char* string, const char* starting);
|
||||||
bool StringEquals(const char* s1, const char* s2);
|
bool StringEquals(const char* s1, const char* s2);
|
||||||
int StringContains(const char* string, const char* match);
|
int StringContains(const char* string, const char* match);
|
||||||
|
void SafeStrncpy(char *dst, const char *src, size_t length) pre(length != 0);
|
||||||
|
void SafeStrncat(char *dst, const char *src, size_t length) pre(length != 0);
|
||||||
|
|
||||||
// Macro to assign an array from an initialiser list
|
// Macro to assign an array from an initialiser list
|
||||||
#define ARRAY_INIT(_dest, _init) static_assert(sizeof(_dest) == sizeof(_init), "Incompatible array types"); memcpy(_dest, _init, sizeof(_init));
|
#define ARRAY_INIT(_dest, _init) static_assert(sizeof(_dest) == sizeof(_init), "Incompatible array types"); memcpy(_dest, _init, sizeof(_init));
|
||||||
|
|
|
@ -387,8 +387,7 @@ bool Scanner::StartScan(const char *filename, int param)
|
||||||
|
|
||||||
// Copy the scan length/degree and the filename
|
// Copy the scan length/degree and the filename
|
||||||
scanParam = param;
|
scanParam = param;
|
||||||
strncpy(scanFilename, filename, ARRAY_SIZE(scanFilename));
|
SafeStrncpy(scanFilename, filename, ARRAY_SIZE(scanFilename));
|
||||||
scanFilename[ARRAY_UPB(scanFilename)] = 0;
|
|
||||||
|
|
||||||
// Run the scan_pre macro and wait for it to finish
|
// Run the scan_pre macro and wait for it to finish
|
||||||
DoFileMacro(SCAN_PRE_G);
|
DoFileMacro(SCAN_PRE_G);
|
||||||
|
|
|
@ -123,21 +123,12 @@ bool MassStorage::FindFirst(const char *directory, FileInfo &file_info)
|
||||||
TCHAR loc[FILENAME_LENGTH + 1];
|
TCHAR loc[FILENAME_LENGTH + 1];
|
||||||
|
|
||||||
// Remove the trailing '/' from the directory name
|
// Remove the trailing '/' from the directory name
|
||||||
size_t len = strnlen(directory, ARRAY_UPB(loc));
|
SafeStrncpy(loc, directory, ARRAY_SIZE(loc));
|
||||||
if (len == 0)
|
const size_t len = strlen(loc);
|
||||||
|
if (len != 0 && loc[len - 1] == '/')
|
||||||
{
|
{
|
||||||
loc[0] = 0;
|
|
||||||
}
|
|
||||||
else if (directory[len - 1] == '/')
|
|
||||||
{
|
|
||||||
strncpy(loc, directory, len - 1);
|
|
||||||
loc[len - 1] = 0;
|
loc[len - 1] = 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
strncpy(loc, directory, len);
|
|
||||||
loc[len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
findDir.lfn = nullptr;
|
findDir.lfn = nullptr;
|
||||||
FRESULT res = f_opendir(&findDir, loc);
|
FRESULT res = f_opendir(&findDir, loc);
|
||||||
|
@ -157,7 +148,7 @@ bool MassStorage::FindFirst(const char *directory, FileInfo &file_info)
|
||||||
|
|
||||||
if (file_info.fileName[0] == 0)
|
if (file_info.fileName[0] == 0)
|
||||||
{
|
{
|
||||||
strncpy(file_info.fileName, entry.fname, ARRAY_SIZE(file_info.fileName));
|
SafeStrncpy(file_info.fileName, entry.fname, ARRAY_SIZE(file_info.fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
file_info.size = entry.fsize;
|
file_info.size = entry.fsize;
|
||||||
|
@ -189,7 +180,7 @@ bool MassStorage::FindNext(FileInfo &file_info)
|
||||||
|
|
||||||
if (file_info.fileName[0] == 0)
|
if (file_info.fileName[0] == 0)
|
||||||
{
|
{
|
||||||
strncpy(file_info.fileName, entry.fname, ARRAY_SIZE(file_info.fileName));
|
SafeStrncpy(file_info.fileName, entry.fname, ARRAY_SIZE(file_info.fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
file_info.lastModified = ConvertTimeStamp(entry.fdate, entry.ftime);
|
file_info.lastModified = ConvertTimeStamp(entry.fdate, entry.ftime);
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
#define SRC_VERSION_H_
|
#define SRC_VERSION_H_
|
||||||
|
|
||||||
#ifndef VERSION
|
#ifndef VERSION
|
||||||
# define VERSION "1.19alpha"
|
# define VERSION "1.19alpha1"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DATE
|
#ifndef DATE
|
||||||
# define DATE "2017-05-01"
|
# define DATE "2017-05-04"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"
|
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"
|
||||||
|
|
Reference in a new issue