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:
David Crocker 2017-05-04 21:39:43 +01:00
parent 9d4c15c5db
commit 384d1d3ad4
25 changed files with 219 additions and 111 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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.

View file

@ -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;
}

View file

@ -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)

View file

@ -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;

View file

@ -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())
{

View file

@ -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]);
}

View file

@ -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

View file

@ -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

View file

@ -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())
{

View file

@ -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

View file

@ -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));

View file

@ -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);

View file

@ -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);

View file

@ -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"