Merged RepRapRro's 0.65e version in

Merged changes (mostly to handle multiple tools i.e. extruders) from
RRP's 0.65e version.
This commit is contained in:
David Crocker 2014-06-04 17:39:36 +01:00
parent 08f7d2e9b1
commit 73724a4b9a
16 changed files with 1190 additions and 469 deletions

View file

@ -24,9 +24,9 @@ Licence: GPL
#define CONFIGURATION_H
#define NAME "RepRapFirmware"
#define VERSION "0.59e-dc42"
#define DATE "2014-06-01"
#define LAST_AUTHOR "dc42"
#define VERSION "0.65e-dc42"
#define DATE "2014-06-04"
#define LAST_AUTHOR "reprappro & dc42"
// Other firmware that we might switch to be compatible with.
@ -48,19 +48,19 @@ enum Compatibility
#define HEAT_SAMPLE_TIME (0.5) // Seconds
#define TEMPERATURE_CLOSE_ENOUGH (2.5) // Celsius
#define TEMPERATURE_CLOSE_ENOUGH (2.0) // Celsius
#define TEMPERATURE_LOW_SO_DONT_CARE (40.0) // Celsius
// If temperatures fall outside this range, something nasty has happened.
#define BAD_LOW_TEMPERATURE -30.0
#define BAD_HIGH_TEMPERATURE 300.0
#define MAX_BAD_TEMPERATURE_COUNT 6
#define BAD_LOW_TEMPERATURE -10.0
#define BAD_HIGH_TEMPERATURE 300.0
#define STANDBY_INTERRUPT_RATE 2.0e-4 // Seconds
#define NUMBER_OF_PROBE_POINTS 4
#define Z_DIVE 5.0 // Height from which to probe the bed (mm)
#define Z_DIVE 8.0 // Height from which to probe the bed (mm)
#define SILLY_Z_VALUE -9999.0
@ -77,6 +77,12 @@ enum Compatibility
#define HOME_Z_G "homez.g"
#define HOME_ALL_G "homeall.g"
#define LIST_SEPARATOR ':' // Lists in G Codes
#define FILE_LIST_SEPARATOR ',' // Put this between file names when listing them
#define FILE_LIST_BRACKET '"' // Put these round file names when listing them
#define GCODE_LETTERS { 'X', 'Y', 'Z', 'E', 'F' } // The drives and feedrate in a GCode
#define LONG_TIME 300.0 // Seconds
#define EOF_STRING "<!-- **EoF** -->"

View file

@ -78,10 +78,6 @@ void GCodes::Reset()
fileGCode->Init();
serialGCode->Init();
cannedCycleGCode->Init();
webGCode->SetFinished(true);
fileGCode->SetFinished(true);
serialGCode->SetFinished(true);
cannedCycleGCode->SetFinished(true);
moveAvailable = false;
fileBeingPrinted.Close();
fileToPrint.Close();
@ -99,7 +95,7 @@ void GCodes::Reset()
extrusionFactor = 1.0;
}
void GCodes::doFilePrint(GCodeBuffer* gb)
void GCodes::DoFilePrint(GCodeBuffer* gb)
{
char b;
@ -240,7 +236,7 @@ void GCodes::Spin()
}
}
doFilePrint(fileGCode);
DoFilePrint(fileGCode);
platform->ClassReport("GCodes", longWait);
}
@ -336,6 +332,8 @@ bool GCodes::Pop()
// Move expects all axis movements to be absolute, and all
// extruder drive moves to be relative. This function serves that.
// If applyLimits is true and we have homed the relevant axes, then we don't allow movement beyond the bed.
// Note that if no tool is active (i.e. a Tn command hasn't previously been sent) then no E values will
// be acted upon as there is nothing to apply them to.
void GCodes::LoadMoveBufferFromGCode(GCodeBuffer *gb, bool doingG92, bool applyLimits)
{
@ -371,32 +369,94 @@ void GCodes::LoadMoveBufferFromGCode(GCodeBuffer *gb, bool doingG92, bool applyL
}
else
{
if (gb->Seen(gCodeLetters[i]))
{
// Doing an extruder. We need to store the relative distance for this move in moveBuffer and the resulting new position in lastPos.
float moveArg = gb->GetFValue() * distanceScale * extrusionFactor;
if (doingG92)
/*Fixed to work with multiple concurrent extruder drives:
* Default or M160 S1 (set use only one extruder drive)
* "G1 En.n" adds the float n.n to the move buffer for the selected head
* There is no change in behaviour for one extruder drive setups, or multiple extruder
* setups where only one drive is used at any one time.
*
* M160 Sn (set to use "n" extruder drives) eg
* "M160 S3"
* "G1 En.n:m.m:o.o" adds the floats to the move buffer in the following way:
* moveBuffer[AXES+selectedHead) = n.n
* moveBuffer[AXES+selectedHead+1) = m.m
* moveBuffer[AXES+selectedHead+2) = o.o
* so if selectedHead=1 move buffer ends up looking like this for a 5 extruder drive setup:
* {x.x, y.y, z.z, n.n, m.m, o.o, 0.0,0.0, f.f}
* where x,y,z are the axes and f is the feedrate.
* If selected head > 0 then there is the possibility that more drives can be set than
* exist, in that case the last values are discarded e.g:
* "T3"
* "M160 S3"
* "G1 En.n:m.m:o.o"
* would leave the move buffer on a 4 extruder drive setup looking like this:
* {x.x, y.y, z.z, 0.0, 0.0, 0.0, n.n,m.m, f.f}
*/
if(gb->Seen('E')&& ((i-AXES) == selectedHead-1))
{
//the number of mixing drives set (by M160)
int numDrives = platform->GetMixingDrives();
const char* extruderString = gb->GetString();
float eArg[numDrives];
uint8_t sp = 0; //string pointer
uint8_t fp = 0; //float pointer for the start of each floating point number in turn
uint8_t hp = 0; //index of the head currently referred to for eArg
while(extruderString[sp])
{
//first check to confirm we have not got to the feedrate setting part of the string
if(extruderString[sp] == 'F')
{
break;
}
if(extruderString[sp] == ':')
{
eArg[hp] = (atoff(&extruderString[fp]))*distanceScale;
hp++;
if(hp >= numDrives)
{
platform->Message(HOST_MESSAGE, "More mixing extruder drives required in G1 string than set with M160: ");
platform->Message(HOST_MESSAGE, gb->Buffer());
platform->Message(HOST_MESSAGE, "\n");
return;
}
sp++;
fp = sp;
}
else
{
sp++;
}
}
//capture the last drive step amount in the string (or the only one in the case of only one extruder)
eArg[hp] = (atoff(&extruderString[fp]))*distanceScale;
//set the move buffer for each extruder drive
for(int j=0;j<numDrives;j++)
{
float moveArg = eArg[j];
if(doingG92)
{
moveBuffer[i] = 0.0; // no move required
lastPos[i - AXES] = moveArg; // set new absolute position
moveBuffer[i+j] = 0.0; // no move required
lastPos[i+j - AXES] = moveArg; // set absolute position
}
else if (drivesRelative)
{
moveBuffer[i] = moveArg;
lastPos[i - AXES] += moveArg;
moveBuffer[i+j] = moveArg;
lastPos[i+j - AXES] += moveArg;
}
else
{
moveBuffer[i] = moveArg - lastPos[i - AXES];
lastPos[i - AXES] = moveArg;
moveBuffer[i+j] = moveArg - lastPos[i+j - AXES];
lastPos[i+j - AXES] = moveArg;
}
}
}
}
}
}
// Deal with feed rate
if (gb->Seen(gCodeLetters[DRIVES]))
if(gb->Seen(FEEDRATE_LETTER))
{
gFeedRate = gb->GetFValue() * distanceScale * speedFactor;
}
@ -415,10 +475,11 @@ int GCodes::SetUpMove(GCodeBuffer *gb)
if (moveAvailable)
return 0;
// Load the last position; if Move can't accept more, return 0
// Load the last position into moveBuffer; If Move can't accept more, return false
if (!reprap.GetMove()->GetCurrentState(moveBuffer))
return 0;
//check to see if the move is a 'homing' move that endstops are checked on.
checkEndStops = false;
if (gb->Seen('S'))
{
@ -427,8 +488,10 @@ int GCodes::SetUpMove(GCodeBuffer *gb)
checkEndStops = true;
}
}
LoadMoveBufferFromGCode(gb, false, !checkEndStops && limitAxes);
//loads the movebuffer with either the absolute movement required or the
//relative movement required
LoadMoveBufferFromGCode(gb, false, !checkEndStops && limitAxes);
//There is a new move in the move buffer
moveAvailable = true;
return (checkEndStops) ? 2 : 1;
}
@ -499,7 +562,7 @@ bool GCodes::DoFileCannedCycles(const char* fileName)
return false;
}
doFilePrint(cannedCycleGCode);
DoFilePrint(cannedCycleGCode);
return false;
}
@ -601,7 +664,7 @@ bool GCodes::OffsetAxes(GCodeBuffer* gb)
}
}
if (gb->Seen(gCodeLetters[DRIVES])) // Has the user specified a feedrate?
if(gb->Seen(FEEDRATE_LETTER)) // Has the user specified a feedrate?
{
moveToDo[DRIVES] = gb->GetFValue();
activeDrive[DRIVES] = true;
@ -628,7 +691,7 @@ bool GCodes::OffsetAxes(GCodeBuffer* gb)
// booleans homeX, homeY and homeZ.
// Returns true if completed, false if needs to be called again.
// 'reply' is only written if there is an error.
// 'error' is false on entry, gets changed to true iff there is an error.
// 'error' is false on entry, gets changed to true if there is an error.
bool GCodes::DoHome(char* reply, bool& error)
//pre(reply.upb == STRING_LENGTH)
{
@ -961,15 +1024,18 @@ bool GCodes::SetPrintZProbe(GCodeBuffer* gb, char* reply)
// are updated at the end of each movement, so this won't tell you
// where you are mid-movement.
// FIXME - needs to deal with multiple extruders
//Fixed to deal with multiple extruders
char* GCodes::GetCurrentCoordinates()
{
float liveCoordinates[DRIVES + 1];
reprap.GetMove()->LiveCoordinates(liveCoordinates);
snprintf(scratchString, STRING_LENGTH, "X:%f Y:%f Z:%f E:%f", liveCoordinates[X_AXIS], liveCoordinates[Y_AXIS],
liveCoordinates[Z_AXIS], liveCoordinates[AXES]);
snprintf(scratchString, STRING_LENGTH, "X:%f Y:%f Z:%f ", liveCoordinates[X_AXIS], liveCoordinates[Y_AXIS], liveCoordinates[Z_AXIS]);
for(int i = AXES; i< DRIVES; i++)
{
sncatf(scratchString, STRING_LENGTH, "E%d:%f ",i-AXES,liveCoordinates[i]);
}
return scratchString;
}
@ -979,6 +1045,7 @@ bool GCodes::OpenFileToWrite(const char* directory, const char* fileName, GCodeB
eofStringCounter = 0;
if (fileBeingWritten == NULL)
{
platform->Message(HOST_MESSAGE, "Can't open GCode file for writing.\n");
return false;
}
else
@ -1087,13 +1154,13 @@ void GCodes::QueueFileToPrint(const char* fileName)
void GCodes::DeleteFile(const char* fileName)
{
if (!platform->GetMassStorage()->Delete(platform->GetGCodeDir(), fileName))
{
platform->Message(HOST_MESSAGE, "Unsuccessful attempt to delete: ");
platform->Message(HOST_MESSAGE, fileName);
platform->Message(HOST_MESSAGE, "\n");
webserver->HandleReply("Failed to delete file", true);
}
if(!platform->GetMassStorage()->Delete(platform->GetGCodeDir(), fileName))
{
platform->Message(HOST_MESSAGE, "Unsuccessful attempt to delete: ");
platform->Message(HOST_MESSAGE, fileName);
platform->Message(HOST_MESSAGE, "\n");
webserver->HandleReply("Failed to delete file", true);
}
}
// Send the config file to USB in response to an M503 command.
@ -1130,7 +1197,7 @@ bool GCodes::SendConfigToLine()
bool GCodes::DoDwell(GCodeBuffer *gb)
{
if (!gb->Seen('P'))
if(!gb->Seen('P'))
return true; // No time given - throw it away
float dwell = 0.001 * (float) gb->GetLValue(); // P values are in milliseconds; we need seconds
@ -1173,7 +1240,7 @@ bool GCodes::SetOffsets(GCodeBuffer *gb)
int8_t head;
if (gb->Seen('P'))
{
head = gb->GetIValue() + 1; // 0 is the Bed
head = gb->GetIValue(); // 0 is the Bed
if (gb->Seen('R'))
reprap.GetHeat()->SetStandbyTemperature(head, gb->GetFValue());
@ -1203,7 +1270,7 @@ bool GCodes::StandbyHeaters()
return false;
for (int8_t heater = 0; heater < HEATERS; heater++)
reprap.GetHeat()->Standby(heater);
selectedHead = -1;
selectedHead = -1; //FIXME check this does not mess up setters (eg M906) when they are used after this command is called
return true;
}
@ -1260,9 +1327,47 @@ void GCodes::SetEthernetAddress(GCodeBuffer *gb, int mCode)
}
}
void GCodes::SetMACAddress(GCodeBuffer *gb)
{
uint8_t mac[6];
const char* ipString = gb->GetString();
uint8_t sp = 0;
uint8_t spp = 0;
uint8_t ipp = 0;
while(ipString[sp])
{
if(ipString[sp] == ':')
{
mac[ipp] = strtol(&ipString[spp], NULL, 0);
ipp++;
if(ipp > 5)
{
platform->Message(HOST_MESSAGE, "Dud MAC address: ");
platform->Message(HOST_MESSAGE, gb->Buffer());
platform->Message(HOST_MESSAGE, "\n");
return;
}
sp++;
spp = sp;
}else
sp++;
}
mac[ipp] = strtol(&ipString[spp], NULL, 0);
if(ipp == 5)
{
platform->SetMACAddress(mac);
} else
{
platform->Message(HOST_MESSAGE, "Dud MAC address: ");
platform->Message(HOST_MESSAGE, gb->Buffer());
platform->Message(HOST_MESSAGE, "\n");
}
}
void GCodes::HandleReply(bool error, bool fromLine, const char* reply, char gMOrT, int code, bool resend)
{
if (gMOrT != 'M' || code != 111) // web server reply for M111 is handled before we get here
if (gMOrT != 'M' || code != 111) // web server reply for M111 is handled before we get here
{
webserver->HandleReply(reply, error);
}
@ -1418,7 +1523,6 @@ void GCodes::SetHeaterParameters(GCodeBuffer *gb, char reply[STRING_LENGTH])
{
r25 = pp.GetThermistorR25();
}
if (gb->Seen('B'))
{
beta = gb->GetFValue();
@ -1727,20 +1831,40 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
bool seen = false;
for (int8_t drive = 0; drive < DRIVES; drive++)
{
if (gb->Seen(gCodeLetters[drive]))
//Do AXES first
if(gb->Seen(gCodeLetters[drive])&& drive<AXES)
{
platform->SetDriveStepsPerUnit(drive, gb->GetFValue());
seen = true;
}
else if(selectedHead < 0)
{
// If no head selected, set the first extruder steps - best we can do
if(gb->Seen('E'))
{
platform->SetDriveStepsPerUnit(AXES, gb->GetFValue());
seen=true;
}
}
else if(gb->Seen('E')&& ((drive-AXES) == selectedHead - 1))//then do active extruder
{
platform->SetDriveStepsPerUnit(AXES+selectedHead - 1, gb->GetFValue());
seen=true;
}
}
reprap.GetMove()->SetStepHypotenuse();
if (!seen)
{
snprintf(reply, STRING_LENGTH, "Steps/mm: X:%f, Y:%f, Z:%f, E:%f",
snprintf(reply, STRING_LENGTH, "Steps/mm: X: %f, Y: %f, Z: %f, E: ",
platform->DriveStepsPerUnit(X_AXIS), platform->DriveStepsPerUnit(Y_AXIS),
platform->DriveStepsPerUnit(Z_AXIS), platform->DriveStepsPerUnit(AXES)); // FIXME - needs to do multiple extruders
platform->DriveStepsPerUnit(Z_AXIS));
// Fixed to do multiple extruders.
for(int8_t drive = AXES; drive < DRIVES; drive++)
{
sncatf(reply, STRING_LENGTH, "%.2f:", platform->DriveStepsPerUnit(drive));
}
}
}
}
break;
case 98:
@ -1755,16 +1879,18 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
break;
case 104: // Deprecated
if (gb->Seen('S'))
if(gb->Seen('S') && selectedHead >= 0)
{
reprap.GetHeat()->SetActiveTemperature(1, gb->GetFValue()); // 0 is the bed
reprap.GetHeat()->Activate(1);
//only sets the selected head (As set by T#)
reprap.GetHeat()->SetActiveTemperature(selectedHead, gb->GetFValue()); // 0 is the bed
reprap.GetHeat()->Activate(selectedHead);
}
break;
case 105: // Deprecated...
strncpy(reply, "T:", STRING_LENGTH);
for (int8_t heater = HEATERS - 1; heater > 0; heater--)
//FIXME - why did this decrement rather than increment through the heaters (odd behaviour)
for(int8_t heater = 1; heater < HEATERS; heater++)
{
sncatf(reply, STRING_LENGTH, "%.1f ", reprap.GetHeat()->GetTemperature(heater));
}
@ -1797,28 +1923,23 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
break;
case 109: // Set extruder temperature and wait - deprecated
case 190: // Set bed temperature and wait - deprecated
{
int8_t heater = (code == 190) ? 0 : 1;
if (gb->Seen('S'))
{
reprap.GetHeat()->SetActiveTemperature(heater, gb->GetFValue());
reprap.GetHeat()->Activate(heater);
}
if (!AllMovesAreFinishedAndMoveBufferIsLoaded())
{
return false;
}
result = reprap.GetHeat()->HeaterAtSetTemperature(heater);
}
break;
if(gb->Seen('S') && selectedHead >= 0)
{
reprap.GetHeat()->SetActiveTemperature(selectedHead, gb->GetFValue()); // 0 is the bed
reprap.GetHeat()->Activate(selectedHead);
}
//check here rather than falling through to M116, we want to just wait for the extruder we specified (otherwise use M116 not M109)
result = reprap.GetHeat()->HeaterAtSetTemperature(selectedHead);
break;
case 110: // Set line numbers - line numbers are dealt with in the GCodeBuffer class
break;
case 111: // Debug level
if (gb->Seen('S'))
{
reprap.SetDebug(gb->GetIValue());
}
break;
case 112: // Emergency stop - acted upon in Webserver, but also here in case it comes from USB etc.
@ -1852,7 +1973,10 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
result = reprap.GetHeat()->AllHeatersAtSetTemperatures();
break;
// case 117 is handled later because it falls through to the default case
//TODO M119
case 119:
platform->Message(HOST_MESSAGE, "M119 - endstop status not yet implemented\n");
break;
case 120:
result = Push();
@ -1889,15 +2013,47 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
platform->Message(HOST_MESSAGE, "M141 - heated chamber not yet implemented\n");
break;
// case 190 is with case 109 because it used the same code
case 160: //number of mixing filament drives
if(gb->Seen('S'))
{
int iValue=gb->GetIValue();
platform->SetMixingDrives(iValue);
}
break;
case 190: // Deprecated...
if(gb->Seen('S'))
{
float value=gb->GetFValue();
reprap.GetHeat()->SetActiveTemperature(0, value);
reprap.GetHeat()->SetStandbyTemperature(0, value); // FIXME have to set both?not sure as the bed should always be selected
reprap.GetHeat()->Activate(0);
}
result = reprap.GetHeat()->HeaterAtSetTemperature(0);
break;
case 201: // Set axis accelerations
for (int8_t drive = 0; drive < DRIVES; drive++)
{
if (gb->Seen(gCodeLetters[drive]))
//Do AXES first
if(gb->Seen(gCodeLetters[drive]) && drive<AXES)
{
float value = gb->GetFValue();
platform->SetAcceleration(drive, value);
platform->SetAcceleration(drive, gb->GetFValue());
}
else if(selectedHead < 0)
{
if(gb->Seen('E')) // Do first one - best we can do
{
platform->SetAcceleration(AXES, gb->GetFValue());
}
}//then do active extruder
else if(gb->Seen('E') && ((drive-AXES) == selectedHead-1))
{
platform->SetAcceleration(AXES+selectedHead-1, gb->GetFValue()); //Set the E acceleration for the currently selected tool
}
else
{
platform->SetAcceleration(drive, -1);
}
}
break;
@ -1905,11 +2061,25 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
case 203: // Set maximum feed rates
for (int8_t drive = 0; drive < DRIVES; drive++)
{
if (gb->Seen(gCodeLetters[drive]))
//Do AXES first
if(gb->Seen(gCodeLetters[drive]) && drive<AXES)
{
float value = gb->GetFValue() * distanceScale * 0.016666667; // G Code feedrates are in mm/minute; we need mm/sec;
platform->SetMaxFeedrate(drive, value);
}
}
else if(selectedHead < 0)
{
if(gb->Seen('E'))
{
float value = gb->GetFValue()*distanceScale*0.016666667; // G Code feedrates are in mm/minute; we need mm/sec;
platform->SetMaxFeedrate(AXES, value); //Set the E Steps for the first E - best we can do
}
}
else if(gb->Seen('E') && ((drive-AXES) == selectedHead-1))//then do active extruder
{
float value = gb->GetFValue()*distanceScale*0.016666667; // G Code feedrates are in mm/minute; we need mm/sec;
platform->SetMaxFeedrate(AXES+selectedHead-1, value); //Set the E Steps for the currently selected tool
}
}
break;
@ -2005,6 +2175,13 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
result = SendConfigToLine();
break;
case 540:
if(gb->Seen('P'))
{
SetMACAddress(gb);
}
break;
case 550: // Set machine name
if (gb->Seen('P'))
reprap.GetWebserver()->SetName(gb->GetString());
@ -2012,12 +2189,16 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
case 551: // Set password
if (gb->Seen('P'))
{
reprap.GetWebserver()->SetPassword(gb->GetString());
}
break;
case 552: // Set/Get IP address
if (gb->Seen('P'))
{
SetEthernetAddress(gb, code);
}
else
{
const byte *ip = platform->IPAddress();
@ -2027,7 +2208,9 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
case 553: // Set/Get netmask
if (gb->Seen('P'))
{
SetEthernetAddress(gb, code);
}
else
{
const byte *nm = platform->NetMask();
@ -2037,7 +2220,9 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
case 554: // Set/Get gateway
if (gb->Seen('P'))
{
SetEthernetAddress(gb, code);
}
else
{
const byte *gw = platform->GateWay();
@ -2047,7 +2232,9 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
case 555: // Set firmware type to emulate
if (gb->Seen('P'))
{
platform->SetEmulating((Compatibility) gb->GetIValue());
}
break;
case 556: // Axis compensation
@ -2055,8 +2242,12 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
{
float value = gb->GetFValue();
for (int8_t axis = 0; axis < AXES; axis++)
{
if (gb->Seen(gCodeLetters[axis]))
{
reprap.GetMove()->SetAxisCompensation(axis, gb->GetFValue() / value);
}
}
}
break;
@ -2142,20 +2333,41 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
}
break;
case 564: // Think outside the box?
if(gb->Seen('S'))
{
limitAxes = (gb->GetIValue() != 0);
}
case 563: // Define tool
break;
case 564: // Think outside the box?
if(gb->Seen('S'))
{
limitAxes = (gb->GetIValue() != 0);
}
break;
case 906: // Set Motor currents
for (uint8_t i = 0; i < DRIVES; i++)
{
if (gb->Seen(gCodeLetters[i]))
//Do AXES first
if(gb->Seen(gCodeLetters[i])&& i<AXES)
{
float value = gb->GetFValue(); // mA
float value = gb->GetFValue(); // mA
platform->SetMotorCurrent(i, value);
}
else if(selectedHead < 0)
{
if(gb->Seen('E'))
{
float value = gb->GetFValue(); // mA
platform->SetMotorCurrent(AXES, value); // Set first one - best we can do
}
}
else //do for selected extruder
{
if(gb->Seen(gCodeLetters[i]))
{
float value = gb->GetFValue(); // mA
platform->SetMotorCurrent(AXES+selectedHead-1, value);
}
}
}
break;
@ -2195,41 +2407,43 @@ bool GCodes::HandleMcode(GCodeBuffer* gb)
bool GCodes::HandleTcode(GCodeBuffer* gb)
{
bool error = false;
char reply[STRING_LENGTH];
reply[0] = 0;
int code = gb->GetIValue();
if (code == selectedHead)
{
HandleReply(error, gb == serialGCode, reply, 'T', code, false);
HandleReply(false, gb == serialGCode, reply, 'T', code, false);
return true;
}
error = true;
for (int8_t i = AXES; i < DRIVES; i++)
{
if (selectedHead == i - AXES)
{
reprap.GetHeat()->Standby(selectedHead + 1); // + 1 because 0 is the Bed
if(selectedHead == i - AXES + 1)
{
reprap.GetHeat()->Standby(selectedHead);
}
}
bool toolNotFound = true;
for (int8_t i = AXES; i < DRIVES; i++)
{
if (code == i - AXES)
if(code == i - AXES + 1)
{
selectedHead = code;
reprap.GetHeat()->Activate(selectedHead + 1); // 0 is the Bed
error = false;
reprap.GetHeat()->Activate(selectedHead);
toolNotFound = false;
}
}
if (error)
{
snprintf(reply, STRING_LENGTH, "Invalid T Code: %s", gb->Buffer());
}
if(toolNotFound)
{
selectedHead = -1;
}
HandleReply(error, gb == serialGCode, reply, 'T', code, false);
// snprintf(reply, STRING_LENGTH, "Invalid T Code: %s", gb->Buffer());
HandleReply(false, gb == serialGCode, reply, 'T', code, false);
return true;
}
@ -2387,6 +2601,7 @@ float GCodeBuffer::GetFValue()
if (readPointer < 0)
{
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode float before a search.\n");
readPointer = -1;
return 0.0;
}
float result = (float) strtod(&gcodeBuffer[readPointer + 1], 0);
@ -2394,6 +2609,66 @@ float GCodeBuffer::GetFValue()
return result;
}
// Get a :-separated list of floats after a key letter
const void GCodeBuffer::GetFloatArray(float a[], int& length)
{
length = 0;
if(readPointer < 0)
{
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode float array before a search.\n");
readPointer = -1;
return;
}
bool inList = true;
while(inList)
{
a[length] = (float)strtod(&gcodeBuffer[readPointer + 1], 0);
length++;
readPointer++;
while(gcodeBuffer[readPointer] && (gcodeBuffer[readPointer] != ' ') && (gcodeBuffer[readPointer] != LIST_SEPARATOR))
{
readPointer++;
}
if(gcodeBuffer[readPointer] != LIST_SEPARATOR)
{
inList = false;
}
}
readPointer = -1;
}
// Get a :-separated list of longs after a key letter
const void GCodeBuffer::GetLongArray(long l[], int& length)
{
length = 0;
if(readPointer < 0)
{
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode long array before a search.\n");
readPointer = -1;
return;
}
bool inList = true;
while(inList)
{
l[length] = strtol(&gcodeBuffer[readPointer + 1], 0, 0);
length++;
readPointer++;
while(gcodeBuffer[readPointer] && (gcodeBuffer[readPointer] != ' ') && (gcodeBuffer[readPointer] != LIST_SEPARATOR))
{
readPointer++;
}
if(gcodeBuffer[readPointer] != LIST_SEPARATOR)
{
inList = false;
}
}
readPointer = -1;
}
// Get a string after a G Code letter found by a call to Seen().
// It will be the whole of the rest of the GCode string, so strings
// should always be the last parameter.
@ -2403,6 +2678,7 @@ const char* GCodeBuffer::GetString()
if (readPointer < 0)
{
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode string before a search.\n");
readPointer = -1;
return "";
}
const char* result = &gcodeBuffer[readPointer + 1];
@ -2425,11 +2701,14 @@ const char* GCodeBuffer::GetUnprecedentedString()
{
readPointer = 0;
while (gcodeBuffer[readPointer] && gcodeBuffer[readPointer] != ' ')
{
readPointer++;
}
if (!gcodeBuffer[readPointer])
{
platform->Message(HOST_MESSAGE, "GCodes: String expected but not seen.\n");
readPointer = -1;
return gcodeBuffer; // Good idea?
}
@ -2445,6 +2724,7 @@ long GCodeBuffer::GetLValue()
if (readPointer < 0)
{
platform->Message(HOST_MESSAGE, "GCodes: Attempt to read a GCode int before a search.\n");
readPointer = -1;
return 0;
}
long result = strtol(&gcodeBuffer[readPointer + 1], 0, 0);

229
GCodes.h
View file

@ -25,7 +25,8 @@ Licence: GPL
#define STACK 5
#define GCODE_LENGTH 100 // Maximum length of internally-generated G Code string
#define GCODE_LETTERS { 'X', 'Y', 'Z', 'E', 'F' } // The drives and feedrate in a GCode
#define GCODE_LETTERS { 'X', 'Y', 'Z', 'E', 'F' } // The drives and feedrate in a GCode //FIXME when working with multiple extruders GCODE_LETTERS[DRIVES] is out of scope
#define FEEDRATE_LETTER 'F'//FIX to work with multiple extruders without having to re-define GCODE_LETTERS array
// Small class to hold an individual GCode and provide functions to allow it to be parsed
@ -33,34 +34,36 @@ class GCodeBuffer
{
public:
GCodeBuffer(Platform* p, const char* id);
void Init();
bool Put(char c);
bool Seen(char c);
float GetFValue();
int GetIValue();
long GetLValue();
const char* GetUnprecedentedString();
const char* GetString();
void Init(); // Set it up
bool Put(char c); // Add a character to the end
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(); // 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();
bool Active() const;
void SetFinished(bool f);
void SetFinished(bool f); // Set the G Code executed (or not)
void Pause();
void CancelPause();
const char* WritingFileDirectory() const;
void SetWritingFileDirectory(const char* wfd);
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
private:
enum State { idle, executing, paused };
int CheckSum();
Platform* platform;
char gcodeBuffer[GCODE_LENGTH];
const char* identity;
int gcodePointer;
int readPointer;
bool inComment;
State state;
const char* writingFileDirectory;
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
};
//****************************************************************************************************
@ -72,113 +75,118 @@ class GCodes
public:
GCodes(Platform* p, Webserver* w);
void Spin();
void Init();
void Exit();
void Spin(); // Called in a tight loop to make this class work
void Init(); // Set it up
void Exit(); // Shut it down
void Reset();
bool RunConfigurationGCodes();
bool ReadMove(float* m, bool& ce);
void QueueFileToPrint(const char* fileName);
void DeleteFile(const char* fileName);
bool GetProbeCoordinates(int count, float& x, float& y, float& z);
char* GetCurrentCoordinates();
bool PrintingAFile() const;
void Diagnostics();
bool HaveIncomingData() const;
bool GetAxisIsHomed(uint8_t axis) const { return axisIsHomed[axis]; }
bool RunConfigurationGCodes(); // Run the configuration G Code file on reboot
bool ReadMove(float* m, bool& 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); // Get pre-recorded probe coordinates
char* GetCurrentCoordinates(); // Get where we are as a string
bool PrintingAFile() const; // Are we in the middle of printing a file?
void Diagnostics(); // Send helpful information out
int8_t GetSelectedHead() const; // return which tool is selected
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; }
float GetExtruderPosition(uint8_t extruder) const;
void PauseSDPrint();
private:
void doFilePrint(GCodeBuffer* gb);
bool AllMovesAreFinishedAndMoveBufferIsLoaded();
bool DoCannedCycleMove(bool ce);
bool DoFileCannedCycles(const char* fileName);
bool FileCannedCyclesReturn();
bool ActOnGcode(GCodeBuffer* gb);
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(bool ce); // Do a move from an internally programmed canned cycle
bool DoFileCannedCycles(const char* fileName); // Run a GCode macro in a file
bool FileCannedCyclesReturn(); // End a macro
bool ActOnGcode(GCodeBuffer* gb); // Do the G Code
bool HandleGcode(GCodeBuffer* gb);
bool HandleMcode(GCodeBuffer* gb);
bool HandleTcode(GCodeBuffer* gb);
int SetUpMove(GCodeBuffer* gb);
bool DoDwell(GCodeBuffer *gb);
bool DoDwell(GCodeBuffer *gb); // Wait for a bit
bool DoDwellTime(float dwell);
bool DoHome(char *reply, bool& error);
bool DoSingleZProbeAtPoint();
bool DoSingleZProbe();
bool SetSingleZProbeAtAPosition(GCodeBuffer *gb);
bool DoMultipleZProbe();
bool SetPrintZProbe(GCodeBuffer *gb, char *reply);
bool SetOffsets(GCodeBuffer *gb);
bool SetPositions(GCodeBuffer *gb);
void LoadMoveBufferFromGCode(GCodeBuffer *gb, bool doingG92, bool applyLimits);
bool NoHome() const;
bool Push();
bool Pop();
bool DisableDrives();
bool StandbyHeaters();
void SetEthernetAddress(GCodeBuffer *gb, int mCode);
void HandleReply(bool error, bool fromLine, const char* reply, char gMOrT, int code, bool resend);
bool OpenFileToWrite(const char* directory, const char* fileName, GCodeBuffer *gb);
void WriteGCodeToFile(GCodeBuffer *gb);
bool SendConfigToLine();
void WriteHTMLToFile(char b, GCodeBuffer *gb);
bool OffsetAxes(GCodeBuffer *gb);
bool DoHome(char *reply, bool& error); // Home some axes
bool DoSingleZProbeAtPoint(); // Probe at a given point
bool DoSingleZProbe(); // Probe where we are
bool SetSingleZProbeAtAPosition(GCodeBuffer *gb); // Probes at a given position - see the comment at the head of the function itself
bool DoMultipleZProbe(); // Probes a series of points and sets the bed equation
bool SetPrintZProbe(GCodeBuffer *gb, char *reply); // Either return the probe value, or set its threshold
bool SetOffsets(GCodeBuffer *gb); // Deal with a G10
bool SetPositions(GCodeBuffer *gb); // Deal with a G92
void 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
bool DisableDrives(); // Turn the motors off
bool StandbyHeaters(); // Set all heaters to standby temperatures
void SetEthernetAddress(GCodeBuffer *gb, int mCode); // Does what it says
void SetMACAddress(GCodeBuffer *gb); // Deals with an M540
void HandleReply(bool error, bool fromLine, const char* reply, // If the GCode is from the serial interface, reply to it
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, char reply[STRING_LENGTH]);
void SetHeaterParameters(GCodeBuffer *gb, char reply[STRING_LENGTH]);
int8_t Heater(int8_t head) const;
Platform* platform;
bool active;
Webserver* webserver;
float dwellTime;
bool dwellWaiting;
GCodeBuffer* webGCode;
GCodeBuffer* fileGCode;
GCodeBuffer* serialGCode;
GCodeBuffer* cannedCycleGCode;
bool moveAvailable;
float moveBuffer[DRIVES+1]; // Last is feed rate
bool checkEndStops;
bool drivesRelative; // All except X, Y and Z
bool axesRelative; // X, Y and Z
bool drivesRelativeStack[STACK];
bool axesRelativeStack[STACK];
float feedrateStack[STACK];
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* cannedCycleGCode; // ... of G Codes
bool moveAvailable; // Have we seen a move G Code and set it up?
float moveBuffer[DRIVES+1]; // Move coordinates; last is feed rate
bool checkEndStops; // Should 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;
char gCodeLetters[DRIVES + 1]; // Extra is for F
float lastPos[DRIVES - AXES]; // Just needed for relative moves.
float record[DRIVES+1];
float moveToDo[DRIVES+1];
bool activeDrive[DRIVES+1];
bool offSetSet;
float distanceScale;
int8_t stackPointer; // Push and Pop stack pointer
char gCodeLetters[DRIVES + 1]; // 'X', 'Y' etc. Extra is for F
float lastPos[DRIVES - AXES]; // Just needed for relative moves; i.e. not X, Y and Z
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;
FileStore* configFile;
bool doingCannedCycleFile;
char* eofString;
uint8_t eofStringCounter;
uint8_t eofStringLength;
int8_t selectedHead;
bool homeX;
bool homeY;
bool homeZ;
float gFeedRate;
int probeCount;
int8_t cannedCycleMoveCount;
bool cannedCycleMoveQueued;
bool zProbesSet;
float longWait;
bool limitAxes; // Don't think outside the box.
bool axisIsHomed[3]; // these record which of the axes have been homed
FileStore* fileBeingWritten; // A file to write G Codes (or sometimes HTML) in
FileStore* configFile; // A file containing a macro
bool doingCannedCycleFile; // Are we executing a macro file?
char* eofString; // What's at the end of an HTML file?
uint8_t eofStringCounter; // Check the...
uint8_t eofStringLength; // ... EoF string as we read.
int8_t selectedHead; // Which extruder is in use
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
int8_t homeAxisMoveCount; // Counts homing moves
float gFeedRate; // Store for the current feedrate
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
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 extrusionFactor; // extrusion factor, normally 1.0
float speedFactor; // speed factor, including the conversion from mm/min to mm/sec, normally 1/60
float extrusionFactor; // extrusion factor, normally 1.0
};
//*****************************************************************************************************
@ -262,4 +270,9 @@ inline bool GCodes::RunConfigurationGCodes()
return !DoFileCannedCycles(platform->GetConfigFile());
}
inline int8_t GCodes::GetSelectedHead() const
{
return selectedHead;
}
#endif

75
Heat.h
View file

@ -21,68 +21,78 @@ Licence: GPL
#ifndef HEAT_H
#define HEAT_H
/**
* This class implements a PID controller for the heaters
*/
class PID
{
public:
friend class Heat;
private:
//public:
PID(Platform* p, int8_t h);
void Init();
void Spin();
void Init(); // (Re)Set everything to start
void Spin(); // Called in a tight loop to keep things running
void SetActiveTemperature(float t);
float GetActiveTemperature() const;
void SetStandbyTemperature(float t);
float GetStandbyTemperature() const;
void Activate();
void Standby();
void Activate(); // Switch from idle to active
void Standby(); // Switch from active to idle
bool Active() const;
void ResetFault();
void ResetFault(); // Reset a fault condition - only call this if you know what you are doing
float GetTemperature() const;
// private:
private:
Platform* platform;
float activeTemperature;
float standbyTemperature;
float temperature;
float lastTemperature;
float temp_iState;
bool active;
int8_t heater;
int8_t badTemperatureCount;
bool temperatureFault;
Platform* platform; // The instance of the class that is the RepRap hardware
float activeTemperature; // The required active temperature
float standbyTemperature; // The required standby temperature
float temperature; // The current temperature
float lastTemperature; // The previous current temperature
float temp_iState; // The integral PID component
bool active; // Are we active or standby?
int8_t heater; // The index of our heater
int8_t badTemperatureCount; // Count of sequential dud readings
bool temperatureFault; // Has our heater developed a fault?
};
/**
* The master class that controls all the heaters in the RepRap machine
*/
class Heat
{
public:
Heat(Platform* p, GCodes* g);
void Spin();
void Init();
void Exit();
void Spin(); // Called in a tight loop to keep everything going
void Init(); // Set everything up
void Exit(); // Shut everything down
void SetActiveTemperature(int8_t heater, float t);
float GetActiveTemperature(int8_t heater) const;
void SetStandbyTemperature(int8_t heater, float t);
float GetStandbyTemperature(int8_t heater) const;
void Activate(int8_t heater);
void Standby(int8_t heater);
void Activate(int8_t heater); // Turn on a heater
void Standby(int8_t heater); // Set a heater idle
float GetTemperature(int8_t heater) const;
void ResetFault(int8_t heater);
void ResetFault(int8_t heater); // Reset a heater fault - oly call this if you know what you are doing
bool AllHeatersAtSetTemperatures() const;
bool HeaterAtSetTemperature(int8_t heater) const; // Is a specific heater at temperature within tolerance?
void Diagnostics();
void Diagnostics(); // Output useful information
private:
Platform* platform;
GCodes* gCodes;
bool active;
PID* pids[HEATERS];
float lastTime;
float longWait;
Platform* platform; // The instance of the RepRap hardware class
GCodes* gCodes; // The instance of the G Code interpreter class
bool active; // Are we active?
PID* pids[HEATERS]; // A PID controller for each heater
float lastTime; // The last time our Spin() was called
float longWait; // Long time for things that happen occasionally
};
//***********************************************************************************************************
@ -189,5 +199,4 @@ inline void Heat::ResetFault(int8_t heater)
}
#endif

View file

@ -513,6 +513,9 @@ err_t ethernetif_init(struct netif *netif)
netif->output = etharp_output;
netif->linkoutput = low_level_output;
#if 1
// We now require the user to configure the MAC address if the default one is unsuitable, instead of selecting it automatically
#else
// Patch the last 4 bytes of the MAC address to be the IP address, so that we can support multiple Duets on the same subnet
{
size_t i;
@ -521,9 +524,19 @@ err_t ethernetif_init(struct netif *netif)
gs_uc_mac_address[i + 2] = ((uint8_t*)&(netif->ip_addr))[i];
}
}
#endif
/* Initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
void RepRapNetworkSetMACAddress(const u8_t macAddress[])
{
size_t i;
for (i = 0; i < 8; ++i)
{
gs_uc_mac_address[i] = macAddress[i];
}
}

View file

@ -271,7 +271,8 @@ bool Move::GetCurrentState(float m[])
if(i < AXES)
m[i] = lastMove->MachineToEndPoint(i);
else
m[i] = 0.0;
m[i] = 0.0; //FIXME This resets extruders to 0.0, even the inactive ones (is this behaviour desired?)
//m[i] = lastMove->MachineToEndPoint(i); //FIXME TEST alternative that does not reset extruders to 0
}
if(currentFeedrate >= 0.0)
m[DRIVES] = currentFeedrate;
@ -364,7 +365,7 @@ void Move::SetStepHypotenuse()
// We don't want 0. If no axes/extruders are moving these should never be used.
// But try to be safe.
stepDistances[0] = 1.0/platform->DriveStepsPerUnit(AXES);
stepDistances[0] = 1.0/platform->DriveStepsPerUnit(AXES); //FIXME this is not multi extruder safe (but we should never get here)
extruderStepDistances[0] = stepDistances[0];
}
@ -520,7 +521,7 @@ void Move::DoLookAhead()
else if (mt & zMove)
c = platform->InstantDv(Z_AXIS);
else
c = platform->InstantDv(AXES); // value for first extruder FIXME??
c = platform->InstantDv((AXES+gCodes->GetSelectedHead())); // value for current extruder
}
n1->SetV(c);
n1->SetProcessed(vCosineSet);
@ -571,7 +572,7 @@ void Move::Interrupt()
dda = NULL;
}
// creates a new lookahead object adds it to the lookahead ring, returns false if its full
bool Move::LookAheadRingAdd(const long ep[], float feedRate, float vv, bool ce, int8_t mt)
{
if(LookAheadRingFull())
@ -614,7 +615,7 @@ void Move::SetIdentityTransform()
secondDegreeCompensation = false;
}
void Move::Transform(float xyzPoint[])
void Move::Transform(float xyzPoint[]) const
{
xyzPoint[X_AXIS] = xyzPoint[X_AXIS] + tanXY*xyzPoint[Y_AXIS] + tanXZ*xyzPoint[Z_AXIS];
xyzPoint[Y_AXIS] = xyzPoint[Y_AXIS] + tanYZ*xyzPoint[Z_AXIS];
@ -624,7 +625,7 @@ void Move::Transform(float xyzPoint[])
xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] + aX*xyzPoint[X_AXIS] + aY*xyzPoint[Y_AXIS] + aC;
}
void Move::InverseTransform(float xyzPoint[])
void Move::InverseTransform(float xyzPoint[]) const
{
if(secondDegreeCompensation)
xyzPoint[Z_AXIS] = xyzPoint[Z_AXIS] - SecondDegreeTransformZ(xyzPoint[X_AXIS], xyzPoint[Y_AXIS]);
@ -973,15 +974,18 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
// by a velocity later.
int8_t mt = myLookAheadEntry->GetMovementType();
if(mt & xyMove) // X or Y involved?
{
// If XY (or Z) are moving, then the extruder won't be considered in the
// acceleration calculation. Usually this is OK. But check that we are not asking
// the extruder to accelerate, decelerate, or move too fast. The common place
// for this to happen is when it is moving back from a previous retraction during
// an XY move.
if(mt & xyMove) // X or Y involved?
{
// If XY (or Z) are moving, then the extruder won't be considered in the
// acceleration calculation. Usually this is OK. But check that we are not asking
// the extruder to accelerate, decelerate, or move too fast. The common place
// for this to happen is when it is moving back from a previous retraction during
// an XY move.
if((mt & eMove) && eDistance > distance)
{
SetEAcceleration(eDistance);
@ -990,7 +994,7 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
{
SetXYAcceleration();
}
} else if (mt & zMove) // Z involved?
} else if (mt & zMove) // Z involved?
{
acceleration = platform->Acceleration(Z_AXIS);
instantDv = platform->InstantDv(Z_AXIS);
@ -1240,11 +1244,13 @@ float LookAhead::Cosine()
return cosine;
}
//Returns units (mm) from steps for a particular drive
float LookAhead::MachineToEndPoint(int8_t drive, long coord)
{
return ((float)coord)/reprap.GetPlatform()->DriveStepsPerUnit(drive);
}
//Returns steps from units (mm) for a particular drive
long LookAhead::EndPointToMachine(int8_t drive, float coord)
{
return (long)roundf(coord*reprap.GetPlatform()->DriveStepsPerUnit(drive));

271
Move.h
View file

@ -60,188 +60,204 @@ enum PointCoordinateSet
zSet = 4
};
/**
* This class implements a look-ahead buffer for moves. It allows colinear
* moves not to decelerate between them, sets velocities at ends and beginnings
* for angled moves, and so on. Entries are joined in a doubly-linked list
* to form a ring buffer.
*/
class LookAhead
{
public:
friend class Move;
friend class DDA;
protected:
LookAhead(Move* m, Platform* p, LookAhead* n);
void Init(const long ep[], float feedRate, float vv, bool ce, int8_t mt);
LookAhead* Next();
LookAhead* Previous();
void Init(const long ep[], float feedRate, float vv, bool ce, int8_t mt); // Set up this move
LookAhead* Next(); // Next one in the ring
LookAhead* Previous(); // Previous one in the ring
const long* MachineEndPoints() const;
float MachineToEndPoint(int8_t drive);
static float MachineToEndPoint(int8_t drive, long coord);
static long EndPointToMachine(int8_t drive, float coord);
int8_t GetMovementType() const;
float FeedRate() const;
float V() const;
void SetV(float vv);
void SetFeedRate(float f);
int8_t Processed() const;
void SetProcessed(MovementState ms);
void SetDriveCoordinateAndZeroEndSpeed(float a, int8_t drive);
bool CheckEndStops() const;
void Release();
float MachineToEndPoint(int8_t drive); // Convert a move endpoint to real mm coordinates
static float MachineToEndPoint(int8_t drive, long coord); // Convert any number to a real coordinate
static long EndPointToMachine(int8_t drive, float coord); // Convert real mm to a machine coordinate
int8_t GetMovementType() const; // What sort of move is this?
float FeedRate() const; // How fast is the maximum speed for this move
float V() const; // The speed at the end of the move
void SetV(float vv); // Set the end speed
void SetFeedRate(float f); // Set the desired feedrate
int8_t Processed() const; // Where we are in the look-ahead prediction sequence
void SetProcessed(MovementState ms); // Set where we are the the look ahead processing
void SetDriveCoordinateAndZeroEndSpeed(float a, int8_t drive); // Force an end ppoint and st its speed to stopped
bool CheckEndStops() const; // Are we checking endstops on this move?
void Release(); // This move has been processed and executed
private:
Move* move;
Platform* platform;
LookAhead* next;
LookAhead* previous;
long endPoint[DRIVES+1]; // Should never use the +1, but safety first
int8_t movementType;
float Cosine();
bool checkEndStops;
float cosine;
float v; // The feedrate we can actually do
float feedRate; // The requested feedrate
float instantDv;
volatile int8_t processed;
Move* move; // The main movement control class
Platform* platform; // The RepRap machine
LookAhead* next; // Next entry in the ring
LookAhead* previous; // Previous entry in the ring
long endPoint[DRIVES+1]; // Machine coordinates of the endpoint. Should never use the +1, but safety first
int8_t movementType; // XY move, Z move, extruder only etc
float Cosine(); // The angle between the previous move and this one
bool checkEndStops; // Check endstops for this move
float cosine; // Store for the cosine value - the function uses lazy evaluation
float v; // The feedrate we can actually do
float feedRate; // The requested feedrate
float instantDv; // The slowest speed we can move at. > 0
volatile int8_t processed; // The stage in the look ahead process that this move is at.
};
/**
* This implements an integer space machine coordinates Bressenham-style DDA to step the drives.
* DDAs are stored in a linked list forming a ring buffer.
*/
class DDA
{
public:
friend class Move;
friend class LookAhead;
protected:
DDA(Move* m, Platform* p, DDA* n);
MovementProfile Init(LookAhead* lookAhead, float& u, float& v);
void Start(bool noTest);
void Step();
MovementProfile Init(LookAhead* lookAhead, float& u, float& v); // Set up the DDA. Also used experimentally in look ahead.
void Start(bool noTest); // Start executing the DDA. I.e. move the move.
void Step(); // Take one step of the DDA. Called by timed interrupt.
bool Active() const;
DDA* Next();
DDA* Next(); // Next entry in the ring
float InstantDv() const;
private:
MovementProfile AccelerationCalculation(float& u, float& v, MovementProfile result);
void SetXYAcceleration();
void SetEAcceleration(float eDistance);
Move* move;
Platform* platform;
DDA* next;
LookAhead* myLookAheadEntry;
long counter[DRIVES];
long delta[DRIVES];
bool directions[DRIVES];
long totalSteps;
long stepCount;
bool checkEndStops;
float timeStep;
float velocity;
long stopAStep;
long startDStep;
float distance;
float acceleration;
float instantDv;
MovementProfile AccelerationCalculation(float& u, float& v, // Compute acceleration profiles
MovementProfile result);
void SetXYAcceleration(); // Compute an XY acceleration
void SetEAcceleration(float eDistance); // Compute an extruder acceleration
Move* move; // The main movement control class
Platform* platform; // The RepRap machine
DDA* next; // The next one in the ring
LookAhead* myLookAheadEntry; // The look-ahead entry corresponding to this DDA
long counter[DRIVES]; // Step counters
long delta[DRIVES]; // How far to move each drive
bool directions[DRIVES]; // Forwards or backwards?
long totalSteps; // Total number of steps for this move
long stepCount; // How many steps we have already taken
bool checkEndStops; // Are we checking endstops?
float timeStep; // The current timestep (seconds)
float velocity; // The current velocity
long stopAStep; // The stepcount at which we stop accelerating
long startDStep; // The stepcount at which we start decelerating
float distance; // How long is the move in real distance
float acceleration; // The acceleration to use
float instantDv; // The lowest possible velocity
float feedRate;
volatile bool active;
volatile bool active; // Is the DDA running?
};
/**
* This is the master movement class. It controls all movement in the machine.
*/
class Move
{
friend class DDA;
public:
Move(Platform* p, GCodes* g);
void Init();
void Spin();
void Exit();
bool GetCurrentState(float m[]); // takes account of all the rings and delays
void LiveCoordinates(float m[]); // Just gives the last point at the end of the last DDA
void Interrupt();
void InterruptTime();
bool AllMovesAreFinished();
void ResumeMoving();
void DoLookAhead();
void HitLowStop(int8_t drive, LookAhead* la, DDA* hitDDA);
void HitHighStop(int8_t drive, LookAhead* la, DDA* hitDDA);
void SetPositions(float move[]);
void SetLiveCoordinates(float coords[]);
void SetXBedProbePoint(int index, float x);
void SetYBedProbePoint(int index, float y);
void SetZBedProbePoint(int index, float z);
float xBedProbePoint(int index) const;
float yBedProbePoint(int index) const;
float zBedProbePoint(int index) const;
int NumberOfProbePoints() const;
int NumberOfXYProbePoints() const;
bool AllProbeCoordinatesSet(int index) const;
bool XYProbeCoordinatesSet(int index) const;
void SetZProbing(bool probing);
void SetProbedBedEquation();
float SecondDegreeTransformZ(float x, float y) const;
float GetLastProbedZ() const;
void SetAxisCompensation(int8_t axis, float tangent);
void SetIdentityTransform();
void Transform(float move[]);
void InverseTransform(float move[]);
void Diagnostics();
float ComputeCurrentCoordinate(int8_t drive, LookAhead* la, DDA* runningDDA);
void SetStepHypotenuse();
friend class DDA;
void Init(); // Start me up
void Spin(); // Called in a tight loop to keep the class going
void Exit(); // Shut down
bool GetCurrentState(float m[]); // Return the current position if possible. Send false otherwise
void LiveCoordinates(float m[]); // Gives the last point at the end of the last complete DDA
void Interrupt(); // The hardware's (i.e. platform's) interrupt should call this.
void InterruptTime(); // Test function - not used
bool AllMovesAreFinished(); // Is the look-ahead ring empty? Stops more moves being added as well.
void ResumeMoving(); // Allow moves to be added after a call to AllMovesAreFinished()
void DoLookAhead(); // Run the look-ahead procedure
void HitLowStop(int8_t drive, // What to do when a low endstop is hit
LookAhead* la, DDA* hitDDA);
void HitHighStop(int8_t drive, // What to do when a high endstop is hit
LookAhead* la, DDA* hitDDA);
void SetPositions(float move[]); // Force the coordinates to be these
void SetLiveCoordinates(float coords[]); // Force the live coordinates (see above) to be these
void SetXBedProbePoint(int index, float x); // Record the X coordinate of a probe point
void SetYBedProbePoint(int index, float y); // Record the Y coordinate of a probe point
void SetZBedProbePoint(int index, float z); // Record the Z coordinate of a probe point
float xBedProbePoint(int index) const; // Get the X coordinate of a probe point
float yBedProbePoint(int index) const; // Get the Y coordinate of a probe point
float zBedProbePoint(int index)const ; // Get the Z coordinate of a probe point
int NumberOfProbePoints() const; // How many points to probe have been set? 0 if incomplete
int NumberOfXYProbePoints() const; // How many XY coordinates of probe points have been set (Zs may not have been probed yet)
bool AllProbeCoordinatesSet(int index) const; // XY, and Z all set for this one?
bool XYProbeCoordinatesSet(int index) const; // Just XY set for this one?
void SetZProbing(bool probing); // Set the Z probe live
void SetProbedBedEquation(); // When we have a full set of probed points, work out the bed's equation
float SecondDegreeTransformZ(float x, float y) const; // Used for second degree bed equation
float GetLastProbedZ() const; // What was the Z when the probe last fired?
void SetAxisCompensation(int8_t axis, float tangent); // Set an axis-pair compensation angle
void SetIdentityTransform(); // Cancel the bed equation; does not reset axis angle compensation
void Transform(float move[]) const; // Take a position and apply the bed and the axis-angle compensations
void InverseTransform(float move[]) const; // Go from a transformed point back to user coordinates
void Diagnostics(); // Report useful stuff
float ComputeCurrentCoordinate(int8_t drive,// Turn a DDA value back into a real world coordinate
LookAhead* la, DDA* runningDDA);
void SetStepHypotenuse(); // Set up the hypotenuse lengths for multiple axis steps, like step both X and Y at once
private:
bool DDARingAdd(LookAhead* lookAhead);
DDA* DDARingGet();
bool DDARingAdd(LookAhead* lookAhead); // Add a processed look-ahead entry to the DDA ring
DDA* DDARingGet(); // Get the next DDA ring entry to be run
bool DDARingEmpty() const;
bool NoLiveMovement() const;
bool DDARingFull() const;
bool GetDDARingLock();
void ReleaseDDARingLock();
bool GetDDARingLock(); // Lock the ring so only this function may access it
void ReleaseDDARingLock(); // Release the DDA ring lock
bool LookAheadRingEmpty() const;
bool LookAheadRingFull() const;
bool LookAheadRingAdd(const long ep[], float feedRate, float vv, bool ce, int8_t movementType);
LookAhead* LookAheadRingGet();
int8_t GetMovementType(const long sp[], const long ep[]) const;
LookAhead* LookAheadRingGet(); // Get the next entry from the look-ahead ring
int8_t GetMovementType(const long sp[], const long ep[]) const; // XY? Z? extruder only?
float liveCoordinates[DRIVES + 1];
Platform* platform; // The RepRap machine
GCodes* gCodes; // The G Codes processing class
Platform* platform;
GCodes* gCodes;
// These implement the DDA ring
DDA* dda;
DDA* ddaRingAddPointer;
DDA* ddaRingGetPointer;
volatile bool ddaRingLocked;
// These implement the look-ahead ring
LookAhead* lookAheadRingAddPointer;
LookAhead* lookAheadRingGetPointer;
LookAhead* lastMove;
DDA* lookAheadDDA;
int lookAheadRingCount;
float lastTime;
bool addNoMoreMoves;
bool active;
float currentFeedrate;
float nextMove[DRIVES + 1]; // Extra is for feedrate
float stepDistances[(1<<AXES)]; // Index bits: lsb -> dx, dy, dz <- msb
float extruderStepDistances[(1<<(DRIVES-AXES))]; // NB - limits us to 5 extruders
long nextMachineEndPoints[DRIVES+1];
float xBedProbePoints[NUMBER_OF_PROBE_POINTS];
float yBedProbePoints[NUMBER_OF_PROBE_POINTS];
float zBedProbePoints[NUMBER_OF_PROBE_POINTS];
uint8_t probePointSet[NUMBER_OF_PROBE_POINTS];
float aX, aY, aC; // Bed plane explicit equation z' = z + aX*x + aY*y + aC
float tanXY, tanYZ, tanXZ; // 90 degrees + angle gives angle between axes
float xRectangle, yRectangle;
float lastZHit;
bool zProbing;
bool secondDegreeCompensation;
float longWait;
float lastTime; // The last time we were called (secs)
bool addNoMoreMoves; // If true, allow no more moves to be added to the look-ahead
bool active; // Are we live and running?
float currentFeedrate; // Err... the current feed rate...
float liveCoordinates[DRIVES + 1]; // The last endpoint that the machine moved to
float nextMove[DRIVES + 1]; // The endpoint of the next move to processExtra entry is for feedrate
float stepDistances[(1<<AXES)]; // The entry for [0b011] is the hypotenuse of an X and Y step together etc. Index bits: lsb -> dx, dy, dz <- msb
float extruderStepDistances[(1<<(DRIVES-AXES))];// Same as above for the extruders. NB - may limit us to 5 extruders
long nextMachineEndPoints[DRIVES+1]; // The next endpoint in machine coordinates (i.e. steps)
float xBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The X coordinates of the points on the bed at which to probe
float yBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The X coordinates of the points on the bed at which to probe
float zBedProbePoints[NUMBER_OF_PROBE_POINTS]; // The X coordinates of the points on the bed at which to probe
uint8_t probePointSet[NUMBER_OF_PROBE_POINTS]; // Has the XY of this point been set? Has the Z been probed?
float aX, aY, aC; // Bed plane explicit equation z' = z + aX*x + aY*y + aC
float tanXY, tanYZ, tanXZ; // Axis compensation - 90 degrees + angle gives angle between axes
float xRectangle, yRectangle; // The side lengths of the rectangle used for second-degree bed compensation
float lastZHit; // The last Z value hit by the probe
bool zProbing; // Are we bed probing as well as moving?
bool secondDegreeCompensation; // Are we using second degree bed compensation. If not, linear
float longWait; // A long time for things that need to be done occasionally
};
//********************************************************************************************************
@ -274,7 +290,6 @@ inline float LookAhead::MachineToEndPoint(int8_t drive)
return ((float)(endPoint[drive]))/platform->DriveStepsPerUnit(drive);
}
inline float LookAhead::FeedRate() const
{
return feedRate;

View file

@ -50,6 +50,8 @@ extern "C"
#include "lwip/src/include/lwip/stats.h"
#include "lwip/src/include/lwip/tcp.h"
void RepRapNetworkSetMACAddress(const u8_t macAddress[]);
}
const int httpStateSize = MEMP_NUM_TCP_PCB + 1; // the +1 is in case of recovering from network errors
@ -317,6 +319,7 @@ void Network::AppendTransaction(RequestState* volatile* list, RequestState *r)
void Network::Init()
{
RepRapNetworkSetMACAddress(reprap.GetPlatform()->MACAddress());
init_ethernet();
}

View file

@ -43,7 +43,6 @@ void setup()
}
reprap.Init();
//reprap.GetMove()->InterruptTime(); // Uncomment this line to time the interrupt routine on startup
}
void loop()
@ -122,6 +121,7 @@ void Platform::Init()
nvData.ipAddress = IP_ADDRESS;
nvData.netMask = NET_MASK;
nvData.gateWay = GATE_WAY;
nvData.macAddress = MAC_ADDRESS;
nvData.zProbeType = 0; // Default is to use the switch
nvData.switchZProbeParameters.Init(0.0);
@ -160,8 +160,8 @@ void Platform::Init()
fileStructureInitialised = true;
mcp.begin();
mcpDuet.begin(); //only call begin once in the entire execution, this begins the I2C comms on that channel for all objects
mcpExpansion.setMCP4461Address(0x2E); //not required for mcpDuet, as this uses the default address
sysDir = SYS_DIR;
configFile = CONFIG_FILE;
@ -180,6 +180,7 @@ void Platform::Init()
potWipes = POT_WIPES;
senseResistor = SENSE_RESISTOR;
maxStepperDigipotVoltage = MAX_STEPPER_DIGIPOT_VOLTAGE;
numMixingDrives = NUM_MIXING_DRIVES;
// Z PROBE
@ -207,26 +208,30 @@ void Platform::Init()
webDir = WEB_DIR;
gcodeDir = GCODE_DIR;
tempDir = TEMP_DIR;
/*
FIXME Nasty having to specify individually if a pin is arduino or not.
requires a unified variant file. If implemented this would be much better
to allow for different hardware in the future
*/
for (size_t i = 0; i < DRIVES; i++)
{
if (stepPins[i] >= 0)
{
if (i > Z_AXIS)
if(i == E0_DRIVE || i == E3_DRIVE) //STEP_PINS {14, 25, 5, X2, 41, 39, X4, 49}
pinModeNonDue(stepPins[i], OUTPUT);
else
pinMode(stepPins[i], OUTPUT);
}
if (directionPins[i] >= 0)
{
if (i > Z_AXIS)
if(i == E0_DRIVE) //DIRECTION_PINS {15, 26, 4, X3, 35, 53, 51, 48}
pinModeNonDue(directionPins[i], OUTPUT);
else
pinMode(directionPins[i], OUTPUT);
}
if (enablePins[i] >= 0)
{
if (i >= Z_AXIS)
if(i == Z_AXIS || i==E0_DRIVE || i==E2_DRIVE) //ENABLE_PINS {29, 27, X1, X0, 37, X8, 50, 47}
pinModeNonDue(enablePins[i], OUTPUT);
else
pinMode(enablePins[i], OUTPUT);
@ -234,8 +239,7 @@ void Platform::Init()
Disable(i);
driveEnabled[i] = false;
}
for (size_t i = 0; i < AXES; i++)
for(size_t i = 0; i < DRIVES; i++)
{
if (lowStopPins[i] >= 0)
{
@ -253,7 +257,7 @@ void Platform::Init()
{
if (heatOnPins[i] >= 0)
{
if (i == 0) // heater 0 (bed heater) is a standard Arduino PWM pin
if(i == E0_HEATER || i==E1_HEATER) //HEAT_ON_PINS {6, X5, X7, 7, 8, 9}
{
pinMode(heatOnPins[i], OUTPUT);
}
@ -262,7 +266,6 @@ void Platform::Init()
pinModeNonDue(heatOnPins[i], OUTPUT);
}
}
thermistorFilters[i].Init();
heaterAdcChannels[i] = PinToAdcChannel(tempSensePins[i]);
@ -276,8 +279,8 @@ void Platform::Init()
if (coolingFanPin >= 0)
{
pinMode(coolingFanPin, OUTPUT);
analogWrite(coolingFanPin, (HEAT_ON == 0) ? 255 : 0); // turn auxiliary cooling fan off
//pinModeNonDue(coolingFanPin, OUTPUT); //not required as analogwrite does this automatically
analogWriteNonDue(coolingFanPin, 255); //inverse logic for Duet v0.6 this turns it off
}
InitialiseInterrupts();
@ -540,9 +543,6 @@ void Platform::Spin()
line->Spin();
if (Time() - lastTime < 0.006)
return;
lastTime = Time();
ClassReport("Platform", longWait);
}
@ -722,7 +722,6 @@ void Platform::SetDebug(int d)
case DiagnosticTest::TestSpinLockup:
debugCode = d; // tell the Spin function to loop
break;
default:
break;
}
@ -898,11 +897,17 @@ void Platform::SetHeater(size_t heater, const float& power)
byte p = (byte) (255.0 * min<float>(1.0, max<float>(0.0, power)));
if (HEAT_ON == 0)
{
p = 255 - p;
if (heater == 0)
analogWrite(heatOnPins[heater], p);
else
analogWriteNonDue(heatOnPins[heater], p);
if(heater == E0_HEATER || heater == E1_HEATER) //HEAT_ON_PINS {6, X5, X7, 7, 8, 9}
{
analogWriteNonDue(heatOnPins[heater], p);
}
else
{
analogWrite(heatOnPins[heater], p);
}
}
}
EndStopHit Platform::Stopped(int8_t drive)
@ -982,6 +987,7 @@ void Platform::Step(byte drive)
}
// current is in mA
void Platform::SetMotorCurrent(byte drive, float current)
{
unsigned short pot = (unsigned short)(0.256*current*8.0*senseResistor/maxStepperDigipotVoltage);
@ -989,18 +995,28 @@ void Platform::SetMotorCurrent(byte drive, float current)
// snprintf(scratchString, STRING_LENGTH, "%d", pot);
// Message(HOST_MESSAGE, scratchString);
// Message(HOST_MESSAGE, "\n");
mcp.setNonVolatileWiper(potWipes[drive], pot);
mcp.setVolatileWiper(potWipes[drive], pot);
if(drive < 4)
{
mcpDuet.setNonVolatileWiper(potWipes[drive], pot);
mcpDuet.setVolatileWiper(potWipes[drive], pot);
}
else
{
mcpExpansion.setNonVolatileWiper(potWipes[drive], pot);
mcpExpansion.setVolatileWiper(potWipes[drive], pot);
}
}
//Changed to be compatible with existing gcode norms
// M106 S0 = fully off M106 S255 = fully on
void Platform::CoolingFan(float speed)
{
if(coolingFanPin > 0)
if(coolingFanPin >= 0)
{
byte p =(byte)speed;
// The cooling fan output pin gets inverted if HEAT_ON == 0
analogWriteNonDue(coolingFanPin, (uint32_t)( (HEAT_ON == 0) ? (255.0 - speed) : speed));
analogWriteNonDue(coolingFanPin, (HEAT_ON == 0) ? (255 - p) : p);
}
}

View file

@ -1,8 +1,8 @@
/****************************************************************************************************
RepRapFirmware - Platform: RepRapPro Mendel with Duet controller
RepRapFirmware - Platform: RepRapPro Ormerod with Duet controller
Platform contains all the code and definitons to deal with machine-dependent things such as control
Platform contains all the code and definitions to deal with machine-dependent things such as control
pins, bed area, number of extruders, tolerable accelerations and speeds and so on.
No definitions that are system-independent should go in here. Put them in Configuration.h. Note that
@ -57,9 +57,9 @@ Licence: GPL
// Some numbers...
#define STRING_LENGTH 1029 // needs to be long enough to receive web data
#define STRING_LENGTH 1029 // needs to be long enough to receive web data
#define SHORT_STRING_LENGTH 40
#define TIME_TO_REPRAP 1.0e6 // Convert seconds to the units used by the machine (usually microseconds)
#define TIME_TO_REPRAP 1.0e6 // Convert seconds to the units used by the machine (usually microseconds)
#define TIME_FROM_REPRAP 1.0e-6 // Convert the units used by the machine (usually microseconds) to seconds
/**************************************************************************************************/
@ -70,53 +70,64 @@ Licence: GPL
#define AXES 3 // The number of movement axes in the machine, usually just X, Y and Z. <= DRIVES
#define HEATERS 2 // The number of heaters in the machine; 0 is the heated bed even if there isn't one.
// The numbers of entries in each array must correspond with the values of DRIVES,
// AXES, or HEATERS. Set values to -1 to flag unavailability.
// The numbers of entries in each {} array definition must correspond with the values of DRIVES,
// AXES, or HEATERS. Set values to -1 to flag unavailability. Pins are the microcontroller pin numbers.
// DRIVES
#define STEP_PINS {14, 25, 5, X2}
#define DIRECTION_PINS {15, 26, 4, X3}
#define FORWARDS true // What to send to go...
#define BACKWARDS false // ...in each direction
#define ENABLE_PINS {29, 27, X1, X0}
#define ENABLE false // What to send to enable...
#define DISABLE true // ...and disable a drive
#define STEP_PINS {14, 25, 5, X2} // Full array for Duet + Duex4 is {14, 25, 5, X2, 41, 39, X4, 49}
#define DIRECTION_PINS {15, 26, 4, X3} // Full array for Duet + Duex4 is {15, 26, 4, X3, 35, 53, 51, 48}
#define FORWARDS true // What to send to go...
#define BACKWARDS false // ...in each direction
#define ENABLE_PINS {29, 27, X1, X0} // Full array for Duet + Duex4 is {29, 27, X1, X0, 37, X8, 50, 47}
#define ENABLE false // What to send to enable...
#define DISABLE true // ...and disable a drive
#define DISABLE_DRIVES {false, false, true, false} // Set true to disable a drive when it becomes idle
#define LOW_STOP_PINS {11, -1, 60, 31}
#define LOW_STOP_PINS {11, -1, 60, 31} // Full array endstop pins for Duet + Duex4 is {11, 28, 60, 31, 24, 46, 45, 44}
#define HIGH_STOP_PINS {-1, 28, -1, -1}
#define ENDSTOP_HIT 1 // when a stop == this it is hit
#define POT_WIPES {1, 3, 2, 0} // Indices for motor current digipots (if any)
#define SENSE_RESISTOR 0.1 // Stepper motor current sense resistor
#define ENDSTOP_HIT 1 // when a stop == this it is hit
// Indices for motor current digipots (if any)
// first 4 are for digipot 1,(on duet)
// second 4 for digipot 2(on expansion board)
// Full order is {1, 3, 2, 0, 1, 3, 2, 0}, only include as many as you have DRIVES defined
#define POT_WIPES {1, 3, 2, 0} // Indices for motor current digipots (if any)
#define SENSE_RESISTOR 0.1 // Stepper motor current sense resistor (ohms)
#define MAX_STEPPER_DIGIPOT_VOLTAGE ( 3.3*2.5/(2.7+2.5) ) // Stepper motor current reference voltage
#define Z_PROBE_AD_VALUE (400)
#define Z_PROBE_STOP_HEIGHT (0.7) // mm
#define Z_PROBE_PIN (0) // Analogue pin number
#define Z_PROBE_MOD_PIN (61) // Digital pin number to turn the IR LED on (high) or off (low)
#define Z_PROBE_AD_VALUE (400) // Default for the Z probe - should be overwritten by experiment
#define Z_PROBE_STOP_HEIGHT (0.7) // mm
#define Z_PROBE_PIN (0) // Analogue pin number
#define Z_PROBE_MOD_PIN (61) // Digital pin number to turn the IR LED on (high) or off (low)
const unsigned int numZProbeReadingsAveraged = 8; // we average this number of readings with IR on, and the same number with IR off
#define MAX_FEEDRATES {50.0, 50.0, 3.0, 16.0} // mm/sec
#define MAX_FEEDRATES {50.0, 50.0, 3.0, 16.0} // mm/sec
#define ACCELERATIONS {800.0, 800.0, 10.0, 250.0} // mm/sec^2
#define DRIVE_STEPS_PER_UNIT {87.4890, 87.4890, 4000.0, 420.0}
#define INSTANT_DVS {10.0, 10.0, 0.2, 2.0} // (mm/sec) these are also the minimum feed rates which is why I (dc42) decreased X/Y from 15 to 10
#define NUM_MIXING_DRIVES 1; //number of mixing drives
// AXES
#define AXIS_MAXIMA {220, 200, 200} // mm
#define AXIS_MINIMA {0, 0, 0} // mm
#define HOME_FEEDRATES {50.0, 50.0, 1.0} // mm/sec
#define HEAD_OFFSETS {0.0, 0.0, 0.0}
#define HOME_FEEDRATES {50.0, 50.0, 1.0} // mm/sec
#define HEAD_OFFSETS {0.0, 0.0, 0.0} // mm
#define X_AXIS 0 // The index of the X axis
#define X_AXIS 0 // The index of the X axis in the arrays
#define Y_AXIS 1 // The index of the Y axis
#define Z_AXIS 2 // The index of the Z axis
#define E0_DRIVE 3 //the index of the first Extruder drive
#define E1_DRIVE 4 //the index of the second Extruder drive
#define E2_DRIVE 5 //the index of the third Extruder drive
#define E3_DRIVE 6 //the index of the fourth Extruder drive
#define E4_DRIVE 7 //the index of the fifth Extruder drive
// HEATERS - The bed is assumed to be the first
// HEATERS - The bed is assumed to be the at index 0
#define TEMP_SENSE_PINS {5, 4} // Analogue pin numbers
#define HEAT_ON_PINS {6, X5}
#define TEMP_SENSE_PINS {5, 4} // Analogue pin numbers (full array for Duet+Duex4 = {5, 4, 0, 7, 8, 9} )
#define HEAT_ON_PINS {6, X5} // PWM pins (full array for Duet+Duex4 = {6, X5, X7, 7, 8, 9} )
// Bed thermistor: http://uk.farnell.com/epcos/b57863s103f040/sensor-miniature-ntc-10k/dp/1299930?Ntt=129-9930
// Hot end thermistor: http://www.digikey.co.uk/product-search/en?x=20&y=11&KeyWords=480-3137-ND
@ -159,8 +170,8 @@ const float defaultPidMax[HEATERS] = {255, 180}; // maximum value of I-term, mus
#define STANDBY_TEMPERATURES {ABS_ZERO, ABS_ZERO} // We specify one for the bed, though it's not needed
#define ACTIVE_TEMPERATURES {ABS_ZERO, ABS_ZERO}
#define COOLING_FAN_PIN X6
#define HEAT_ON 0 // 0 for inverted heater (e.g. Duet v0.6) 1 for not (e.g. Duet v0.4)
#define COOLING_FAN_PIN X6 //pin D34 is PWM capable but not an Arduino PWM pin - use X6 instead
#define HEAT_ON 0 // 0 for inverted heater (eg Duet v0.6) 1 for not (e.g. Duet v0.4)
// For the theory behind ADC oversampling, see http://www.atmel.com/Images/doc8003.pdf
const unsigned int adOversampleBits = 1; // number of bits we oversample when reading temperatures
@ -174,6 +185,11 @@ const unsigned int adDisconnectedReal = adRangeReal - 3; // we consider an ADC r
const unsigned int adDisconnectedVirtual = adDisconnectedReal << adOversampleBits;
#define HOT_BED 0 // The index of the heated bed; set to -1 if there is no heated bed
#define E0_HEATER 1 //the index of the first extruder heater
#define E1_HEATER 2 //the index of the first extruder heater
#define E2_HEATER 3 //the index of the first extruder heater
#define E3_HEATER 4 //the index of the first extruder heater
#define E4_HEATER 5 //the index of the first extruder heater
/****************************************************************************************************/
@ -182,40 +198,39 @@ const unsigned int adDisconnectedVirtual = adDisconnectedReal << adOversampleBit
#define MAX_FILES (10) // must be large enough to handle the max number of simultaneous web requests + file being printed
#define FILE_BUF_LEN (256)
#define SD_SPI (4) //Pin
#define WEB_DIR "0:/www/" // Place to find web files on the server
#define GCODE_DIR "0:/gcodes/" // Ditto - g-codes
#define SYS_DIR "0:/sys/" // Ditto - system files
#define TEMP_DIR "0:/tmp/" // Ditto - temporary files
#define FILE_LIST_SEPARATOR ','
#define FILE_LIST_BRACKET '"'
#define FILE_LIST_LENGTH (1000) // Maximum length of file list - can't make it much longer unless we also make jsonResponse longer
#define WEB_DIR "0:/www/" // Place to find web files on the SD card
#define GCODE_DIR "0:/gcodes/" // Ditto - g-codes
#define SYS_DIR "0:/sys/" // Ditto - system files
#define TEMP_DIR "0:/tmp/" // Ditto - temporary files
#define FILE_LIST_LENGTH (1000) // Maximum length of file list
#define FLASH_LED 'F' // Type byte of a message that is to flash an LED; the next two bytes define the frequency and M/S ratio.
#define DISPLAY_MESSAGE 'L' // Type byte of a message that is to appear on a local display; the L is not displayed; \f and \n should be supported.
#define HOST_MESSAGE 'H' // Type byte of a message that is to be sent to the host; the H is not sent.
#define FLASH_LED 'F' // Type byte of a message that is to flash an LED; the next two bytes define
// the frequency and M/S ratio.
#define DISPLAY_MESSAGE 'L' // Type byte of a message that is to appear on a local display; the L is
// not displayed; \f and \n should be supported.
#define HOST_MESSAGE 'H' // Type byte of a message that is to be sent to the host; the H is not sent.
#define DEBUG_MESSAGE 'D' // Type byte of a message that is to be sent for debugging; the D is not sent.
#define MAC_ADDRESS {0xBE, 0xEF, 0xDE, 0xAD, 0xFE, 0xED}
/****************************************************************************************************/
// Miscellaneous...
//#define LED_PIN 13 // Indicator LED
#define BAUD_RATE 115200 // Communication speed of the USB if needed.
#define BAUD_RATE 115200 // Communication speed of the USB if needed.
const int atxPowerPin = 12; // Arduino Due pin number that controls the ATX power on/off
const uint16_t lineInBufsize = 256; // use a power of 2 for good performance
const uint16_t lineOutBufSize = 2048; // ideally this should be large enough to hold the results of an M503 command,
// but could be reduced if we ever need the memory
const uint16_t NumZProbeReadingsAveraged = 8; // must be an even number, preferably a power of 2 for performance, and no greater than 64
/****************************************************************************************************/
enum EndStopHit
{
noStop = 0, // no endstop hit
lowHit = 1, // low switch hit, or Z-probe in use and above threshold
lowHit = 1, // low switch hit, or Z-probe in use and above threshold
highHit = 2, // high stop hit
lowNear = 3 // approaching Z-probe threshold
};
@ -254,6 +269,7 @@ namespace DiagnosticTest
{
TestWatchdog = 1001, // test that we get a watchdog reset if the tick interrupt stops
TestSpinLockup = 1002 // test that we get a software reset if a Spin() function takes too long
};
}
@ -515,14 +531,14 @@ public:
void SetDebug(int d);
void SoftwareReset(uint16_t reason);
void SetAtxPower(bool on);
// Timing
float Time(); // Returns elapsed seconds since some arbitrary time
void SetInterrupt(float s); // Set a regular interrupt going every s seconds; if s is -ve turn interrupt off
void DisableInterrupts();
void Tick();
// Communications and data storage
Line* GetLine() const;
@ -532,6 +548,8 @@ public:
const byte* NetMask() const;
void SetGateWay(byte gw[]);
const byte* GateWay() const;
void SetMACAddress(uint8_t mac[]);
const uint8_t* MACAddress() const;
friend class FileStore;
@ -544,7 +562,7 @@ public:
const char* GetConfigFile() const; // Where the configuration is stored (in the system dir).
void Message(char type, const char* message); // Send a message. Messages may simply flash an LED, or,
// say, display the messages on an LCD. This may also transmit the messages to the host.
// say, display the messages on an LCD. This may also transmit the messages to the host.
void PushMessageIndent();
void PopMessageIndent();
@ -582,6 +600,11 @@ public:
bool GetZProbeParameters(struct ZProbeParameters& params) const;
bool SetZProbeParameters(const struct ZProbeParameters& params);
bool MustHomeXYBeforeZ() const;
// Mixing support
void SetMixingDrives(int);
int GetMixingDrives();
// Heat and temperature
@ -619,6 +642,7 @@ private:
byte ipAddress[4];
byte netMask[4];
byte gateWay[4];
uint8_t macAddress[6];
Compatibility compatibility;
};
@ -650,7 +674,10 @@ private:
float accelerations[DRIVES];
float driveStepsPerUnit[DRIVES];
float instantDvs[DRIVES];
MCP4461 mcp;
MCP4461 mcpDuet;
MCP4461 mcpExpansion;
int8_t potWipes[DRIVES];
float senseResistor;
float maxStepperDigipotVoltage;
@ -660,6 +687,7 @@ private:
volatile ZProbeAveragingFilter zProbeOnFilter; // Z probe readings we took with the IR turned on
volatile ZProbeAveragingFilter zProbeOffFilter; // Z probe readings we took with the IR turned off
volatile ThermistorAveragingFilter thermistorFilters[HEATERS]; // bed and extruder thermistor readings
int8_t numMixingDrives;
// AXES
@ -671,7 +699,7 @@ private:
float axisMinima[AXES];
float homeFeedrates[AXES];
float headOffsets[AXES]; // FIXME - needs a 2D array
// HEATERS - Bed is assumed to be the first
int GetRawTemperature(byte heater) const;
@ -809,7 +837,7 @@ inline const char* Platform::GetWebDir() const
// Where the gcodes are
inline const char* Platform::GetGCodeDir() const
{
{
return gcodeDir;
}
@ -819,7 +847,7 @@ inline const char* Platform::GetSysDir() const
{
return sysDir;
}
// Where the temporary files are
inline const char* Platform::GetTempDir() const
@ -832,7 +860,7 @@ inline const char* Platform::GetConfigFile() const
{
return configFile;
}
//*****************************************************************************************************************
@ -840,15 +868,15 @@ inline const char* Platform::GetConfigFile() const
// Drive the RepRap machine - Movement
inline float Platform::DriveStepsPerUnit(int8_t drive) const
{
{
return driveStepsPerUnit[drive];
}
}
inline void Platform::SetDriveStepsPerUnit(int8_t drive, float value)
{
driveStepsPerUnit[drive] = value;
}
inline float Platform::Acceleration(int8_t drive) const
{
return accelerations[drive];
@ -916,6 +944,21 @@ inline void Platform::SetMaxFeedrate(int8_t drive, float value)
maxFeedrates[drive] = value;
}
inline void Platform::SetMixingDrives(int num_drives)
{
if(num_drives>(DRIVES-AXES))
{
Message(HOST_MESSAGE, "More mixing extruder drives set with M160 than exist in firmware configuration\n");
return;
}
numMixingDrives = num_drives;
}
inline int Platform::GetMixingDrives()
{
return numMixingDrives;
}
//********************************************************************************************************
// Drive the RepRap machine - Heat and temperature
@ -932,8 +975,6 @@ inline float Platform::HeatSampleTime() const
return heatSampleTime;
}
//****************************************************************************************************************
inline const byte* Platform::IPAddress() const
{
return nvData.ipAddress;
@ -949,6 +990,28 @@ inline const byte* Platform::GateWay() const
return nvData.gateWay;
}
inline void Platform::SetMACAddress(uint8_t mac[])
{
bool changed = false;
for(int8_t i = 0; i < 6; i++)
{
if (nvData.macAddress[i] != mac[i])
{
nvData.macAddress[i] = mac[i];
changed = true;
}
}
if (changed)
{
WriteNvData();
}
}
inline const byte* Platform::MACAddress() const
{
return nvData.macAddress;
}
inline Line* Platform::GetLine() const
{
return line;

Binary file not shown.

View file

@ -165,6 +165,7 @@ RepRap::RepRap() : active(false), debug(false), stopped(false), spinState(0), ti
gCodes = new GCodes(platform, webserver);
move = new Move(platform, gCodes);
heat = new Heat(platform, gCodes);
toolList = NULL;
}
void RepRap::Init()
@ -177,7 +178,7 @@ void RepRap::Init()
webserver->Init();
move->Init();
heat->Init();
currentTool = NULL;
const uint32_t wdtTicks = 256; // number of watchdog ticks @ 32768Hz/128 before the watchdog times out (max 4095)
WDT_Enable(WDT, (wdtTicks << WDT_MR_WDV_Pos) | (wdtTicks << WDT_MR_WDD_Pos) | WDT_MR_WDRSTEN); // enable watchdog, reset the mcu if it times out
active = true; // must do this before we start the network, else the watchdog may time out
@ -199,6 +200,9 @@ void RepRap::Init()
platform->Message(HOST_MESSAGE, "\n");
platform->Message(HOST_MESSAGE, NAME);
platform->Message(HOST_MESSAGE, " is up and running.\n");
fastLoop = FLT_MAX;
slowLoop = 0.0;
lastTime = platform->Time();
}
void RepRap::Exit()
@ -243,6 +247,15 @@ void RepRap::Spin()
spinState = 0;
ticksInSpinState = 0;
// Keep track of the loop time
double t = platform->Time();
double dt = t - lastTime;
if(dt < fastLoop)
fastLoop = dt;
if(dt > slowLoop)
slowLoop = dt;
lastTime = t;
}
void RepRap::Diagnostics()
@ -252,6 +265,10 @@ void RepRap::Diagnostics()
heat->Diagnostics();
gCodes->Diagnostics();
webserver->Diagnostics();
snprintf(scratchString, STRING_LENGTH, "Slow loop secs: %f; fast: %f\n", slowLoop, fastLoop);
platform->Message(HOST_MESSAGE, scratchString);
fastLoop = FLT_MAX;
slowLoop = 0.0;
}
// Turn off the heaters, disable the motors, and
@ -265,6 +282,13 @@ void RepRap::EmergencyStop()
//platform->DisableInterrupts();
Tool* t = toolList;
while(t)
{
t->Standby();
t = t->Next();
}
heat->Exit();
for(int8_t i = 0; i < HEATERS; i++)
{
@ -290,6 +314,84 @@ void RepRap::EmergencyStop()
webserver->HandleReply("Emergency Stop! Reset the controller to continue.", false);
}
void RepRap::AddTool(Tool* t)
{
if(toolList == NULL)
{
toolList = t;
return;
}
toolList->AddTool(t);
}
void RepRap::SelectTool(int toolNumber)
{
Tool* t = toolList;
while(t)
{
if(t->Number() == toolNumber)
{
t->Activate(currentTool);
currentTool = t;
return;
}
t = t->Next();
}
platform->Message(HOST_MESSAGE, "Attempt to select and activate a non-existent tool.\n");
}
void RepRap::StandbyTool(int toolNumber)
{
Tool* t = toolList;
while(t)
{
if(t->Number() == toolNumber)
{
t->Standby();
if(currentTool == t)
currentTool = NULL;
return;
}
t = t->Next();
}
platform->Message(HOST_MESSAGE, "Attempt to standby a non-existent tool.\n");
}
void RepRap::SetToolVariables(int toolNumber, float x, float y, float z, float* standbyTemperatures, float* activeTemperatures)
{
Tool* t = toolList;
while(t)
{
if(t->Number() == toolNumber)
{
t->SetVariables(x, y, z, standbyTemperatures, activeTemperatures);
return;
}
t = t->Next();
}
platform->Message(HOST_MESSAGE, "Attempt to set-up a non-existent tool.\n");
}
void RepRap::GetCurrentToolOffset(float& x, float& y, float& z)
{
if(currentTool == NULL)
{
platform->Message(HOST_MESSAGE, "Attempt to get offset when no tool selected.\n");
x = 0.0;
y = 0.0;
z = 0.0;
return;
}
currentTool->GetOffset(x, y, z);
}
void RepRap::Tick()
{
if (active)
@ -306,7 +408,6 @@ void RepRap::Tick()
{
platform->SetHeater(i, 0.0);
}
for(uint8_t i = 0; i < DRIVES; i++)
{
platform->Disable(i);
@ -324,6 +425,7 @@ void RepRap::Tick()
// 1 = debug on
// other = print stats and run code-specific tests
void RepRap::SetDebug(int d)
{
switch(d)
{

View file

@ -35,15 +35,16 @@ class Webserver;
class GCodes;
class Move;
class Heat;
class Tool;
class RepRap;
class FileStore;
// A single instance of the RepRap class contains all the others
extern RepRap reprap;
// Functions and globals not part of any class
void debugPrintf(const char* fmt, ...);
int sncatf(char *dst, size_t len, const char* fmt, ...);
#if 0 // no longer used
@ -53,7 +54,7 @@ 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);
// Macro to give us the number of elements in an array
#define ARRAY_SIZE(_x) (sizeof(_x)/sizeof(_x[0]))
// Macro to give us the highest valid index into an array i.e. one less than the size
@ -69,6 +70,7 @@ extern char scratchString[];
#include "GCodes.h"
#include "Move.h"
#include "Heat.h"
#include "Tool.h"
#include "Reprap.h"
// std::min and std::max don't seem to work with this variant of gcc, so define our own ones here

View file

@ -34,6 +34,11 @@ class RepRap
void Diagnostics();
bool Debug() const;
void SetDebug(int d);
void AddTool(Tool* t);
void SelectTool(int toolNumber);
void StandbyTool(int toolNumber);
void SetToolVariables(int toolNumber, float x, float y, float z, float* standbyTemperatures, float* activeTemperatures);
void GetCurrentToolOffset(float& x, float& y, float& z);
Platform* GetPlatform() const;
Move* GetMove() const;
Heat* GetHeat() const;
@ -52,9 +57,13 @@ class RepRap
Heat* heat;
GCodes* gCodes;
Webserver* webserver;
Tool* toolList;
Tool* currentTool;
uint16_t ticksInSpinState;
uint8_t spinState;
bool debug;
float fastLoop, slowLoop;
float lastTime;
bool stopped;
bool active;
bool resetting;
@ -71,7 +80,6 @@ inline void RepRap::Interrupt() { move->Interrupt(); }
inline bool RepRap::IsStopped() const { return stopped; }
inline uint16_t RepRap::GetTicksInSpinState() const { return ticksInSpinState; }
#endif

107
Tool.cpp Normal file
View file

@ -0,0 +1,107 @@
/****************************************************************************************************
RepRapFirmware - Tool
This class implements a tool in the RepRap machine, usually (though not necessarily) an extruder.
Tools may have zero or more drives associated with them and zero or more heaters. There are a fixed number
of tools in a given RepRap, with fixed heaters and drives. All this is specified on reboot, and cannot
be altered dynamically. This restriction may be lifted in the future. Tool descriptions are stored in
GCode macros that are loaded on reboot.
-----------------------------------------------------------------------------------------------------
Version 0.1
Created on: Apr 11, 2014
Adrian Bowyer
RepRap Professional Ltd
http://reprappro.com
Licence: GPL
****************************************************************************************************/
#include "RepRapFirmware.h"
Tool::Tool(int tNum, int d[], int h[])
{
myNumber = tNum;
next = NULL;
active = false;
for(driveCount = 0; driveCount < DRIVES; driveCount++)
if(d[driveCount] < 0)
break;
if(driveCount > 0)
{
drives = new int[driveCount];
for(int8_t drive = 0; drive < driveCount; drive++)
drives[drive] = d[drive];
}
for(heaterCount = 0; heaterCount < HEATERS; heaterCount++)
if(h[heaterCount] < 0)
break;
if(heaterCount > 0)
{
heaters = new int[heaterCount];
for(int8_t heater = 0; heater < heaterCount; heater++)
heaters[heater] = h[heater];
}
x = 0.0;
y = 0.0;
z = 0.0;
}
// Add a tool to the end of the linked list.
// (We must already be in it.)
void Tool::AddTool(Tool* t)
{
Tool* last = this;
Tool* n = next;
while(n)
{
last = n;
n = Next();
}
t->next = NULL; // Defensive...
last->next = t;
}
void Tool::Activate(Tool* currentlyActive)
{
if(active)
return;
if(currentlyActive)
currentlyActive->Standby();
for(int8_t heater = 0; heater < heaterCount; heater++)
reprap.GetHeat()->Activate(heaters[heater]);
active = true;
}
void Tool::Standby()
{
if(!active)
return;
for(int8_t heater = 0; heater < heaterCount; heater++)
reprap.GetHeat()->Standby(heaters[heater]);
active = false;
}
void Tool::SetVariables(float xx, float yy, float zz, float* standbyTemperatures, float* activeTemperatures)
{
x = xx;
y = yy;
z = zz;
for(int8_t heater = 0; heater < heaterCount; heater++)
{
reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
}
}

78
Tool.h Normal file
View file

@ -0,0 +1,78 @@
/****************************************************************************************************
RepRapFirmware - Tool
This class implements a tool in the RepRap machine, usually (though not necessarily) an extruder.
Tools may have zero or more drives associated with them and zero or more heaters. There are a fixed number
of tools in a given RepRap, with fixed heaters and drives. All this is specified on reboot, and cannot
be altered dynamically. This restriction may be lifted in the future. Tool descriptions are stored in
GCode macros that are loaded on reboot.
-----------------------------------------------------------------------------------------------------
Version 0.1
Created on: Apr 11, 2014
Adrian Bowyer
RepRap Professional Ltd
http://reprappro.com
Licence: GPL
****************************************************************************************************/
#ifndef TOOL_H_
#define TOOL_H_
class Tool
{
public:
Tool(int tNum, int d[], int h[]);
friend class RepRap;
protected:
Tool* Next();
int Number();
void Activate(Tool* currentlyActive);
void Standby();
void AddTool(Tool* t);
void SetVariables(float xx, float yy, float zz, float* standbyTemperatures, float* activeTemperatures);
void GetOffset(float& xx, float& yy, float& zz);
private:
int myNumber;
int* drives;
int driveCount;
int* heaters;
int heaterCount;
Tool* next;
float x, y, z;
bool active;
};
inline Tool* Tool::Next()
{
return next;
}
inline int Tool::Number()
{
return myNumber;
}
inline void Tool::GetOffset(float& xx, float& yy, float& zz)
{
xx = x;
yy = y;
zz = z;
}
#endif /* TOOL_H_ */