Skeleton of the GCode interpreter written.
This commit is contained in:
parent
00ca902341
commit
b23e6943a8
9 changed files with 331 additions and 121 deletions
|
@ -23,6 +23,13 @@ Licence: GPL
|
|||
#ifndef CONFIGURATION_H
|
||||
#define CONFIGURATION_H
|
||||
|
||||
class RepRap;
|
||||
class Platform;
|
||||
class Move;
|
||||
class Heat;
|
||||
class GCodes;
|
||||
class Webserver;
|
||||
|
||||
#define ABS_ZERO -273.15
|
||||
|
||||
#define FLASH_LED 'F' // Type byte of a message that is to flash an LED; the next two bytes define
|
||||
|
@ -52,5 +59,6 @@ Licence: GPL
|
|||
#define PHP_ECHO 2
|
||||
#define PHP_PRINT 3
|
||||
#define NO_PHP 99
|
||||
#define START_FEED_RATE 200
|
||||
|
||||
#endif
|
||||
|
|
10
GCodes.h
10
GCodes.h
|
@ -36,6 +36,10 @@ class GCodes
|
|||
private:
|
||||
|
||||
void ActOnGcode();
|
||||
boolean Seen(char c);
|
||||
float GetFValue();
|
||||
int GetIValue();
|
||||
void SetUpMove();
|
||||
|
||||
Platform* platform;
|
||||
boolean active;
|
||||
|
@ -43,9 +47,13 @@ class GCodes
|
|||
unsigned long lastTime;
|
||||
char gcodeBuffer[GCODE_LENGTH];
|
||||
int gcodePointer;
|
||||
int readPointer;
|
||||
boolean moveAvailable;
|
||||
boolean heatAvailable;
|
||||
float moveBuffer[DRIVES];
|
||||
float moveBuffer[DRIVES+1]; // Last is feedrate
|
||||
boolean drivesRelative; // All except X, Y and Z
|
||||
boolean axesRelative; // X, Y and Z
|
||||
char gCodeLetters[DRIVES + 1]; // Extra is for F
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
149
GCodes.ino
149
GCodes.ino
|
@ -24,7 +24,6 @@ Licence: GPL
|
|||
GCodes::GCodes(Platform* p, Webserver* w)
|
||||
{
|
||||
active = false;
|
||||
//Serial.println("GCodes constructor");
|
||||
platform = p;
|
||||
webserver = w;
|
||||
}
|
||||
|
@ -41,19 +40,111 @@ void GCodes::Init()
|
|||
active = true;
|
||||
moveAvailable = false;
|
||||
heatAvailable = false;
|
||||
readPointer = -1;
|
||||
drivesRelative = false;
|
||||
axesRelative = false;
|
||||
gCodeLetters = GCODE_LETTERS;
|
||||
}
|
||||
|
||||
|
||||
void GCodes::SetUpMove()
|
||||
{
|
||||
reprap.GetMove()->GetCurrentState(moveBuffer);
|
||||
for(char i = 0; i < DRIVES; i++)
|
||||
{
|
||||
if(i < AXES)
|
||||
{
|
||||
if(Seen(gCodeLetters[i]))
|
||||
{
|
||||
if(axesRelative)
|
||||
moveBuffer[i] += GetFValue();
|
||||
else
|
||||
moveBuffer[i] = GetFValue();
|
||||
}
|
||||
} else
|
||||
{
|
||||
if(Seen(gCodeLetters[i]))
|
||||
{
|
||||
if(drivesRelative)
|
||||
moveBuffer[i] = GetFValue();
|
||||
else
|
||||
moveBuffer[i] = GetFValue(); //***TODO need to store old values and subtract them here
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Seen(gCodeLetters[DRIVES]))
|
||||
moveBuffer[DRIVES] = GetFValue();
|
||||
moveAvailable = true;
|
||||
}
|
||||
|
||||
void GCodes::ActOnGcode()
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "GCode: ");
|
||||
platform->Message(HOST_MESSAGE, gcodeBuffer);
|
||||
platform->Message(HOST_MESSAGE, "<br>\n");
|
||||
int code;
|
||||
|
||||
if(Seen('G'))
|
||||
{
|
||||
code = GetIValue();
|
||||
switch(code)
|
||||
{
|
||||
case 1:
|
||||
SetUpMove();
|
||||
break;
|
||||
|
||||
case 90:
|
||||
drivesRelative = false;
|
||||
axesRelative = false;
|
||||
break;
|
||||
|
||||
case 91:
|
||||
drivesRelative = true;
|
||||
axesRelative = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
platform->Message(HOST_MESSAGE, "GCodes - invalid G Code: ");
|
||||
platform->Message(HOST_MESSAGE, gcodeBuffer);
|
||||
platform->Message(HOST_MESSAGE, "<br>\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(Seen('M'))
|
||||
{
|
||||
code = GetIValue();
|
||||
switch(code)
|
||||
{
|
||||
case 82:
|
||||
drivesRelative = false;
|
||||
break;
|
||||
|
||||
case 83:
|
||||
drivesRelative = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
platform->Message(HOST_MESSAGE, "GCodes - invalid M Code: ");
|
||||
platform->Message(HOST_MESSAGE, gcodeBuffer);
|
||||
platform->Message(HOST_MESSAGE, "<br>\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(Seen('T'))
|
||||
{
|
||||
code = GetIValue();
|
||||
switch(code)
|
||||
{
|
||||
|
||||
|
||||
default:
|
||||
platform->Message(HOST_MESSAGE, "GCodes - invalid T Code: ");
|
||||
platform->Message(HOST_MESSAGE, gcodeBuffer);
|
||||
platform->Message(HOST_MESSAGE, "<br>\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GCodes::Spin()
|
||||
{
|
||||
if(!active)
|
||||
|
@ -73,7 +164,7 @@ void GCodes::Spin()
|
|||
|
||||
if(gcodePointer >= GCODE_LENGTH)
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "GCodes: G Code buffer length overflow.");
|
||||
platform->Message(HOST_MESSAGE, "GCodes: G Code buffer length overflow.<br>\n");
|
||||
gcodePointer = 0;
|
||||
gcodeBuffer[0] = 0;
|
||||
}
|
||||
|
@ -85,7 +176,7 @@ boolean GCodes::ReadMove(float* m)
|
|||
{
|
||||
if(!moveAvailable)
|
||||
return false;
|
||||
for(char i = 0; i < DRIVES; i++)
|
||||
for(char i = 0; i <= DRIVES; i++)
|
||||
m[i] = moveBuffer[i];
|
||||
moveAvailable = false;
|
||||
}
|
||||
|
@ -93,7 +184,47 @@ boolean GCodes::ReadMove(float* m)
|
|||
|
||||
boolean GCodes::ReadHeat(float* h)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean GCodes::Seen(char c)
|
||||
{
|
||||
readPointer = 0;
|
||||
while(gcodeBuffer[readPointer])
|
||||
{
|
||||
if(gcodeBuffer[readPointer] == c)
|
||||
return true;
|
||||
readPointer++;
|
||||
}
|
||||
readPointer = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float GCodes::GetFValue()
|
||||
{
|
||||
if(readPointer < 0)
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode float before a search.<br>\n");
|
||||
return 0.0;
|
||||
}
|
||||
float result = (float)strtod(&gcodeBuffer[readPointer + 1], NULL);
|
||||
readPointer = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int GCodes::GetIValue()
|
||||
{
|
||||
if(readPointer < 0)
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode int before a search.<br>\n");
|
||||
return 0;
|
||||
}
|
||||
int result = (int)strtol(&gcodeBuffer[readPointer + 1], NULL, 0);
|
||||
readPointer = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
5
Move.h
5
Move.h
|
@ -32,6 +32,7 @@ class Move
|
|||
void Spin();
|
||||
void Exit();
|
||||
void Qmove();
|
||||
void GetCurrentState(float m[]);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -39,8 +40,10 @@ class Move
|
|||
GCodes* gCodes;
|
||||
unsigned long lastTime;
|
||||
boolean active;
|
||||
float currentFeedrate;
|
||||
float currentPosition[AXES]; // Note - drives above AXES are always relative moves
|
||||
float nextMove[DRIVES];
|
||||
float nextMove[DRIVES + 1]; // Extra is for feedrate
|
||||
char scratchString[STRING_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
|
|
30
Move.ino
30
Move.ino
|
@ -22,7 +22,6 @@ Licence: GPL
|
|||
|
||||
Move::Move(Platform* p, GCodes* g)
|
||||
{
|
||||
//Serial.println("Move constructor");
|
||||
platform = p;
|
||||
gCodes = g;
|
||||
active = false;
|
||||
|
@ -33,7 +32,10 @@ void Move::Init()
|
|||
lastTime = platform->Time();
|
||||
for(char i = 0; i < DRIVES; i++)
|
||||
platform->SetDirection(i, FORWARDS);
|
||||
active = true;
|
||||
for(char i = 0; i <= AXES; i++)
|
||||
currentPosition[i] = 0.0;
|
||||
active = true;
|
||||
currentFeedrate = START_FEED_RATE;
|
||||
}
|
||||
|
||||
void Move::Exit()
|
||||
|
@ -53,5 +55,29 @@ void Move::Qmove()
|
|||
{
|
||||
if(!gCodes->ReadMove(nextMove))
|
||||
return;
|
||||
platform->Message(HOST_MESSAGE, "Move - got a move:");
|
||||
for(char i = 0; i <= DRIVES; i++)
|
||||
{
|
||||
ftoa(scratchString, nextMove[i], 3);
|
||||
platform->Message(HOST_MESSAGE, scratchString);
|
||||
platform->Message(HOST_MESSAGE, ", ");
|
||||
}
|
||||
platform->Message(HOST_MESSAGE, "<br>\n");
|
||||
|
||||
// Make it so
|
||||
|
||||
for(char i = 0; i <= AXES; i++)
|
||||
currentPosition[i] = nextMove[i];
|
||||
}
|
||||
|
||||
void Move::GetCurrentState(float m[])
|
||||
{
|
||||
for(char i = 0; i < DRIVES; i++)
|
||||
{
|
||||
if(i < AXES)
|
||||
m[i] = currentPosition[i];
|
||||
else
|
||||
m[i] = 0.0;
|
||||
}
|
||||
m[DRIVES] = currentFeedrate;
|
||||
}
|
||||
|
|
98
Platform.h
98
Platform.h
|
@ -74,6 +74,8 @@ Licence: GPL
|
|||
#define JERKS {15.0, 15.0, 0.4, 15.0} // (mm/sec)
|
||||
#define DRIVE_RELATIVE_MODES {false, false, false, true} // false for default absolute movement, true for relative to last position
|
||||
|
||||
#define GCODE_LETTERS {'X', 'Y', 'Z', 'E', 'F' }
|
||||
|
||||
// AXES
|
||||
|
||||
|
||||
|
@ -305,101 +307,5 @@ inline unsigned long Platform::Time()
|
|||
return micros();
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
|
||||
// Network connection
|
||||
|
||||
inline int Platform::ClientStatus()
|
||||
{
|
||||
return clientStatus;
|
||||
}
|
||||
|
||||
inline void Platform::SendToClient(unsigned char b)
|
||||
{
|
||||
if(client)
|
||||
{
|
||||
client.write(b);
|
||||
//Serial.write(b);
|
||||
} else
|
||||
Message(HOST_MESSAGE, "Attempt to send byte to disconnected client.");
|
||||
}
|
||||
|
||||
inline unsigned char Platform::ClientRead()
|
||||
{
|
||||
if(client)
|
||||
return client.read();
|
||||
|
||||
Message(HOST_MESSAGE, "Attempt to read from disconnected client.");
|
||||
return '\n'; // good idea??
|
||||
}
|
||||
|
||||
inline void Platform::ClientMonitor()
|
||||
{
|
||||
clientStatus = 0;
|
||||
|
||||
if(!client)
|
||||
{
|
||||
client = server->available();
|
||||
if(!client)
|
||||
return;
|
||||
//else
|
||||
//Serial.println("new client");
|
||||
}
|
||||
|
||||
clientStatus |= CLIENT;
|
||||
|
||||
if(!client.connected())
|
||||
return;
|
||||
|
||||
clientStatus |= CONNECTED;
|
||||
|
||||
if (!client.available())
|
||||
return;
|
||||
|
||||
clientStatus |= AVAILABLE;
|
||||
}
|
||||
|
||||
inline void Platform::DisconnectClient()
|
||||
{
|
||||
if (client)
|
||||
{
|
||||
client.stop();
|
||||
//Serial.println("client disconnected");
|
||||
} else
|
||||
Message(HOST_MESSAGE, "Attempt to disconnect non-existent client.");
|
||||
}
|
||||
|
||||
//*****************************************************************************************************************
|
||||
|
||||
// Interrupts
|
||||
|
||||
inline void Platform::SetInterrupt(long t)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline void Platform::Interrupt()
|
||||
{
|
||||
reprap->Interrupt(); // Put nothing else in this function
|
||||
}
|
||||
|
||||
//*****************************************************************************************************************
|
||||
|
||||
// Drive the RepRap machine
|
||||
|
||||
inline void Platform::SetDirection(byte drive, bool direction)
|
||||
{
|
||||
digitalWrite(directionPins[drive], direction);
|
||||
}
|
||||
|
||||
inline void Platform::Step(byte drive)
|
||||
{
|
||||
digitalWrite(stepPins[drive], !digitalRead(stepPins[drive]));
|
||||
}
|
||||
|
||||
inline int Platform::GetRawTemperature(byte heater)
|
||||
{
|
||||
return analogRead(tempSensePins[heater]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
101
Platform.ino
101
Platform.ino
|
@ -42,6 +42,107 @@ Platform::Platform(RepRap* r)
|
|||
active = false;
|
||||
}
|
||||
|
||||
//*****************************************************************************************************************
|
||||
|
||||
// Interrupts
|
||||
|
||||
inline void Platform::SetInterrupt(long t)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline void Platform::Interrupt()
|
||||
{
|
||||
reprap->Interrupt(); // Put nothing else in this function
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
|
||||
// Network connection
|
||||
|
||||
inline int Platform::ClientStatus()
|
||||
{
|
||||
return clientStatus;
|
||||
}
|
||||
|
||||
inline void Platform::SendToClient(unsigned char b)
|
||||
{
|
||||
if(client)
|
||||
{
|
||||
client.write(b);
|
||||
//Serial.write(b);
|
||||
} else
|
||||
Message(HOST_MESSAGE, "Attempt to send byte to disconnected client.");
|
||||
}
|
||||
|
||||
inline unsigned char Platform::ClientRead()
|
||||
{
|
||||
if(client)
|
||||
return client.read();
|
||||
|
||||
Message(HOST_MESSAGE, "Attempt to read from disconnected client.");
|
||||
return '\n'; // good idea??
|
||||
}
|
||||
|
||||
inline void Platform::ClientMonitor()
|
||||
{
|
||||
clientStatus = 0;
|
||||
|
||||
if(!client)
|
||||
{
|
||||
client = server->available();
|
||||
if(!client)
|
||||
return;
|
||||
//else
|
||||
//Serial.println("new client");
|
||||
}
|
||||
|
||||
clientStatus |= CLIENT;
|
||||
|
||||
if(!client.connected())
|
||||
return;
|
||||
|
||||
clientStatus |= CONNECTED;
|
||||
|
||||
if (!client.available())
|
||||
return;
|
||||
|
||||
clientStatus |= AVAILABLE;
|
||||
}
|
||||
|
||||
inline void Platform::DisconnectClient()
|
||||
{
|
||||
if (client)
|
||||
{
|
||||
client.stop();
|
||||
//Serial.println("client disconnected");
|
||||
} else
|
||||
Message(HOST_MESSAGE, "Attempt to disconnect non-existent client.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//*****************************************************************************************************************
|
||||
|
||||
// Drive the RepRap machine
|
||||
|
||||
inline void Platform::SetDirection(byte drive, bool direction)
|
||||
{
|
||||
digitalWrite(directionPins[drive], direction);
|
||||
}
|
||||
|
||||
inline void Platform::Step(byte drive)
|
||||
{
|
||||
digitalWrite(stepPins[drive], !digitalRead(stepPins[drive]));
|
||||
}
|
||||
|
||||
inline int Platform::GetRawTemperature(byte heater)
|
||||
{
|
||||
return analogRead(tempSensePins[heater]);
|
||||
}
|
||||
|
||||
//*******************************************************************************************************************
|
||||
|
||||
void Platform::Init()
|
||||
{
|
||||
byte i;
|
||||
|
|
|
@ -28,11 +28,8 @@ Licence: GPL
|
|||
#define DATE "2012-11-18"
|
||||
#define LAST_AUTHOR "reprappro.com"
|
||||
|
||||
class Platform;
|
||||
class Move;
|
||||
class Heat;
|
||||
class GCodes;
|
||||
class Webserver;
|
||||
#include "Configuration.h"
|
||||
#include "Platform.h"
|
||||
|
||||
class RepRap
|
||||
{
|
||||
|
@ -42,9 +39,12 @@ class RepRap
|
|||
void Init();
|
||||
void Spin();
|
||||
void Exit();
|
||||
|
||||
void Interrupt();
|
||||
|
||||
Platform* GetPlatform();
|
||||
Move* GetMove();
|
||||
Heat* GetHeat();
|
||||
GCodes* GetGCodes();
|
||||
Webserver* GetWebserver();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -56,18 +56,15 @@ class RepRap
|
|||
Webserver* webserver;
|
||||
};
|
||||
|
||||
#include "Configuration.h"
|
||||
#include "Platform.h"
|
||||
#include "Webserver.h"
|
||||
#include "GCodes.h"
|
||||
#include "Move.h"
|
||||
#include "Heat.h"
|
||||
|
||||
|
||||
char* ftoa(char *a, const float& f, int prec);
|
||||
|
||||
extern RepRap reprap;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -64,6 +64,12 @@ RepRap::RepRap()
|
|||
heat = new Heat(platform, gCodes);
|
||||
}
|
||||
|
||||
inline Platform* RepRap::GetPlatform() { return platform; }
|
||||
inline Move* RepRap::GetMove() { return move; }
|
||||
inline Heat* RepRap::GetHeat() { return heat; }
|
||||
inline GCodes* RepRap::GetGCodes() { return gCodes; }
|
||||
inline Webserver* RepRap::GetWebserver() { return webserver; }
|
||||
|
||||
void RepRap::Init()
|
||||
{
|
||||
platform->Init();
|
||||
|
@ -98,12 +104,36 @@ void RepRap::Spin()
|
|||
}
|
||||
|
||||
|
||||
|
||||
void RepRap::Interrupt()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//*************************************************************************************************
|
||||
|
||||
// Utilities and storage not part of any class
|
||||
|
||||
static long precision[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
|
||||
|
||||
char* ftoa(char *a, const float& f, int prec)
|
||||
{
|
||||
char *ret = a;
|
||||
long whole = (long)f;
|
||||
sprintf(a,"%d",whole);
|
||||
while (*a != '\0') a++;
|
||||
*a++ = '.';
|
||||
long decimal = abs((long)((f - (float)whole) * precision[prec]));
|
||||
sprintf(a,"%d",decimal);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Reference in a new issue