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);
|
||||
}
|
||||
|
||||
wiFiServerVersion[0] = 0;
|
||||
strcpy(ssid, "(unknown)");
|
||||
strcpy(wiFiServerVersion, "(unknown)");
|
||||
}
|
||||
|
||||
void Network::Init()
|
||||
|
@ -131,7 +132,7 @@ void Network::Init()
|
|||
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)
|
||||
{
|
||||
|
@ -153,7 +154,7 @@ void Network::EnableProtocol(int protocol, int port, bool secure, StringRef& rep
|
|||
if (state == NetworkState::active)
|
||||
{
|
||||
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)
|
||||
{
|
||||
DoMdnsAnnounce();
|
||||
|
@ -305,6 +306,10 @@ bool Network::GetNetworkState(StringRef& reply)
|
|||
case NetworkState::active:
|
||||
reply.copy("WiFi module is ");
|
||||
reply.cat(TranslateWiFiState(currentMode));
|
||||
if (currentMode == WiFiState::connected || currentMode == WiFiState::runningAsAccessPoint)
|
||||
{
|
||||
reply.cat(ssid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
reply.copy("Unknown network state");
|
||||
|
@ -403,6 +408,13 @@ void Network::Spin(bool full)
|
|||
SetupSpi(); // set up the SPI subsystem
|
||||
state = NetworkState::active;
|
||||
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;
|
||||
|
@ -455,7 +467,22 @@ void Network::Spin(bool full)
|
|||
}
|
||||
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);
|
||||
++currentSocket;
|
||||
if (currentSocket == NumTcpSockets)
|
||||
|
@ -498,12 +525,31 @@ void Network::Spin(bool full)
|
|||
GetNewStatus();
|
||||
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;
|
||||
platform->MessageF(HOST_MESSAGE, "Wifi module is %s\n", TranslateWiFiState(currentMode));
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
switch (w)
|
||||
|
@ -648,8 +696,8 @@ int Network::EnableState() const
|
|||
case WiFiState::disabled: return "disabled";
|
||||
case WiFiState::idle: return "idle";
|
||||
case WiFiState::connecting: return "trying to connect";
|
||||
case WiFiState::connected: return "connected to an access point";
|
||||
case WiFiState::runningAsAccessPoint: return "providing an access point";
|
||||
case WiFiState::connected: return "connected to access point ";
|
||||
case WiFiState::runningAsAccessPoint: return "providing access point ";
|
||||
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
|
||||
bool Network::FindResponder(Socket *skt, Port localPort)
|
||||
{
|
||||
|
@ -758,7 +818,7 @@ void Network::CloseDataPort()
|
|||
if (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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
void Start();
|
||||
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 ReportProtocols(StringRef& reply) const;
|
||||
|
||||
|
@ -91,6 +91,7 @@ public:
|
|||
|
||||
void SpiInterrupt();
|
||||
void EspRequestsTransfer();
|
||||
void UpdateSocketStatus(uint16_t connectedSockets, uint16_t otherEndClosedSockets);
|
||||
|
||||
private:
|
||||
enum class NetworkState
|
||||
|
@ -150,6 +151,7 @@ private:
|
|||
uint8_t netmask[4];
|
||||
uint8_t gateway[4];
|
||||
char hostname[16]; // Limit DHCP hostname to 15 characters + terminating 0
|
||||
char ssid[SsidLength + 1];
|
||||
|
||||
uint32_t spiTxUnderruns;
|
||||
uint32_t spiRxOverruns;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
const uint32_t FindResponderTimeout = 2000; // how long we wait for a responder to become available
|
||||
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)
|
||||
{
|
||||
// Get the socket status
|
||||
Network * const network = reprap.GetNetwork();
|
||||
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())
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
case ConnState::connected:
|
||||
|
@ -148,7 +153,7 @@ void Socket::Poll(bool full)
|
|||
{
|
||||
whenConnected = millis();
|
||||
}
|
||||
if (reprap.GetNetwork()->FindResponder(this, localPort))
|
||||
if (network->FindResponder(this, localPort))
|
||||
{
|
||||
state = SocketState::connected;
|
||||
if (reprap.Debug(moduleNetwork))
|
||||
|
@ -204,6 +209,8 @@ void Socket::Poll(bool full)
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
needsPolling = false;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
bool CanSend() const;
|
||||
size_t Send(const uint8_t *data, size_t length);
|
||||
void Send();
|
||||
void SetNeedsPolling() { needsPolling = true; }
|
||||
bool NeedsPolling() const;
|
||||
|
||||
private:
|
||||
enum class SocketState : uint8_t
|
||||
|
@ -53,8 +55,7 @@ private:
|
|||
uint16_t txBufferSpace; // How much free transmit buffer space the WiFi mofule reported
|
||||
SocketNumber socketNum; // The WiFi socket number we are using
|
||||
SocketState state;
|
||||
bool sendOutstanding; // True if we have written data to the socket but not flushed it
|
||||
bool isSending; // True if we have written data to send and have not yet seen success or timeout
|
||||
bool needsPolling;
|
||||
};
|
||||
|
||||
#endif /* SRC_DUETNG_DUETWIFI_SOCKET_H_ */
|
||||
|
|
|
@ -619,8 +619,7 @@ void FtpResponder::ProcessLine()
|
|||
{
|
||||
filename = GetPlatform()->GetMassStorage()->CombineName(currentDirectory, filename);
|
||||
}
|
||||
strncpy(fileToMove, filename, FILENAME_LENGTH);
|
||||
fileToMove[FILENAME_LENGTH - 1] = 0;
|
||||
SafeStrncpy(fileToMove, filename, ARRAY_SIZE(fileToMove));
|
||||
|
||||
if (GetPlatform()->GetMassStorage()->FileExists(fileToMove))
|
||||
{
|
||||
|
@ -802,8 +801,7 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
|||
// Prepare the new directory path
|
||||
if (newDirectory[0] == '/') // Absolute path
|
||||
{
|
||||
strncpy(combinedPath, newDirectory, FILENAME_LENGTH);
|
||||
combinedPath[FILENAME_LENGTH - 1] = 0;
|
||||
SafeStrncpy(combinedPath, newDirectory, ARRAY_SIZE(combinedPath));
|
||||
}
|
||||
else // Relative path
|
||||
{
|
||||
|
@ -818,8 +816,7 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
|||
}
|
||||
|
||||
// No - find the parent directory
|
||||
strncpy(combinedPath, currentDirectory, FILENAME_LENGTH);
|
||||
combinedPath[ARRAY_UPB(combinedPath)] = 0;
|
||||
SafeStrncpy(combinedPath, currentDirectory, ARRAY_SIZE(combinedPath));
|
||||
for(int i = strlen(combinedPath) - 2; i >= 0; i--)
|
||||
{
|
||||
if (combinedPath[i] == '/')
|
||||
|
@ -831,13 +828,12 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
|||
}
|
||||
else // Go to child directory
|
||||
{
|
||||
strncpy(combinedPath, currentDirectory, FILENAME_LENGTH);
|
||||
SafeStrncpy(combinedPath, currentDirectory, ARRAY_SIZE(combinedPath));
|
||||
if (!StringEndsWith(combinedPath, "/") && strlen(combinedPath) > 1)
|
||||
{
|
||||
strncat(combinedPath, "/", FILENAME_LENGTH);
|
||||
SafeStrncat(combinedPath, "/", ARRAY_SIZE(combinedPath));
|
||||
}
|
||||
strncat(combinedPath, newDirectory, FILENAME_LENGTH);
|
||||
combinedPath[ARRAY_UPB(combinedPath)] = 0;
|
||||
SafeStrncat(combinedPath, newDirectory, ARRAY_SIZE(combinedPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -850,7 +846,7 @@ void FtpResponder::ChangeDirectory(const char *newDirectory)
|
|||
// Verify the final path and change it if possible
|
||||
if (GetPlatform()->GetMassStorage()->DirectoryExists(combinedPath))
|
||||
{
|
||||
strncpy(currentDirectory, combinedPath, FILENAME_LENGTH);
|
||||
SafeStrncpy(currentDirectory, combinedPath, ARRAY_SIZE(currentDirectory));
|
||||
outBuf->copy("250 Directory successfully changed.\r\n");
|
||||
Commit(responderState);
|
||||
}
|
||||
|
|
|
@ -543,8 +543,7 @@ bool HttpResponder::GetJsonResponse(const char* request, OutputBuffer *&response
|
|||
if (nameVal != nullptr)
|
||||
{
|
||||
// Regular rr_fileinfo?name=xxx call
|
||||
strncpy(filenameBeingProcessed, nameVal, ARRAY_SIZE(filenameBeingProcessed));
|
||||
filenameBeingProcessed[ARRAY_UPB(filenameBeingProcessed)] = 0;
|
||||
SafeStrncpy(filenameBeingProcessed, nameVal, ARRAY_SIZE(filenameBeingProcessed));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -867,8 +866,7 @@ void HttpResponder::SendJsonResponse(const char* command)
|
|||
{
|
||||
const char *configPath = GetPlatform()->GetMassStorage()->CombineName(GetPlatform()->GetSysDir(), GetPlatform()->GetConfigFile());
|
||||
char fileName[FILENAME_LENGTH];
|
||||
strncpy(fileName, configPath, FILENAME_LENGTH);
|
||||
|
||||
SafeStrncpy(fileName, configPath, ARRAY_SIZE(fileName));
|
||||
SendFile(fileName, false);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ const Port DefaultTelnetPort = 23;
|
|||
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
fileBeingUploaded.Set(file);
|
||||
strncpy(filenameBeingUploaded, fileName, ARRAY_SIZE(filenameBeingUploaded));
|
||||
filenameBeingUploaded[ARRAY_UPB(filenameBeingUploaded)] = 0;
|
||||
SafeStrncpy(filenameBeingUploaded, fileName, ARRAY_SIZE(filenameBeingUploaded));
|
||||
responderState = ResponderState::uploading;
|
||||
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
|
||||
queueCode = false;
|
||||
codeToRunLength = strlen(queuedItems->code);
|
||||
strncpy(codeToRun, queuedItems->code, codeToRunLength);
|
||||
codeToRun[ARRAY_UPB(codeToRun)] = 0;
|
||||
SafeStrncpy(codeToRun, queuedItems->code, ARRAY_SIZE(codeToRun));
|
||||
|
||||
// Release the first queued item so that it can be reused later
|
||||
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
|
||||
QueuedCode *code = freeItems;
|
||||
QueuedCode * const code = freeItems;
|
||||
freeItems = code->next;
|
||||
code->AssignFrom(gb);
|
||||
code->executeAtMove = scheduledMoves;
|
||||
|
@ -223,8 +222,7 @@ void GCodeQueue::Diagnostics(MessageType mtype)
|
|||
void QueuedCode::AssignFrom(GCodeBuffer &gb)
|
||||
{
|
||||
toolNumberAdjust = gb.GetToolNumberAdjust();
|
||||
strncpy(code, gb.Buffer(), GCODE_LENGTH);
|
||||
code[ARRAY_UPB(code)] = 0;
|
||||
SafeStrncpy(code, gb.Buffer(), ARRAY_SIZE(code));
|
||||
}
|
||||
|
||||
void QueuedCode::AssignTo(GCodeBuffer *gb)
|
||||
|
|
|
@ -40,11 +40,11 @@
|
|||
|
||||
const char GCodes::axisLetters[MAX_AXES] = { 'X', 'Y', 'Z', 'U', 'V', 'W' };
|
||||
|
||||
const char* PAUSE_G = "pause.g";
|
||||
const char* HomingFileNames[MAX_AXES] = { "homex.g", "homey.g", "homez.g", "homeu.g", "homev.g", "homew.g" };
|
||||
const char* HOME_ALL_G = "homeall.g";
|
||||
const char* HOME_DELTA_G = "homedelta.g";
|
||||
const char* DefaultHeightMapFile = "heightmap.csv";
|
||||
const char* const PAUSE_G = "pause.g";
|
||||
const char* const HomingFileNames[MAX_AXES] = { "homex.g", "homey.g", "homez.g", "homeu.g", "homev.g", "homew.g" };
|
||||
const char* const HOME_ALL_G = "homeall.g";
|
||||
const char* const HOME_DELTA_G = "homedelta.g";
|
||||
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
|
||||
|
||||
|
@ -366,7 +366,10 @@ void GCodes::Spin()
|
|||
if (LockMovementAndWaitForStandstill(gb))
|
||||
{
|
||||
gb.SetState(GCodeState::pausing2);
|
||||
DoFileMacro(gb, PAUSE_G, true);
|
||||
if (AllAxesAreHomed())
|
||||
{
|
||||
DoFileMacro(gb, PAUSE_G, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -511,7 +514,7 @@ void GCodes::Spin()
|
|||
moveBuffer.coords[Y_AXIS] = y - platform->GetCurrentZProbeParameters().yOffset;
|
||||
moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
|
||||
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
|
||||
moveBuffer.xAxes = 0;
|
||||
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||
segmentsLeft = 1;
|
||||
gb.AdvanceState();
|
||||
}
|
||||
|
@ -551,7 +554,7 @@ void GCodes::Spin()
|
|||
moveBuffer.filePos = noFilePosition;
|
||||
moveBuffer.coords[Z_AXIS] = -platform->GetZProbeDiveHeight();
|
||||
moveBuffer.feedRate = platform->GetCurrentZProbeParameters().probeSpeed;
|
||||
moveBuffer.xAxes = 0;
|
||||
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||
segmentsLeft = 1;
|
||||
gb.SetState(GCodeState::gridProbing3);
|
||||
}
|
||||
|
@ -579,7 +582,7 @@ void GCodes::Spin()
|
|||
moveBuffer.filePos = noFilePosition;
|
||||
moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
|
||||
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
|
||||
moveBuffer.xAxes = 0;
|
||||
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||
segmentsLeft = 1;
|
||||
gb.SetState(GCodeState::gridProbing4);
|
||||
}
|
||||
|
@ -1300,7 +1303,7 @@ int GCodes::SetUpMove(GCodeBuffer& gb, StringRef& reply)
|
|||
if (ival == 1 || ival == 2)
|
||||
{
|
||||
moveBuffer.moveType = ival;
|
||||
moveBuffer.xAxes = 0; // don't do bed compensation
|
||||
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||
}
|
||||
|
||||
if (ival == 1)
|
||||
|
@ -1686,7 +1689,7 @@ bool GCodes::DoCannedCycleMove(GCodeBuffer& gb, EndstopChecks ce)
|
|||
}
|
||||
}
|
||||
moveBuffer.feedRate = cannedFeedRate;
|
||||
moveBuffer.xAxes = 0;
|
||||
moveBuffer.xAxes = DefaultXAxisMapping;
|
||||
moveBuffer.endStopsToCheck = ce;
|
||||
moveBuffer.filePos = noFilePosition;
|
||||
moveBuffer.usePressureAdvance = false;
|
||||
|
|
|
@ -22,19 +22,16 @@
|
|||
|
||||
#ifdef DUET_NG
|
||||
# include "FirmwareUpdater.h"
|
||||
# ifdef DUET_WIFI
|
||||
# include "MessageFormats.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
const char* BED_EQUATION_G = "bed.g";
|
||||
const char* RESUME_G = "resume.g";
|
||||
const char* CANCEL_G = "cancel.g";
|
||||
const char* STOP_G = "stop.g";
|
||||
const char* SLEEP_G = "sleep.g";
|
||||
const char* CONFIG_OVERRIDE_G = "config-override.g";
|
||||
const char* DEPLOYPROBE_G = "deployprobe.g";
|
||||
const char* RETRACTPROBE_G = "retractprobe.g";
|
||||
const char* const BED_EQUATION_G = "bed.g";
|
||||
const char* const RESUME_G = "resume.g";
|
||||
const char* const CANCEL_G = "cancel.g";
|
||||
const char* const STOP_G = "stop.g";
|
||||
const char* const SLEEP_G = "sleep.g";
|
||||
const char* const CONFIG_OVERRIDE_G = "config-override.g";
|
||||
const char* const DEPLOYPROBE_G = "deployprobe.g";
|
||||
const char* const RETRACTPROBE_G = "retractprobe.g";
|
||||
|
||||
const float MinServoPulseWidth = 544.0, MaxServoPulseWidth = 2400.0;
|
||||
const uint16_t ServoRefreshFrequency = 50;
|
||||
|
@ -324,13 +321,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
|
|||
if (wasPaused)
|
||||
{
|
||||
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 (code == 0)
|
||||
// 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 && 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)
|
||||
{
|
||||
gb.SetState(GCodeState::resuming1);
|
||||
DoFileMacro(gb, RESUME_G, true);
|
||||
if (AllAxesAreHomed())
|
||||
{
|
||||
DoFileMacro(gb, RESUME_G, true);
|
||||
}
|
||||
}
|
||||
else if (!fileToPrint.IsLive())
|
||||
{
|
||||
|
|
|
@ -216,7 +216,8 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
|||
}
|
||||
|
||||
isPrintingMove = false;
|
||||
bool realMove = false, xyMoving = false, xyzMoving = false;
|
||||
bool realMove = false, xyzMoving = false;
|
||||
xyMoving = false;
|
||||
const bool isSpecialDeltaMove = (move->IsDeltaMode() && !doMotorMapping);
|
||||
float accelerations[DRIVES];
|
||||
const float * const normalAccelerations = reprap.GetPlatform()->Accelerations();
|
||||
|
@ -239,10 +240,13 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
|||
directionVector[drive] = positionDelta;
|
||||
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)
|
||||
|
@ -287,6 +291,7 @@ bool DDA::Init(const GCodes::RawMove &nextMove, bool doMotorMapping)
|
|||
}
|
||||
|
||||
// 3. Store some values
|
||||
xAxes = nextMove.xAxes;
|
||||
endStopsToCheck = nextMove.endStopsToCheck;
|
||||
canPauseAfter = nextMove.canPauseAfter;
|
||||
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());
|
||||
}
|
||||
|
||||
totalDistance = Normalise(directionVector, DRIVES, numAxes);
|
||||
totalDistance = NormaliseXYZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -527,13 +532,13 @@ void DDA::AdvanceBabyStepping(float amount)
|
|||
while(cdda != this)
|
||||
{
|
||||
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
|
||||
const float maxBabySteppingAmount = cdda->totalDistance * min<float>(0.1, 0.5 * reprap.GetPlatform()->ConfiguredInstantDv(Z_AXIS)/cdda->topSpeed);
|
||||
babySteppingToDo = constrain<float>(amount, -maxBabySteppingAmount, maxBabySteppingAmount);
|
||||
cdda->directionVector[Z_AXIS] += babySteppingToDo/cdda->totalDistance;
|
||||
cdda->totalDistance *= Normalise(cdda->directionVector, DRIVES, reprap.GetGCodes()->GetNumAxes());
|
||||
cdda->totalDistance *= cdda->NormaliseXYZ();
|
||||
cdda->RecalculateMove();
|
||||
babySteppingDone += babySteppingToDo;
|
||||
amount -= babySteppingToDo;
|
||||
|
@ -991,7 +996,7 @@ void DDA::Prepare()
|
|||
|
||||
// Take a unit positive-hyperquadrant vector, and return the factor needed to obtain
|
||||
// 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
|
||||
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
|
||||
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)
|
||||
{
|
||||
return 0.0;
|
||||
|
@ -1022,8 +1027,37 @@ float DDA::Normalise(float v[], size_t dim1, size_t dim2)
|
|||
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
|
||||
float DDA::Magnitude(const float v[], size_t dimensions)
|
||||
/*static*/ float DDA::Magnitude(const float v[], size_t dimensions)
|
||||
{
|
||||
float magnitude = 0.0;
|
||||
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
|
||||
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
|
||||
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]);
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ private:
|
|||
void DebugPrintVector(const char *name, const float *vec, size_t len) const;
|
||||
void CheckEndstops(Platform *platform);
|
||||
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 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 *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 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
|
||||
|
@ -127,10 +128,12 @@ private:
|
|||
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 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
|
||||
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
|
||||
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)
|
||||
{
|
||||
printingFileParsed = GetFileInfo(platform->GetGCodeDir(), filename, printingFileInfo);
|
||||
strncpy(filenameBeingPrinted, filename, ARRAY_SIZE(filenameBeingPrinted));
|
||||
filenameBeingPrinted[ARRAY_UPB(filenameBeingPrinted)] = 0;
|
||||
SafeStrncpy(filenameBeingPrinted, filename, ARRAY_SIZE(filenameBeingPrinted));
|
||||
}
|
||||
|
||||
// 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
|
||||
strncpy(filenameBeingParsed, fileName, ARRAY_SIZE(filenameBeingParsed));
|
||||
filenameBeingParsed[ARRAY_UPB(filenameBeingParsed)] = 0;
|
||||
SafeStrncpy(filenameBeingParsed, fileName, ARRAY_SIZE(filenameBeingParsed));
|
||||
fileOverlapLength = 0;
|
||||
|
||||
// Set up the info struct
|
||||
|
|
|
@ -1323,8 +1323,7 @@ OutputBuffer *RepRap::GetFilesResponse(const char *dir, bool flagsDirs)
|
|||
// Get the long filename if possible
|
||||
if (flagsDirs && fileInfo.isDirectory)
|
||||
{
|
||||
strncpy(filename + sizeof(char), fileInfo.fileName, FILENAME_LENGTH - 1);
|
||||
filename[FILENAME_LENGTH - 1] = 0;
|
||||
SafeStrncpy(filename + 1, fileInfo.fileName, ARRAY_SIZE(fileInfo.fileName) - 1);
|
||||
fname = filename;
|
||||
}
|
||||
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.
|
||||
void RepRap::SetMessage(const char *msg)
|
||||
{
|
||||
strncpy(message, msg, MESSAGE_LENGTH);
|
||||
message[MESSAGE_LENGTH] = 0;
|
||||
SafeStrncpy(message, msg, ARRAY_SIZE(message));
|
||||
|
||||
if (platform->HaveAux())
|
||||
{
|
||||
|
|
|
@ -271,4 +271,20 @@ int StringContains(const char* string, const char* match)
|
|||
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
|
||||
|
|
|
@ -78,6 +78,8 @@ bool StringEndsWith(const char* string, const char* ending);
|
|||
bool StringStartsWith(const char* string, const char* starting);
|
||||
bool StringEquals(const char* s1, const char* s2);
|
||||
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
|
||||
#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
|
||||
scanParam = param;
|
||||
strncpy(scanFilename, filename, ARRAY_SIZE(scanFilename));
|
||||
scanFilename[ARRAY_UPB(scanFilename)] = 0;
|
||||
SafeStrncpy(scanFilename, filename, ARRAY_SIZE(scanFilename));
|
||||
|
||||
// Run the scan_pre macro and wait for it to finish
|
||||
DoFileMacro(SCAN_PRE_G);
|
||||
|
|
|
@ -123,21 +123,12 @@ bool MassStorage::FindFirst(const char *directory, FileInfo &file_info)
|
|||
TCHAR loc[FILENAME_LENGTH + 1];
|
||||
|
||||
// Remove the trailing '/' from the directory name
|
||||
size_t len = strnlen(directory, ARRAY_UPB(loc));
|
||||
if (len == 0)
|
||||
SafeStrncpy(loc, directory, ARRAY_SIZE(loc));
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(loc, directory, len);
|
||||
loc[len] = 0;
|
||||
}
|
||||
|
||||
findDir.lfn = nullptr;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
@ -189,7 +180,7 @@ bool MassStorage::FindNext(FileInfo &file_info)
|
|||
|
||||
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);
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
#define SRC_VERSION_H_
|
||||
|
||||
#ifndef VERSION
|
||||
# define VERSION "1.19alpha"
|
||||
# define VERSION "1.19alpha1"
|
||||
#endif
|
||||
|
||||
#ifndef DATE
|
||||
# define DATE "2017-05-01"
|
||||
# define DATE "2017-05-04"
|
||||
#endif
|
||||
|
||||
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"
|
||||
|
|
Reference in a new issue