
Incorporated zpl's Network module updates and some of his Gcodes updated Merged RRP's 0.96 Move code into mine Added M105 S3, M20 S2 and M36 commands for supporting TFT control panel Added X parameter to M305 command to allow thermistor channels to be changed Removed space after "B:" in M105 response to avoid confusing Pronterface
325 lines
14 KiB
C++
325 lines
14 KiB
C++
/****************************************************************************************************
|
|
|
|
RepRapFirmware - G Codes
|
|
|
|
This class interprets G Codes from one or more sources, and calls the functions in Move, Heat etc
|
|
that drive the machine to do what the G Codes command.
|
|
|
|
-----------------------------------------------------------------------------------------------------
|
|
|
|
Version 0.1
|
|
|
|
13 February 2013
|
|
|
|
Adrian Bowyer
|
|
RepRap Professional Ltd
|
|
http://reprappro.com
|
|
|
|
Licence: GPL
|
|
|
|
****************************************************************************************************/
|
|
|
|
#ifndef GCODES_H
|
|
#define GCODES_H
|
|
|
|
#define STACK 5
|
|
#define GCODE_LENGTH 100 // Maximum length of internally-generated G Code string
|
|
|
|
const char feedrateLetter = 'F'; // GCode feedrate
|
|
const char extrudeLetter = 'E'; // GCode extrude
|
|
|
|
// Type for specifying which endstops we want to check
|
|
typedef uint8_t EndstopChecks;
|
|
|
|
// Small class to hold an individual GCode and provide functions to allow it to be parsed
|
|
|
|
class GCodeBuffer
|
|
{
|
|
public:
|
|
GCodeBuffer(Platform* p, const char* id);
|
|
void Init(); // Set it up
|
|
bool Put(char c); // Add a character to the end
|
|
bool Put(const char *str, size_t len); // Add an entire string
|
|
bool IsEmpty() const; // Does this buffer contain any code?
|
|
bool Seen(char c); // Is a character present?
|
|
float GetFValue(); // Get a float after a key letter
|
|
int GetIValue(); // Get an integer after a key letter
|
|
long GetLValue(); // Get a long integer after a key letter
|
|
const char* GetUnprecedentedString(bool optional = false); // Get a string with no preceding key letter
|
|
const char* GetString(); // Get a string after a key letter
|
|
const void GetFloatArray(float a[], int& length); // Get a :-separated list of floats after a key letter
|
|
const void GetLongArray(long l[], int& length); // Get a :-separated list of longs after a key letter
|
|
const char* Buffer() const;
|
|
bool Active() const;
|
|
void SetFinished(bool f); // Set the G Code executed (or not)
|
|
void Pause();
|
|
void CancelPause();
|
|
void Resume();
|
|
const char* WritingFileDirectory() const; // If we are writing the G Code to a file, where that file is
|
|
void SetWritingFileDirectory(const char* wfd); // Set the directory for the file to write the GCode in
|
|
int GetToolNumberAdjust() const { return toolNumberAdjust; }
|
|
void SetToolNumberAdjust(int arg) { toolNumberAdjust = arg; }
|
|
|
|
private:
|
|
|
|
enum State { idle, executing, paused };
|
|
int CheckSum(); // Compute the checksum (if any) at the end of the G Code
|
|
Platform* platform; // Pointer to the RepRap's controlling class
|
|
char gcodeBuffer[GCODE_LENGTH]; // The G Code
|
|
const char* identity; // Where we are from (web, file, serial line etc)
|
|
int gcodePointer; // Index in the buffer
|
|
int readPointer; // Where in the buffer to read next
|
|
bool inComment; // Are we after a ';' character?
|
|
State state; // Idle, executing or paused
|
|
const char* writingFileDirectory; // If the G Code is going into a file, where that is
|
|
int toolNumberAdjust;
|
|
};
|
|
|
|
//****************************************************************************************************
|
|
|
|
// The GCode interpreter
|
|
|
|
class GCodes
|
|
{
|
|
public:
|
|
|
|
GCodes(Platform* p, Webserver* w);
|
|
void Spin(); // Called in a tight loop to make this class work
|
|
void Init(); // Set it up
|
|
void Exit(); // Shut it down
|
|
void Reset(); // Reset some parameter to defaults
|
|
bool RunConfigurationGCodes(); // Run the configuration G Code file on reboot
|
|
bool ReadMove(float* m, EndstopChecks& ce); // Called by the Move class to get a movement set by the last G Code
|
|
void QueueFileToPrint(const char* fileName); // Open a file of G Codes to run
|
|
void DeleteFile(const char* fileName); // Does what it says
|
|
bool GetProbeCoordinates(int count, float& x, float& y, float& z) const; // Get pre-recorded probe coordinates
|
|
const char* GetCurrentCoordinates() const; // Get where we are as a string
|
|
bool PrintingAFile() const; // Are we in the middle of printing a file?
|
|
float FractionOfFilePrinted() const; // Get fraction of file printed
|
|
void Diagnostics(); // Send helpful information out
|
|
bool HaveIncomingData() const; // Is there something that we have to do?
|
|
bool GetAxisIsHomed(uint8_t axis) const { return axisIsHomed[axis]; } // Is the axis at 0?
|
|
void SetAxisIsHomed(uint8_t axis) { axisIsHomed[axis] = true; } // Tell us that the axis is now homes
|
|
bool CoolingInverted() const; // Is the current fan value inverted?
|
|
float GetExtruderPosition(uint8_t extruder) const; // Get the amount of filament extruded
|
|
void PauseSDPrint(); // Pause the current print from SD card
|
|
float GetSpeedFactor() const { return speedFactor * 60.0; } // Return the current speed factor
|
|
const float *GetExtrusionFactors() const { return extrusionFactors; } // Return the current extrusion factors
|
|
|
|
private:
|
|
|
|
void DoFilePrint(GCodeBuffer* gb); // Get G Codes from a file and print them
|
|
bool AllMovesAreFinishedAndMoveBufferIsLoaded(); // Wait for move queue to exhaust and the current position is loaded
|
|
bool DoCannedCycleMove(EndstopChecks ce); // Do a move from an internally programmed canned cycle
|
|
bool DoFileMacro(const char* fileName); // Run a GCode macro in a file
|
|
bool FileMacroCyclesReturn(); // End a macro
|
|
bool ActOnCode(GCodeBuffer* gb); // Do a G, M or T Code
|
|
bool HandleGcode(GCodeBuffer* gb); // Do a G code
|
|
bool HandleMcode(GCodeBuffer* gb); // Do an M code
|
|
bool HandleTcode(GCodeBuffer* gb); // Do a T code
|
|
int SetUpMove(GCodeBuffer* gb); // Pass a move on to the Move module
|
|
bool DoDwell(GCodeBuffer *gb); // Wait for a bit
|
|
bool DoDwellTime(float dwell); // Really wait for a bit
|
|
bool DoHome(StringRef& reply, bool& error); // Home some axes
|
|
bool DoSingleZProbeAtPoint(); // Probe at a given point
|
|
bool DoSingleZProbe(); // Probe where we are
|
|
bool SetSingleZProbeAtAPosition(GCodeBuffer *gb, StringRef& reply); // Probes at a given position - see the comment at the head of the function itself
|
|
bool SetBedEquationWithProbe(StringRef& reply); // Probes a series of points and sets the bed equation
|
|
bool SetPrintZProbe(GCodeBuffer *gb, StringRef& reply); // Either return the probe value, or set its threshold
|
|
void SetOrReportOffsets(StringRef& reply, GCodeBuffer *gb); // Deal with a G10
|
|
bool SetPositions(GCodeBuffer *gb); // Deal with a G92
|
|
bool LoadMoveBufferFromGCode(GCodeBuffer *gb, // Set up a move for the Move class
|
|
bool doingG92, bool applyLimits);
|
|
bool NoHome() const; // Are we homing and not finished?
|
|
bool Push(); // Push feedrate etc on the stack
|
|
bool Pop(); // Pop feedrate etc
|
|
void DisableDrives(); // Turn the motors off
|
|
void SetEthernetAddress(GCodeBuffer *gb, int mCode); // Does what it says
|
|
void SetMACAddress(GCodeBuffer *gb); // Deals with an M540
|
|
void HandleReply(bool error, const GCodeBuffer *gb, // If the GCode is from the serial interface, reply to it
|
|
const char* reply, char gMOrT, int code, bool resend);
|
|
bool OpenFileToWrite(const char* directory, // Start saving GCodes in a file
|
|
const char* fileName, GCodeBuffer *gb);
|
|
void WriteGCodeToFile(GCodeBuffer *gb); // Write this GCode into a file
|
|
bool SendConfigToLine(); // Deal with M503
|
|
void WriteHTMLToFile(char b, GCodeBuffer *gb); // Save an HTML file (usually to upload a new web interface)
|
|
bool OffsetAxes(GCodeBuffer *gb); // Set offsets - deprecated, use G10
|
|
void SetPidParameters(GCodeBuffer *gb, int heater, StringRef& reply); // Set the P/I/D parameters for a heater
|
|
void SetHeaterParameters(GCodeBuffer *gb, StringRef& reply); // Set the thermistor and ADC parameters for a heater
|
|
int8_t Heater(int8_t head) const; // Legacy G codes start heaters at 0, but we use 0 for the bed. This sorts that out.
|
|
void AddNewTool(GCodeBuffer *gb, StringRef& reply); // Create a new tool definition
|
|
void SetToolHeaters(Tool *tool, float temperature); // Set all a tool's heaters to the temperature. For M104...
|
|
bool ChangeTool(int newToolNumber); // Select a new tool
|
|
bool ToolHeatersAtSetTemperatures(const Tool *tool) const; // Wait for the heaters associated with the specified tool to reach their set temperatures
|
|
|
|
Platform* platform; // The RepRap machine
|
|
bool active; // Live and running?
|
|
Webserver* webserver; // The webserver class
|
|
float dwellTime; // How long a pause for a dwell (seconds)?
|
|
bool dwellWaiting; // We are in a dwell
|
|
GCodeBuffer* webGCode; // The sources...
|
|
GCodeBuffer* fileGCode; // ...
|
|
GCodeBuffer* serialGCode; // ...
|
|
GCodeBuffer* auxGCode; // this one is for the LCD display on the async serial interface
|
|
GCodeBuffer* fileMacroGCode; // ...
|
|
bool moveAvailable; // Have we seen a move G Code and set it up?
|
|
float moveBuffer[DRIVES+1]; // Move coordinates; last is feed rate
|
|
EndstopChecks endStopsToCheck; // Which end stops we check them on the next move
|
|
bool drivesRelative; // Are movements relative - all except X, Y and Z
|
|
bool axesRelative; // Are movements relative - X, Y and Z
|
|
bool drivesRelativeStack[STACK]; // For dealing with Push and Pop
|
|
bool axesRelativeStack[STACK]; // For dealing with Push and Pop
|
|
float feedrateStack[STACK]; // For dealing with Push and Pop
|
|
FileData fileStack[STACK];
|
|
int8_t stackPointer; // Push and Pop stack pointer
|
|
static const char axisLetters[AXES]; // 'X', 'Y', 'Z'
|
|
float lastExtruderPosition[DRIVES - AXES]; // Extruder position of the last move fed into the Move class
|
|
float record[DRIVES+1]; // Temporary store for move positions
|
|
float moveToDo[DRIVES+1]; // Where to go set by G1 etc
|
|
bool activeDrive[DRIVES+1]; // Is this drive involved in a move?
|
|
bool offSetSet; // Are any axis offsets non-zero?
|
|
float distanceScale; // MM or inches
|
|
FileData fileBeingPrinted;
|
|
FileData fileToPrint;
|
|
FileStore* fileBeingWritten; // A file to write G Codes (or sometimes HTML) in
|
|
FileStore* configFile; // A file containing a macro
|
|
bool doingFileMacro; // Are we executing a macro file?
|
|
bool doResumeMacro; // Are we executing the pause/resume macro file?
|
|
float fractionOfFilePrinted; // Only used to record the main file when a macro is being printed
|
|
const char* eofString; // What's at the end of an HTML file?
|
|
uint8_t eofStringCounter; // Check the...
|
|
uint8_t eofStringLength; // ... EoF string as we read.
|
|
bool homing; // Are we homing any axes?
|
|
bool homeX; // True to home the X axis this move
|
|
bool homeY; // True to home the Y axis this move
|
|
bool homeZ; // True to home the Z axis this move
|
|
int probeCount; // Counts multiple probe points
|
|
int8_t cannedCycleMoveCount; // Counts through internal (i.e. not macro) canned cycle moves
|
|
bool cannedCycleMoveQueued; // True if a canned cycle move has been set
|
|
bool zProbesSet; // True if all Z probing is done and we can set the bed equation
|
|
bool settingBedEquationWithProbe; // True if we're executing G32 without a macro
|
|
float longWait; // Timer for things that happen occasionally (seconds)
|
|
bool limitAxes; // Don't think outside the box.
|
|
bool axisIsHomed[3]; // These record which of the axes have been homed
|
|
bool waitingForMoveToComplete;
|
|
bool coolingInverted;
|
|
float speedFactor; // speed factor, including the conversion from mm/min to mm/sec, normally 1/60
|
|
float speedFactorChange; // factor by which we changed the speed factor since the last move
|
|
float extrusionFactors[DRIVES - AXES]; // extrusion factors (normally 1.0)
|
|
int8_t toolChangeSequence; // Steps through the tool change procedure
|
|
};
|
|
|
|
//*****************************************************************************************************
|
|
|
|
// Get an Int after a G Code letter
|
|
|
|
inline int GCodeBuffer::GetIValue()
|
|
{
|
|
return (int)GetLValue();
|
|
}
|
|
|
|
inline const char* GCodeBuffer::Buffer() const
|
|
{
|
|
return gcodeBuffer;
|
|
}
|
|
|
|
inline bool GCodeBuffer::Active() const
|
|
{
|
|
return state == executing;
|
|
}
|
|
|
|
inline void GCodeBuffer::SetFinished(bool f)
|
|
{
|
|
state = (f) ? idle : executing;
|
|
}
|
|
|
|
inline void GCodeBuffer::Pause()
|
|
{
|
|
if (state == executing)
|
|
{
|
|
state = paused;
|
|
}
|
|
}
|
|
|
|
// If we paused a print, cancel printing that file and get ready to print a new one
|
|
inline void GCodeBuffer::CancelPause()
|
|
{
|
|
if (state == paused)
|
|
{
|
|
Init();
|
|
}
|
|
}
|
|
|
|
inline void GCodeBuffer::Resume()
|
|
{
|
|
if (state == paused)
|
|
{
|
|
state = executing;
|
|
}
|
|
}
|
|
|
|
inline const char* GCodeBuffer::WritingFileDirectory() const
|
|
{
|
|
return writingFileDirectory;
|
|
}
|
|
|
|
inline void GCodeBuffer::SetWritingFileDirectory(const char* wfd)
|
|
{
|
|
writingFileDirectory = wfd;
|
|
}
|
|
|
|
inline float GCodes::FractionOfFilePrinted() const
|
|
{
|
|
if (fractionOfFilePrinted < 0.0)
|
|
{
|
|
return fileBeingPrinted.FractionRead();
|
|
}
|
|
|
|
if (!fileBeingPrinted.IsLive())
|
|
{
|
|
return -1.0;
|
|
}
|
|
|
|
return fractionOfFilePrinted;
|
|
}
|
|
|
|
inline bool GCodes::PrintingAFile() const
|
|
{
|
|
return FractionOfFilePrinted() >= 0.0;
|
|
}
|
|
|
|
inline bool GCodes::HaveIncomingData() const
|
|
{
|
|
return fileBeingPrinted.IsLive() ||
|
|
webserver->GCodeAvailable() ||
|
|
(platform->GetLine()->Status() & byteAvailable) ||
|
|
(platform->GetAux()->Status() & byteAvailable);
|
|
}
|
|
|
|
inline bool GCodes::NoHome() const
|
|
{
|
|
return !(homeX || homeY || homeZ);
|
|
}
|
|
|
|
// This function takes care of the fact that the heater and head indices
|
|
// don't match because the bed is heater 0.
|
|
|
|
inline int8_t GCodes::Heater(int8_t head) const
|
|
{
|
|
return head+1;
|
|
}
|
|
|
|
// Run the configuration G Code file to set up the machine. Usually just called once
|
|
// on re-boot.
|
|
|
|
inline bool GCodes::RunConfigurationGCodes()
|
|
{
|
|
return !DoFileMacro(platform->GetConfigFile());
|
|
}
|
|
|
|
inline bool GCodes::CoolingInverted() const
|
|
{
|
|
return coolingInverted;
|
|
}
|
|
|
|
#endif
|