Printing G Code files implemented.
This commit is contained in:
parent
30767c8f62
commit
9b0d714a3a
9 changed files with 194 additions and 73 deletions
11
GCodes.h
11
GCodes.h
|
@ -33,6 +33,7 @@ class GCodeBuffer
|
|||
boolean Seen(char c);
|
||||
float GetFValue();
|
||||
int GetIValue();
|
||||
long GetLValue();
|
||||
char* Buffer();
|
||||
|
||||
private:
|
||||
|
@ -58,14 +59,18 @@ class GCodes
|
|||
|
||||
private:
|
||||
|
||||
void ActOnGcode(GCodeBuffer* gb);
|
||||
boolean ActOnGcode(GCodeBuffer* gb);
|
||||
void SetUpMove(GCodeBuffer* gb);
|
||||
boolean doDwell(GCodeBuffer *gb);
|
||||
Platform* platform;
|
||||
boolean active;
|
||||
Webserver* webserver;
|
||||
unsigned long lastTime;
|
||||
unsigned long dwellTime;
|
||||
boolean dwellWaiting;
|
||||
GCodeBuffer* webGCode;
|
||||
GCodeBuffer* fileGCode;
|
||||
boolean webGCodePending;
|
||||
boolean fileGCodePending;
|
||||
boolean moveAvailable;
|
||||
boolean heatAvailable;
|
||||
float moveBuffer[DRIVES+1]; // Last is feedrate
|
||||
|
@ -74,6 +79,8 @@ class GCodes
|
|||
char gCodeLetters[DRIVES + 1]; // Extra is for F
|
||||
float lastPos[DRIVES - AXES]; // Just needed for relative moves.
|
||||
float distanceScale;
|
||||
int fileBeingPrinted;
|
||||
int fileToPrint;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
130
GCodes.ino
130
GCodes.ino
|
@ -37,9 +37,10 @@ void GCodes::Exit()
|
|||
|
||||
void GCodes::Init()
|
||||
{
|
||||
lastTime = platform->Time();
|
||||
webGCode->Init();
|
||||
fileGCode->Init();
|
||||
webGCodePending = false;
|
||||
fileGCodePending = false;
|
||||
active = true;
|
||||
moveAvailable = false;
|
||||
heatAvailable = false;
|
||||
|
@ -49,6 +50,49 @@ void GCodes::Init()
|
|||
distanceScale = 1.0;
|
||||
for(char i = 0; i < DRIVES - AXES; i++)
|
||||
lastPos[i] = 0.0;
|
||||
fileBeingPrinted = -1;
|
||||
fileToPrint = -1;
|
||||
dwellWaiting = false;
|
||||
dwellTime = platform->Time();
|
||||
}
|
||||
|
||||
void GCodes::Spin()
|
||||
{
|
||||
if(!active)
|
||||
return;
|
||||
|
||||
if(webGCodePending)
|
||||
{
|
||||
webGCodePending = !ActOnGcode(webGCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fileGCodePending)
|
||||
{
|
||||
fileGCodePending = !ActOnGcode(fileGCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(webserver->GCodeAvailable())
|
||||
{
|
||||
if(webGCode->Put(webserver->ReadGCode()))
|
||||
webGCodePending = !ActOnGcode(webGCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fileBeingPrinted >= 0)
|
||||
{
|
||||
unsigned char b;
|
||||
if(platform->Read(fileBeingPrinted, b))
|
||||
{
|
||||
if(fileGCode->Put(b))
|
||||
fileGCodePending = !ActOnGcode(fileGCode);
|
||||
} else
|
||||
{
|
||||
platform->Close(fileBeingPrinted);
|
||||
fileBeingPrinted = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move expects all axis movements to be absolute, and all
|
||||
|
@ -101,12 +145,51 @@ void GCodes::SetUpMove(GCodeBuffer *gb)
|
|||
|
||||
void GCodes::QueueFileToPrint(char* fileName)
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "File queued for printing.\n");
|
||||
fileToPrint = platform->OpenFile(platform->GetGCodeDir(), fileName, false);
|
||||
}
|
||||
|
||||
void GCodes::ActOnGcode(GCodeBuffer *gb)
|
||||
|
||||
// Function to handle dwell delays. Return true for
|
||||
// Dwell finished, false otherwise.
|
||||
|
||||
boolean GCodes::doDwell(GCodeBuffer *gb)
|
||||
{
|
||||
unsigned long dwell;
|
||||
|
||||
if(gb->Seen('P'))
|
||||
dwell = 1000ul*(unsigned long)gb->GetLValue(); // P values are in milliseconds; we need microseconds
|
||||
else
|
||||
return true; // No time given - throw it away
|
||||
|
||||
// Wait for all the queued moves to stop
|
||||
|
||||
if(!reprap.GetMove()->AllMovesFinished())
|
||||
return false;
|
||||
|
||||
// Are we already in a dwell?
|
||||
|
||||
if(dwellWaiting)
|
||||
{
|
||||
if((long)(platform->Time() - dwellTime) >= 0)
|
||||
{
|
||||
dwellWaiting = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// New dwell - set it up
|
||||
|
||||
dwellWaiting = true;
|
||||
dwellTime = platform->Time() + dwell;
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean GCodes::ActOnGcode(GCodeBuffer *gb)
|
||||
{
|
||||
int code;
|
||||
boolean result = true;
|
||||
unsigned long dwell;
|
||||
|
||||
if(gb->Seen('G'))
|
||||
{
|
||||
|
@ -119,7 +202,7 @@ void GCodes::ActOnGcode(GCodeBuffer *gb)
|
|||
break;
|
||||
|
||||
case 4: // Dwell
|
||||
platform->Message(HOST_MESSAGE, "Dwell received\n");
|
||||
result = doDwell(gb);
|
||||
break;
|
||||
|
||||
case 10: // Set offsets
|
||||
|
@ -157,7 +240,7 @@ void GCodes::ActOnGcode(GCodeBuffer *gb)
|
|||
platform->Message(HOST_MESSAGE, gb->Buffer());
|
||||
platform->Message(HOST_MESSAGE, "\n");
|
||||
}
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
|
||||
if(gb->Seen('M'))
|
||||
|
@ -179,7 +262,8 @@ void GCodes::ActOnGcode(GCodeBuffer *gb)
|
|||
break;
|
||||
|
||||
case 24: // Print selected file
|
||||
platform->Message(HOST_MESSAGE, "Print started\n");
|
||||
fileBeingPrinted = fileToPrint;
|
||||
fileToPrint = -1;
|
||||
break;
|
||||
|
||||
case 82:
|
||||
|
@ -223,7 +307,7 @@ void GCodes::ActOnGcode(GCodeBuffer *gb)
|
|||
platform->Message(HOST_MESSAGE, gb->Buffer());
|
||||
platform->Message(HOST_MESSAGE, "\n");
|
||||
}
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
|
||||
if(gb->Seen('T'))
|
||||
|
@ -247,24 +331,10 @@ void GCodes::ActOnGcode(GCodeBuffer *gb)
|
|||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void GCodes::Spin()
|
||||
{
|
||||
if(!active)
|
||||
return;
|
||||
|
||||
if(webserver->GCodeAvailable())
|
||||
{
|
||||
if(webGCode->Put(webserver->ReadGCode()))
|
||||
ActOnGcode(webGCode);
|
||||
}
|
||||
|
||||
// TODO - Add processing of GCodes from file
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean GCodes::ReadMove(float* m)
|
||||
{
|
||||
|
@ -281,6 +351,8 @@ boolean GCodes::ReadHeat(float* h)
|
|||
|
||||
}
|
||||
|
||||
//*************************************************************************************
|
||||
|
||||
GCodeBuffer::GCodeBuffer(Platform* p)
|
||||
{
|
||||
platform = p;
|
||||
|
@ -345,20 +417,28 @@ float GCodeBuffer::GetFValue()
|
|||
return result;
|
||||
}
|
||||
|
||||
// Get an Int after a G Code letter
|
||||
|
||||
int GCodeBuffer::GetIValue()
|
||||
// Get an long after a G Code letter
|
||||
|
||||
long GCodeBuffer::GetLValue()
|
||||
{
|
||||
if(readPointer < 0)
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode int before a search.\n");
|
||||
return 0;
|
||||
}
|
||||
int result = (int)strtol(&gcodeBuffer[readPointer + 1], NULL, 0);
|
||||
long result = strtol(&gcodeBuffer[readPointer + 1], NULL, 0);
|
||||
readPointer = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get an Int after a G Code letter
|
||||
|
||||
int GCodeBuffer::GetIValue()
|
||||
{
|
||||
return (int)GetLValue();
|
||||
}
|
||||
|
||||
char* GCodeBuffer::Buffer()
|
||||
{
|
||||
return gcodeBuffer;
|
||||
|
|
1
Move.h
1
Move.h
|
@ -74,6 +74,7 @@ class Move
|
|||
void Qmove();
|
||||
void GetCurrentState(float m[]);
|
||||
void Interrupt();
|
||||
boolean AllMovesFinished();
|
||||
void InterruptTime();
|
||||
|
||||
friend class DDA;
|
||||
|
|
6
Move.ino
6
Move.ino
|
@ -223,6 +223,12 @@ void Move::Interrupt()
|
|||
dda = NULL;
|
||||
}
|
||||
|
||||
boolean Move::AllMovesFinished()
|
||||
{
|
||||
// TODO - put some code in here
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function is never normally called. It is a test to time
|
||||
// the interrupt function. To activate it, uncomment the line that calls
|
||||
// this in Platform.ino.
|
||||
|
|
13
Platform.h
13
Platform.h
|
@ -184,7 +184,8 @@ class Platform
|
|||
// Communications and data storage; opening something unsupported returns -1.
|
||||
|
||||
char* FileList(char* directory); // Returns a ,-separated list of all the files in the named directory (for example on an SD card).
|
||||
int OpenFile(char* fileName, boolean write); // Open a local file (for example on an SD card).
|
||||
//int OpenFile(char* fileName, boolean write); // Open a local file (for example on an SD card).
|
||||
int OpenFile(char* directory, char* fileName, boolean write); // Open a local file (for example on an SD card).
|
||||
void GoToEnd(int file); // Position the file at the end (so you can write on the end).
|
||||
boolean Read(int file, unsigned char& b); // Read a single byte from a file into b,
|
||||
// returned value is false for EoF, true otherwise
|
||||
|
@ -192,12 +193,11 @@ class Platform
|
|||
void Write(int file, char b); // Write the byte b to a file.
|
||||
unsigned long Length(int file); // File size in bytes
|
||||
char* GetWebDir(); // Where the htm etc files are
|
||||
char* GetGcodeDir(); // Where the gcodes are
|
||||
char* GetGCodeDir(); // Where the gcodes are
|
||||
char* GetSysDir(); // Where the system files are
|
||||
char* GetTempDir(); // Where temporary files are
|
||||
void Close(int file); // Close a file or device, writing any unwritten buffer contents first.
|
||||
boolean DeleteFile(char* fileName); // Delete a file
|
||||
char* PrependRoot(char* result, char* root, char* fileName);
|
||||
boolean DeleteFile(char* directory, char* fileName); // Delete a file
|
||||
|
||||
unsigned char ClientRead(); // Read a byte from the client
|
||||
void SendToClient(char* message); // Send string to the host
|
||||
|
@ -242,6 +242,8 @@ class Platform
|
|||
|
||||
void InitialiseInterrupts();
|
||||
|
||||
char* CombineName(char* result, char* directory, char* fileName);
|
||||
|
||||
RepRap* reprap;
|
||||
|
||||
// DRIVES
|
||||
|
@ -286,6 +288,7 @@ class Platform
|
|||
byte* buf[MAX_FILES];
|
||||
int bPointer[MAX_FILES];
|
||||
char fileList[FILE_LIST_LENGTH];
|
||||
char scratchString[STRING_LENGTH];
|
||||
|
||||
// Network connection
|
||||
|
||||
|
@ -316,7 +319,7 @@ inline char* Platform::GetWebDir()
|
|||
|
||||
// Where the gcodes are
|
||||
|
||||
inline char* Platform::GetGcodeDir()
|
||||
inline char* Platform::GetGCodeDir()
|
||||
{
|
||||
return gcodeDir;
|
||||
}
|
||||
|
|
78
Platform.ino
78
Platform.ino
|
@ -58,27 +58,6 @@ inline void Platform::Interrupt()
|
|||
reprap->Interrupt(); // Put nothing else in this function
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency)
|
||||
{
|
||||
pmc_set_writeprotect(false);
|
||||
pmc_enable_periph_clk((uint32_t)irq);
|
||||
TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
|
||||
// VARIANT_MCK = 84x10^6 for the Due
|
||||
uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
|
||||
TC_SetRA(tc, channel, rc/2); //50% high, 50% low
|
||||
TC_SetRC(tc, channel, rc);
|
||||
TC_Start(tc, channel);
|
||||
tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
|
||||
tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
|
||||
NVIC_EnableIRQ(irq);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
//*******************************************************************************************************************
|
||||
|
||||
void Platform::Init()
|
||||
|
@ -207,13 +186,13 @@ void Platform::Init()
|
|||
active = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
char* Platform::PrependRoot(char* result, char* root, char* fileName)
|
||||
{
|
||||
strcpy(result, root);
|
||||
return strcat(result, fileName);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// Load settings from local storage; return true if successful, false otherwise
|
||||
|
||||
|
@ -277,6 +256,41 @@ void Platform::SetHeater(char heater, const float& power)
|
|||
|
||||
*/
|
||||
|
||||
char* Platform::CombineName(char* result, char* directory, char* fileName)
|
||||
{
|
||||
int out = 0;
|
||||
int in = 0;
|
||||
|
||||
result[out] = '/';
|
||||
out++;
|
||||
|
||||
if(directory != NULL)
|
||||
{
|
||||
if(directory[in] == '/')
|
||||
in++;
|
||||
while(directory[in] != 0 && directory[in] != '\n' && directory[in] != '/')
|
||||
{
|
||||
result[out] = directory[in];
|
||||
out++;
|
||||
in++;
|
||||
}
|
||||
}
|
||||
|
||||
result[out] = '/';
|
||||
out++;
|
||||
|
||||
in = 0;
|
||||
while(fileName[in] != 0 && fileName[in] != '\n' && fileName[in] != '/')
|
||||
{
|
||||
result[out] = fileName[in];
|
||||
out++;
|
||||
in++;
|
||||
}
|
||||
result[out] = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// List the flat files in a directory. No sub-directories or recursion.
|
||||
|
||||
char* Platform::FileList(char* directory)
|
||||
|
@ -317,15 +331,17 @@ char* Platform::FileList(char* directory)
|
|||
}
|
||||
|
||||
// Delete a file
|
||||
boolean Platform::DeleteFile(char* fileName)
|
||||
boolean Platform::DeleteFile(char* directory, char* fileName)
|
||||
{
|
||||
return SD.remove(fileName);
|
||||
CombineName(scratchString, directory, fileName);
|
||||
return SD.remove(scratchString);
|
||||
}
|
||||
|
||||
// Open a local file (for example on an SD card).
|
||||
|
||||
int Platform::OpenFile(char* fileName, boolean write)
|
||||
int Platform::OpenFile(char* directory, char* fileName, boolean write)
|
||||
{
|
||||
CombineName(scratchString, directory, fileName);
|
||||
int result = -1;
|
||||
for(int i = 0; i < MAX_FILES; i++)
|
||||
if(!inUse[i])
|
||||
|
@ -339,7 +355,7 @@ int Platform::OpenFile(char* fileName, boolean write)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if(!SD.exists(fileName))
|
||||
if(!SD.exists(scratchString))
|
||||
{
|
||||
if(!write)
|
||||
{
|
||||
|
@ -348,16 +364,16 @@ int Platform::OpenFile(char* fileName, boolean write)
|
|||
Message(HOST_MESSAGE, " not found for reading.\n");
|
||||
return -1;
|
||||
}
|
||||
files[result] = SD.open(fileName, FILE_WRITE);
|
||||
files[result] = SD.open(scratchString, FILE_WRITE);
|
||||
bPointer[result] = 0;
|
||||
} else
|
||||
{
|
||||
if(write)
|
||||
{
|
||||
files[result] = SD.open(fileName, FILE_WRITE);
|
||||
files[result] = SD.open(scratchString, FILE_WRITE);
|
||||
bPointer[result] = 0;
|
||||
} else
|
||||
files[result] = SD.open(fileName, FILE_READ);
|
||||
files[result] = SD.open(scratchString, FILE_READ);
|
||||
}
|
||||
|
||||
inUse[result] = true;
|
||||
|
@ -469,7 +485,7 @@ void Platform::Message(char type, char* message)
|
|||
default:
|
||||
|
||||
|
||||
int m = OpenFile(PrependRoot(scratchString, GetWebDir(), MESSAGE_FILE), true);
|
||||
int m = OpenFile(GetWebDir(), MESSAGE_FILE, true);
|
||||
GoToEnd(m);
|
||||
WriteString(m, message);
|
||||
Serial.print(message);
|
||||
|
|
9
SD-image/gcodes/square.g
Normal file
9
SD-image/gcodes/square.g
Normal file
|
@ -0,0 +1,9 @@
|
|||
G1 X55 Y5 F2000
|
||||
G1 X55 Y55
|
||||
G1 X5 Y55
|
||||
G1 X5 Y5
|
||||
G1 X55 Y5
|
||||
G1 X55 Y55
|
||||
G1 X5 Y55
|
||||
G1 X5 Y5
|
||||
|
0
SD-image/gcodes/square.g~
Normal file
0
SD-image/gcodes/square.g~
Normal file
|
@ -132,10 +132,10 @@ boolean Webserver::LoadGcodeBuffer(char* gc, boolean convertWeb)
|
|||
if(StringStartsWith(gcodeBuffer, "M23 ")) fileAct |= 2;
|
||||
|
||||
if(fileAct) // Delete or print a file?
|
||||
{
|
||||
{
|
||||
if(fileAct == 1) // Delete?
|
||||
{
|
||||
if(!platform->DeleteFile(platform->PrependRoot(scratchString, platform->GetGcodeDir(), &gcodeBuffer[4])))
|
||||
if(!platform->DeleteFile(platform->GetGCodeDir(), &gcodeBuffer[4]))
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "Unsuccsessful attempt to delete: ");
|
||||
platform->Message(HOST_MESSAGE, &gcodeBuffer[4]);
|
||||
|
@ -143,12 +143,11 @@ boolean Webserver::LoadGcodeBuffer(char* gc, boolean convertWeb)
|
|||
}
|
||||
} else // Print it
|
||||
{
|
||||
reprap.GetGCodes()->QueueFileToPrint(platform->PrependRoot(scratchString, platform->GetGcodeDir(), &gcodeBuffer[4]));
|
||||
reprap.GetGCodes()->QueueFileToPrint(&gcodeBuffer[4]);
|
||||
}
|
||||
|
||||
// Check for further G Codes in the string
|
||||
|
||||
gcodePointer = 0;
|
||||
while(gcodeBuffer[gcodePointer])
|
||||
{
|
||||
if(gcodeBuffer[gcodePointer] == '\n')
|
||||
|
@ -199,11 +198,11 @@ void Webserver::SendFile(char* nameOfFileToSend)
|
|||
|
||||
if(jsonPointer < 0)
|
||||
{
|
||||
fileBeingSent = platform->OpenFile(platform->PrependRoot(scratchString, platform->GetWebDir(), nameOfFileToSend), false);
|
||||
fileBeingSent = platform->OpenFile(platform->GetWebDir(), nameOfFileToSend, false);
|
||||
if(fileBeingSent < 0)
|
||||
{
|
||||
nameOfFileToSend = FOUR04_FILE;
|
||||
fileBeingSent = platform->OpenFile(platform->PrependRoot(scratchString, platform->GetWebDir(), nameOfFileToSend), false);
|
||||
fileBeingSent = platform->OpenFile(platform->GetWebDir(), nameOfFileToSend, false);
|
||||
}
|
||||
writing = true;
|
||||
}
|
||||
|
@ -321,7 +320,7 @@ void Webserver::GetJsonResponse(char* request)
|
|||
|
||||
if(StringStartsWith(request, "files"))
|
||||
{
|
||||
char* fileList = platform->FileList(platform->GetGcodeDir());
|
||||
char* fileList = platform->FileList(platform->GetGCodeDir());
|
||||
strcpy(jsonResponse, "{\"files\":[");
|
||||
strcat(jsonResponse, fileList);
|
||||
strcat(jsonResponse, "]}");
|
||||
|
@ -496,11 +495,11 @@ void Webserver::BlankLineFromClient()
|
|||
|
||||
if(receivingPost)
|
||||
{
|
||||
postFile = platform->OpenFile(platform->PrependRoot(scratchString, platform->GetGcodeDir(), postFileName), true);
|
||||
postFile = platform->OpenFile(platform->GetGCodeDir(), postFileName, true);
|
||||
if(postFile < 0 || !postBoundary[0])
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "Can't open file for write or no post boundary: ");
|
||||
platform->Message(HOST_MESSAGE, platform->PrependRoot(scratchString, platform->GetGcodeDir(), postFileName));
|
||||
platform->Message(HOST_MESSAGE, postFileName);
|
||||
platform->Message(HOST_MESSAGE, "\n");
|
||||
InitialisePost();
|
||||
}
|
||||
|
@ -626,7 +625,7 @@ void Webserver::Init()
|
|||
|
||||
// Reinitialise the message file
|
||||
|
||||
platform->DeleteFile(platform->PrependRoot(scratchString, platform->GetWebDir(), MESSAGE_FILE));
|
||||
platform->DeleteFile(platform->GetWebDir(), MESSAGE_FILE);
|
||||
}
|
||||
|
||||
void Webserver::Exit()
|
||||
|
|
Reference in a new issue