1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
/*
* GCodeBuffer.h
*
* Created on: 6 Feb 2015
* Author: David
*/
#ifndef SRC_GCODES_GCODEBUFFER_GCODEBUFFER_H
#define SRC_GCODES_GCODEBUFFER_GCODEBUFFER_H
#include "BinaryParser.h"
#include "StringParser.h"
#include "RepRapFirmware.h"
#include "GCodes/GCodeChannel.h"
#include "GCodes/GCodeMachineState.h"
#include "GCodes/GCodeResult.h"
#include "Linux/LinuxMessageFormats.h"
#include "MessageType.h"
#include "ObjectModel/ObjectModel.h"
class FileGCodeInput;
// The processing state of each buffer
enum class GCodeBufferState : uint8_t
{
parseNotStarted, // we haven't started parsing yet
parsingLineNumber, // we saw N at the start and we are parsing the line number
parsingWhitespace, // parsing whitespace after the line number
parsingComment, // parsing a whole-line comment that we may be interested in
parsingGCode, // parsing GCode words
parsingBracketedComment, // inside a (...) comment
parsingQuotedString, // inside a double-quoted string
parsingChecksum, // parsing the checksum after '*'
discarding, // discarding characters after the checksum or an end-of-line comment
ready, // we have a complete gcode but haven't started executing it
executing // we have a complete gcode and have started executing it
};
// Class to hold an individual GCode and provide functions to allow it to be parsed
class GCodeBuffer INHERIT_OBJECT_MODEL
{
public:
friend class BinaryParser;
friend class StringParser;
GCodeBuffer(GCodeChannel::RawType channel, GCodeInput *normalIn, FileGCodeInput *fileIn, MessageType mt, Compatibility::RawType c = Compatibility::RepRapFirmware) noexcept;
void Reset() noexcept; // Reset it to its state after start-up
void Init() noexcept; // Set it up to parse another G-code
void Diagnostics(MessageType mtype) noexcept; // Write some debug info
bool Put(char c) noexcept __attribute__((hot)); // Add a character to the end
#if HAS_LINUX_INTERFACE
void PutAndDecode(const char *data, size_t len, bool isBinary = false) noexcept; // Add an entire G-Code, overwriting any existing content
#else
void PutAndDecode(const char *data, size_t len) noexcept; // Add an entire G-Code, overwriting any existing content
#endif
void PutAndDecode(const char *str) noexcept; // Add a null-terminated string, overwriting any existing content
void StartNewFile() noexcept; // Called when we start a new file
bool FileEnded() noexcept; // Called when we reach the end of the file we are reading from
void DecodeCommand() noexcept; // Decode the command in the buffer when it is complete
bool CheckMetaCommand(const StringRef& reply) THROWS(GCodeException); // Check whether the current command is a meta command, or we are skipping a block
char GetCommandLetter() const noexcept;
bool HasCommandNumber() const noexcept;
int GetCommandNumber() const noexcept;
int8_t GetCommandFraction() const noexcept; // Return the command fraction, or -1 if none given
bool ContainsExpression() const noexcept;
void GetCompleteParameters(const StringRef& str) THROWS(GCodeException); // Get all of the line following the command. Currently called only for the Q0 command.
int32_t GetLineNumber() const noexcept { return machineState->lineNumber; }
GCodeResult GetLastResult() const noexcept { return lastResult; }
void SetLastResult(GCodeResult r) noexcept { lastResult = r; }
bool Seen(char c) noexcept __attribute__((hot)); // Is a character present?
void MustSee(char c) THROWS(GCodeException); // Test for character present, throw error if not
float GetFValue() THROWS(GCodeException) __attribute__((hot)); // Get a float after a key letter
float GetDistance() THROWS(GCodeException); // Get a distance or coordinate and convert it from inches to mm if necessary
int32_t GetIValue() THROWS(GCodeException) __attribute__((hot)); // Get an integer after a key letter
int32_t GetLimitedIValue(char c, int32_t minValue, int32_t maxValue) THROWS(GCodeException)
post(minValue <= result; result <= maxValue); // Get an integer after a key letter
uint32_t GetUIValue() THROWS(GCodeException); // Get an unsigned integer value
uint32_t GetLimitedUIValue(char c, uint32_t maxValuePlusOne, uint32_t minValue = 0) THROWS(GCodeException)
pre(maxValuePlusOne > minValue)
post(result >= minValue; result < maxValuePlusOne); // Get an unsigned integer value, throw if outside limits
void GetIPAddress(IPAddress& returnedIp) THROWS(GCodeException); // Get an IP address quad after a key letter
void GetMacAddress(MacAddress& mac) THROWS(GCodeException); // Get a MAC address sextet after a key letter
PwmFrequency GetPwmFrequency() THROWS(GCodeException); // Get a PWM frequency
float GetPwmValue() THROWS(GCodeException); // Get a PWM value
DriverId GetDriverId() THROWS(GCodeException); // Get a driver ID
void GetUnprecedentedString(const StringRef& str, bool allowEmpty = false) THROWS(GCodeException); // Get a string with no preceding key letter
void GetQuotedString(const StringRef& str) THROWS(GCodeException); // Get and copy a quoted string
void GetPossiblyQuotedString(const StringRef& str) THROWS(GCodeException); // Get and copy a string which may or may not be quoted
void GetReducedString(const StringRef& str) THROWS(GCodeException); // Get and copy a quoted string, removing certain characters
void GetFloatArray(float arr[], size_t& length, bool doPad) THROWS(GCodeException) __attribute__((hot)); // Get a colon-separated list of floats after a key letter
void GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS(GCodeException); // Get a :-separated list of ints after a key letter
void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS(GCodeException); // Get a :-separated list of unsigned ints after a key letter
void GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of drivers after a key letter
bool TryGetFValue(char c, float& val, bool& seen) THROWS(GCodeException);
bool TryGetIValue(char c, int32_t& val, bool& seen) THROWS(GCodeException);
bool TryGetLimitedIValue(char c, int32_t& val, bool& seen, int32_t minValue, int32_t maxValue) THROWS(GCodeException);
bool TryGetUIValue(char c, uint32_t& val, bool& seen) THROWS(GCodeException);
bool TryGetLimitedUIValue(char c, uint32_t& val, bool& seen, uint32_t maxValuePlusOne) THROWS(GCodeException);
bool TryGetBValue(char c, bool& val, bool& seen) THROWS(GCodeException);
bool TryGetFloatArray(char c, size_t numVals, float vals[], const StringRef& reply, bool& seen, bool doPad = false) THROWS(GCodeException);
bool TryGetUIArray(char c, size_t numVals, uint32_t vals[], const StringRef& reply, bool& seen, bool doPad = false) THROWS(GCodeException);
bool TryGetQuotedString(char c, const StringRef& str, bool& seen) THROWS(GCodeException);
bool TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen) THROWS(GCodeException);
bool IsIdle() const noexcept;
bool IsCompletelyIdle() const noexcept;
bool IsReady() const noexcept; // Return true if a gcode is ready but hasn't been started yet
bool IsExecuting() const noexcept; // Return true if a gcode has been started and is not paused
void SetFinished(bool f) noexcept; // Set the G Code executed (or not)
void SetCommsProperties(uint32_t arg) noexcept;
GCodeMachineState& MachineState() const noexcept { return *machineState; }
GCodeMachineState& OriginalMachineState() const noexcept;
float ConvertDistance(float distance) const noexcept;
float InverseConvertDistance(float distance) const noexcept;
unsigned int GetStackDepth() const noexcept;
bool PushState(bool withinSameFile) noexcept; // Push state returning true if successful (i.e. stack not overflowed)
bool PopState(bool withinSameFile) noexcept; // Pop state returning true if successful (i.e. no stack underrun)
bool IsPausing() const;
bool IsResuming() const;
void AbortFile(bool abortAll, bool requestAbort = true) noexcept;
bool IsDoingFile() const noexcept; // Return true if this source is executing a file
bool IsDoingLocalFile() const noexcept; // Return true if this source is executing a file from the local SD card
bool IsDoingFileMacro() const noexcept; // Return true if this source is executing a file macro
FilePosition GetFilePosition() const noexcept; // Get the file position at the start of the current command
#if HAS_LINUX_INTERFACE
bool IsBinary() const noexcept { return isBinaryBuffer; } // Return true if the code is in binary format
bool IsFileFinished() const noexcept; // Return true if this source has finished execution of a file
void SetFileFinished(bool error) noexcept; // Mark the last file as finished
void SetPrintFinished() noexcept; // Mark the print file as finished
bool RequestMacroFile(const char *filename, bool fromCode) noexcept; // Request execution of a file macro
bool IsWaitingForMacro() const noexcept { return isWaitingForMacro; } // Indicates if the GB is waiting for a macro to be opened
bool HasStartedMacro() const noexcept { return hasStartedMacro; } // Has this GB just started a new macro file?
bool IsMacroRequestPending() const noexcept { return !requestedMacroFile.IsEmpty(); } // Indicates if a macro file is being requested
const char *GetRequestedMacroFile() const noexcept { return requestedMacroFile.c_str(); } // Return requested macro file or nullptr if none
bool IsMacroFromCode() const noexcept { return machineState->isMacroFromCode; } // Returns if the macro was requested from a code
void MacroRequestSent() noexcept { requestedMacroFile.Clear(); } // Called when a macro file request has been sent
void ResolveMacroRequest(bool hadError, bool isEmpty) noexcept; // Resolve the call waiting for a macro to be executed
bool IsMacroEmpty() const noexcept { return macroEmpty; } // Returns if the last opened macro file is empty
bool IsAbortRequested() const noexcept; // Is the cancellation of the current file requested?
bool IsAbortAllRequested() const noexcept; // Is the cancellation of all files being executed on this channel requested?
void AcknowledgeAbort() noexcept; // Indicates that the current macro file is being cancelled
bool IsInvalidated() const noexcept { return invalidated; } // Indicates if the channel is invalidated
void Invalidate(bool i = true) noexcept { invalidated = i; } // Invalidate this channel (or not)
bool IsSendRequested() const noexcept { return sendToSbc; } // Is this code supposed to be sent to the SBC
void SendToSbc() noexcept { sendToSbc = true; } // Send this code to the attached SBC
#endif
GCodeState GetState() const noexcept;
void SetState(GCodeState newState) noexcept;
void AdvanceState() noexcept;
void MessageAcknowledged(bool cancelled) noexcept;
GCodeChannel GetChannel() const noexcept { return codeChannel; }
const char *GetIdentity() const noexcept { return codeChannel.ToString(); }
bool CanQueueCodes() const noexcept;
MessageType GetResponseMessageType() const noexcept;
#if HAS_MASS_STORAGE
bool OpenFileToWrite(const char* directory, const char* fileName, const FilePosition size, const bool binaryWrite, const uint32_t fileCRC32) noexcept;
// open a file to write to
bool IsWritingFile() const noexcept; // Returns true if writing a file
void WriteToFile() noexcept; // Write the current GCode to file
bool IsWritingBinary() const noexcept; // Returns true if writing binary
void WriteBinaryToFile(char b) noexcept; // Write a byte to the file
void FinishWritingBinary() noexcept;
#endif
const char* DataStart() const noexcept; // Get the start of the current command
size_t DataLength() const noexcept; // Get the length of the current command
void PrintCommand(const StringRef& s) const noexcept;
void AppendFullCommand(const StringRef &s) const noexcept;
bool IsTimerRunning() const noexcept { return timerRunning; }
uint32_t WhenTimerStarted() const noexcept { return whenTimerStarted; }
void StartTimer() noexcept;
void StopTimer() noexcept { timerRunning = false; }
bool DoDwellTime(uint32_t dwellMillis) noexcept; // Execute a dwell returning true if it has finished
void ResetReportDueTimer() noexcept { whenReportDueTimerStarted = millis(); };
bool IsReportDue() noexcept;
void RestartFrom(FilePosition pos) noexcept;
#if HAS_MASS_STORAGE
FileGCodeInput *GetFileInput() const noexcept { return fileInput; }
#endif
GCodeInput *GetNormalInput() const noexcept { return normalInput; }
void MotionCommanded() noexcept { motionCommanded = true; }
void MotionStopped() noexcept { motionCommanded = false; }
bool WasMotionCommanded() const noexcept { return motionCommanded; }
Mutex mutex;
protected:
DECLARE_OBJECT_MODEL
private:
#if SUPPORT_OBJECT_MODEL
const char *GetStateText() const noexcept;
#endif
const GCodeChannel codeChannel; // Channel number of this instance
GCodeInput *normalInput; // Our normal input stream, or nullptr if there isn't one
#if HAS_MASS_STORAGE
FileGCodeInput *fileInput; // Our file input stream for when we are reading from a print file or a macro file, may be shared with other GCodeBuffers
#endif
const MessageType responseMessageType; // The message type we use for responses to string codes coming from this channel
GCodeResult lastResult;
#if HAS_LINUX_INTERFACE
BinaryParser binaryParser;
#endif
StringParser stringParser;
GCodeBufferState bufferState; // Idle, executing or paused
GCodeMachineState *machineState; // Machine state for this gcode source
uint32_t whenTimerStarted; // When we started waiting
uint32_t whenReportDueTimerStarted; // When the report-due-timer has been started
static constexpr uint32_t reportDueInterval = 1000; // Interval in which we send in ms
#if HAS_LINUX_INTERFACE
bool isBinaryBuffer;
#endif
bool timerRunning; // True if we are waiting
bool motionCommanded; // true if this GCode stream has commanded motion since it last waited for motion to stop
#if HAS_LINUX_INTERFACE
alignas(4) char buffer[MaxCodeBufferSize]; // must be aligned because we do dword fetches from it
#else
char buffer[GCODE_LENGTH];
#endif
#if HAS_LINUX_INTERFACE
String<MaxFilenameLength> requestedMacroFile;
uint8_t
isWaitingForMacro : 1, // Is this GB waiting in DoFileMacro?
hasStartedMacro : 1, // Whether the GB has just started a macro file
macroEmpty : 1, // May be true if the macro file could be opened but it is empty
macroError : 1, // Whether the macro file could be opened or if an error occurred
abortFile : 1, // Whether to abort the last file on the stack
abortAllFiles : 1, // Whether to abort all opened files
invalidated : 1, // Set to true if the GB content is not valid and about to be cleared
sendToSbc : 1; // Indicates if the GB string content is supposed to be sent to the SBC
BinarySemaphore macroSemaphore;
#endif
};
inline bool GCodeBuffer::IsDoingFileMacro() const noexcept
{
return machineState->doingFileMacro;
}
inline GCodeState GCodeBuffer::GetState() const noexcept
{
return machineState->GetState();
}
inline void GCodeBuffer::SetState(GCodeState newState) noexcept
{
machineState->SetState(newState);
}
inline void GCodeBuffer::AdvanceState() noexcept
{
machineState->AdvanceState();
}
// Return true if we can queue gcodes from this source. This is the case if a file is being executed
inline bool GCodeBuffer::CanQueueCodes() const noexcept
{
return IsDoingFile();
}
inline bool GCodeBuffer::IsDoingFile() const noexcept
{
return machineState->DoingFile();
}
// Return true if this source is executing a file from the local SD card
inline bool GCodeBuffer::IsDoingLocalFile() const noexcept
{
#if HAS_LINUX_INTERFACE
return !IsBinary() && IsDoingFile();
#else
return IsDoingFile();
#endif
}
#if HAS_LINUX_INTERFACE
inline bool GCodeBuffer::IsAbortRequested() const noexcept
{
return abortFile;
}
inline bool GCodeBuffer::IsAbortAllRequested() const noexcept
{
return abortAllFiles;
}
inline void GCodeBuffer::AcknowledgeAbort() noexcept
{
abortFile = abortAllFiles = false;
}
#endif
#endif /* SRC_GCODES_GCODEBUFFER_GCODEBUFFER_H */
|