Version 1.09s beta 4
Enhancements: - Implemented M143 and M350 - Wait until movement finished when processing M906 - Allow for additional axes in M906 reporting code - Added support for external drivers module - Aux2 device support is now conditional - Added separate error code for temperature above safety limit Bug fixes: - Fixed spurious error report when processing corrupt input line - When there is a temperature error, return the correct error code - Update the overheat ADC value when changing thermistor parameters - Fixed occasional divide by zero problem in PrintMonitor that led to AJAX errors - Cold extrusion prevention only checks the active tool, to allow the same extruder and heater to be configured in multiple tools - If extrusion is prevented because of a temperature fault, display a message instead of silently preventing extrusion
This commit is contained in:
parent
a5722accc7
commit
bac9eb516e
15 changed files with 498 additions and 252 deletions
|
@ -26,17 +26,20 @@ Licence: GPL
|
|||
#define NAME "RepRapFirmware"
|
||||
|
||||
#ifndef VERSION
|
||||
#define VERSION "1.09r-dc42"
|
||||
#define VERSION "1.09s-dc42-beta4"
|
||||
#endif
|
||||
|
||||
#ifndef DATE
|
||||
#define DATE "2016-01-16"
|
||||
#define DATE "2016-03-08"
|
||||
#endif
|
||||
|
||||
#define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman"
|
||||
|
||||
#define FLASH_SAVE_ENABLED (1)
|
||||
|
||||
//#define EXTERNAL_DRIVERS (1)
|
||||
//#define FIRST_EXTERNAL_DRIVE (4)
|
||||
|
||||
// Other firmware that we might switch to be compatible with.
|
||||
|
||||
enum Compatibility
|
||||
|
@ -81,9 +84,9 @@ const float HOT_ENOUGH_TO_EXTRUDE = 160.0; // Celsius
|
|||
const float HOT_ENOUGH_TO_RETRACT = 90.0; // Celsius
|
||||
const float TIME_TO_HOT = 150.0; // Seconds
|
||||
|
||||
const uint8_t MAX_BAD_TEMPERATURE_COUNT = 6; // Number of bad temperature samples before a heater fault is reported
|
||||
const uint8_t MAX_BAD_TEMPERATURE_COUNT = 4; // Number of bad temperature samples permitted before a heater fault is reported
|
||||
const float BAD_LOW_TEMPERATURE = -10.0; // Celsius
|
||||
const float BAD_HIGH_TEMPERATURE = 300.0; // Celsius
|
||||
const float DEFAULT_TEMPERATURE_LIMIT = 300.0; // Celsius
|
||||
const float HOT_END_FAN_TEMPERATURE = 45.0; // Temperature at which a thermostatic hot end fan comes on
|
||||
const float BAD_ERROR_TEMPERATURE = 2000.0; // must exceed BAD_HIGH_TEMPERATURE
|
||||
|
||||
|
|
21
ExternalDrivers.h
Normal file
21
ExternalDrivers.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ExternalDrivers.h
|
||||
*
|
||||
* Created on: 23 Jan 2016
|
||||
* Author: David
|
||||
*/
|
||||
|
||||
#ifndef EXTERNALDRIVERS_H_
|
||||
#define EXTERNALDRIVERS_H_
|
||||
|
||||
namespace ExternalDrivers
|
||||
{
|
||||
void Init();
|
||||
void SetCurrent(size_t drive, float current);
|
||||
void EnableDrive(size_t drive, bool en);
|
||||
uint32_t GetStatus(size_t drive);
|
||||
bool SetMicrostepping(size_t drive, int microsteps, int mode);
|
||||
unsigned int GetMicrostepping(size_t drive, bool& interpolation);
|
||||
};
|
||||
|
||||
#endif /* EXTERNALDRIVERS_H_ */
|
|
@ -65,12 +65,14 @@ bool GCodeBuffer::Put(char c)
|
|||
// Deal with line numbers and checksums
|
||||
if (Seen('*'))
|
||||
{
|
||||
int csSent = GetIValue();
|
||||
int csHere = CheckSum();
|
||||
Seen('N');
|
||||
const int csSent = GetIValue();
|
||||
const int csHere = CheckSum();
|
||||
if (csSent != csHere)
|
||||
{
|
||||
if (Seen('N'))
|
||||
{
|
||||
snprintf(gcodeBuffer, GCODE_LENGTH, "M998 P%d", GetIValue());
|
||||
}
|
||||
Init();
|
||||
return true;
|
||||
}
|
||||
|
|
106
GCodes.cpp
106
GCodes.cpp
|
@ -3550,8 +3550,19 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
|
|||
}
|
||||
break;
|
||||
|
||||
case 143: // Set temperature limit
|
||||
if (gb->Seen('S'))
|
||||
{
|
||||
platform->SetTemperatureLimit(gb->GetFValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.printf("Temperature limit is %.1fC", platform->GetTemperatureLimit());
|
||||
}
|
||||
break;
|
||||
|
||||
case 144: // Set bed to standby
|
||||
#if BED_HEATER != -1
|
||||
#if BED_HEATER >= 0
|
||||
reprap.GetHeat()->Standby(BED_HEATER);
|
||||
#else
|
||||
reply.copy("Hot bed is not present!");
|
||||
|
@ -3559,14 +3570,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
|
|||
#endif
|
||||
break;
|
||||
|
||||
// case 160: //number of mixing filament drives TODO: With tools defined, is this needed?
|
||||
// if(gb->Seen('S'))
|
||||
// {
|
||||
// platform->SetMixingDrives(gb->GetIValue());
|
||||
// }
|
||||
// break;
|
||||
|
||||
case 190: // Deprecated...
|
||||
case 190: // Set bed temperature and wait
|
||||
if (!AllMovesAreFinishedAndMoveBufferIsLoaded()) // tell Move not to wait for more moves
|
||||
{
|
||||
return false;
|
||||
|
@ -3818,9 +3822,75 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
|
|||
SetHeaterParameters(gb, reply);
|
||||
break;
|
||||
|
||||
case 350: // Set/report microstepping
|
||||
if (!AllMovesAreFinishedAndMoveBufferIsLoaded())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
{
|
||||
// interp is current an int not a bool, because we use special values of interp to set the chopper control register
|
||||
int interp = 0;
|
||||
if (gb->Seen('I'))
|
||||
{
|
||||
interp = gb->GetIValue();
|
||||
}
|
||||
|
||||
bool seen = false;
|
||||
for (size_t axis = 0; axis < AXES; axis++)
|
||||
{
|
||||
if (gb->Seen(axisLetters[axis]))
|
||||
{
|
||||
seen = true;
|
||||
int microsteps = gb->GetIValue();
|
||||
if (!platform->SetMicrostepping(axis, microsteps, interp))
|
||||
{
|
||||
platform->MessageF(GENERIC_MESSAGE, "Drive %c does not support %dx microstepping%s\n",
|
||||
axisLetters[axis], microsteps, (interp) ? " with interpolation" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gb->Seen(extrudeLetter))
|
||||
{
|
||||
seen = true;
|
||||
long eVals[DRIVES - AXES];
|
||||
size_t eCount = DRIVES - AXES;
|
||||
gb->GetLongArray(eVals, eCount);
|
||||
for (size_t e = 0; e < eCount; e++)
|
||||
{
|
||||
if (!platform->SetMicrostepping(AXES + e, (int)eVals[e], interp))
|
||||
{
|
||||
platform->MessageF(GENERIC_MESSAGE, "Drive E%u does not support %dx microstepping%s\n",
|
||||
e, (int)eVals[e], (interp) ? " with interpolation" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!seen)
|
||||
{
|
||||
reply.copy("Microstepping - ");
|
||||
for (size_t axis = 0; axis < AXES; ++axis)
|
||||
{
|
||||
bool interp;
|
||||
int microsteps = platform->GetMicrostepping(axis, interp);
|
||||
reply.catf("%c:%d%s, ", axisLetters[axis], microsteps, (interp) ? "(on)" : "");
|
||||
}
|
||||
reply.cat("E");
|
||||
for (size_t drive = AXES; drive < DRIVES; drive++)
|
||||
{
|
||||
bool interp;
|
||||
int microsteps = platform->GetMicrostepping(drive, interp);
|
||||
reply.catf(":%d%s", microsteps, (interp) ? "(on)" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 400: // Wait for current moves to finish
|
||||
if (!AllMovesAreFinishedAndMoveBufferIsLoaded())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 404: // Filament width and nozzle diameter
|
||||
|
@ -4610,7 +4680,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
|
|||
break;
|
||||
#endif
|
||||
|
||||
case 579: // Scale Cartesian axes (for Delta configurations)
|
||||
case 579: // Scale Cartesian axes (mostly for Delta configurations)
|
||||
{
|
||||
bool seen = false;
|
||||
for(size_t axis = 0; axis < AXES; axis++)
|
||||
|
@ -4820,6 +4890,10 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
|
|||
break;
|
||||
|
||||
case 906: // Set/report Motor currents
|
||||
if (!AllMovesAreFinishedAndMoveBufferIsLoaded())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
{
|
||||
bool seen = false;
|
||||
for (size_t axis = 0; axis < AXES; axis++)
|
||||
|
@ -4856,13 +4930,17 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply)
|
|||
|
||||
if (!seen)
|
||||
{
|
||||
reply.printf("Axis currents (mA) - X:%d, Y:%d, Z:%d, E:", (int) platform->MotorCurrent(X_AXIS),
|
||||
(int) platform->MotorCurrent(Y_AXIS), (int) platform->MotorCurrent(Z_AXIS));
|
||||
reply.copy("Axis currents (mA) - ");
|
||||
for (size_t axis = 0; axis < AXES; ++axis)
|
||||
{
|
||||
reply.catf("%c:%d, ", axisLetters[axis], (int) platform->MotorCurrent(axis));
|
||||
}
|
||||
reply.cat("E");
|
||||
for (size_t drive = AXES; drive < DRIVES; drive++)
|
||||
{
|
||||
reply.catf("%d%c", (int) platform->MotorCurrent(drive), (drive < DRIVES - 1) ? ':' : ',');
|
||||
reply.catf(":%d", (int) platform->MotorCurrent(drive));
|
||||
}
|
||||
reply.catf(" idle factor %d", (int)(platform->GetIdleCurrentFactor() * 100.0));
|
||||
reply.catf(", idle factor %d%%", (int)(platform->GetIdleCurrentFactor() * 100.0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
84
Heat.cpp
84
Heat.cpp
|
@ -163,8 +163,8 @@ void PID::Spin()
|
|||
|
||||
// Always know our temperature, regardless of whether we have been switched on or not
|
||||
|
||||
Platform::TempError err = Platform::TempError::errOpen; // Initially assign an error; call should update but if it doesn't, we'll treat as an error
|
||||
temperature = platform->GetTemperature(heater, &err); // In the event of an error, err is set and BAD_ERROR_TEMPERATURE is returned
|
||||
Platform::TempError err = Platform::TempError::errOk; // assume no error
|
||||
temperature = platform->GetTemperature(heater, &err); // in the event of an error, err is set and BAD_ERROR_TEMPERATURE is returned
|
||||
|
||||
// If we're not switched on, or there's a fault, turn the power off and go home.
|
||||
// If we're not switched on, then nothing is using us. This probably means that
|
||||
|
@ -180,7 +180,16 @@ void PID::Spin()
|
|||
|
||||
// We are switched on. Check for faults. Temperature silly-low or silly-high mean open-circuit
|
||||
// or shorted thermistor respectively.
|
||||
if (temperature < BAD_LOW_TEMPERATURE || temperature > BAD_HIGH_TEMPERATURE)
|
||||
if (temperature < BAD_LOW_TEMPERATURE)
|
||||
{
|
||||
err = Platform::TempError::errOpen;
|
||||
}
|
||||
else if (temperature > platform->GetTemperatureLimit())
|
||||
{
|
||||
err = Platform::TempError::errTooHigh;
|
||||
}
|
||||
|
||||
if (err != Platform::TempError::errOk)
|
||||
{
|
||||
if (platform->DoThermistorAdc(heater) || !(Platform::TempErrorPermanent(err)))
|
||||
{
|
||||
|
@ -303,6 +312,75 @@ void PID::Spin()
|
|||
// debugPrintf("Heater %d: e=%f, P=%f, I=%f, d=%f, r=%f\n", heater, error, pp.kP*error, temp_iState, temp_dState, result);
|
||||
}
|
||||
|
||||
void PID::SetActiveTemperature(float t)
|
||||
{
|
||||
if (t > platform->GetTemperatureLimit())
|
||||
{
|
||||
platform->MessageF(GENERIC_MESSAGE, "Error: Temperature %.1f too high for heater %d!\n", t, heater);
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
activeTemperature = t;
|
||||
}
|
||||
|
||||
void PID::SetStandbyTemperature(float t)
|
||||
{
|
||||
if (t > platform->GetTemperatureLimit())
|
||||
{
|
||||
platform->MessageF(GENERIC_MESSAGE, "Error: Temperature %.1f too high for heater %d!\n", t, heater);
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
standbyTemperature = t;
|
||||
}
|
||||
|
||||
void PID::Activate()
|
||||
{
|
||||
if (temperatureFault)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
active = true;
|
||||
if (!heatingUp)
|
||||
{
|
||||
timeSetHeating = platform->Time();
|
||||
}
|
||||
heatingUp = activeTemperature > temperature;
|
||||
}
|
||||
|
||||
void PID::Standby()
|
||||
{
|
||||
if (temperatureFault)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
active = false;
|
||||
if (!heatingUp)
|
||||
{
|
||||
timeSetHeating = platform->Time();
|
||||
}
|
||||
heatingUp = standbyTemperature > temperature;
|
||||
}
|
||||
|
||||
void PID::ResetFault()
|
||||
{
|
||||
temperatureFault = false;
|
||||
timeSetHeating = platform->Time(); // otherwise we will get another timeout immediately
|
||||
badTemperatureCount = 0;
|
||||
}
|
||||
|
||||
void PID::SwitchOff()
|
||||
{
|
||||
SetHeater(0.0);
|
||||
active = false;
|
||||
switchedOff = true;
|
||||
heatingUp = false;
|
||||
}
|
||||
|
||||
float PID::GetAveragePWM() const
|
||||
{
|
||||
return averagePWM * invHeatPwmAverageCount;
|
||||
|
|
69
Heat.h
69
Heat.h
|
@ -137,33 +137,11 @@ inline bool PID::Active() const
|
|||
return active;
|
||||
}
|
||||
|
||||
inline void PID::SetActiveTemperature(float t)
|
||||
{
|
||||
if (t > BAD_HIGH_TEMPERATURE)
|
||||
{
|
||||
platform->MessageF(GENERIC_MESSAGE, "Error: Temperature %.1f too high for heater %d!\n", t, heater);
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
activeTemperature = t;
|
||||
}
|
||||
|
||||
inline float PID::GetActiveTemperature() const
|
||||
{
|
||||
return activeTemperature;
|
||||
}
|
||||
|
||||
inline void PID::SetStandbyTemperature(float t)
|
||||
{
|
||||
if (t > BAD_HIGH_TEMPERATURE)
|
||||
{
|
||||
platform->MessageF(GENERIC_MESSAGE, "Error: Temperature %.1f too high for heater %d!\n", t, heater);
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
standbyTemperature = t;
|
||||
}
|
||||
|
||||
inline float PID::GetStandbyTemperature() const
|
||||
{
|
||||
return standbyTemperature;
|
||||
|
@ -174,58 +152,11 @@ inline float PID::GetTemperature() const
|
|||
return temperature;
|
||||
}
|
||||
|
||||
inline void PID::Activate()
|
||||
{
|
||||
if (temperatureFault)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
active = true;
|
||||
if (!heatingUp)
|
||||
{
|
||||
timeSetHeating = platform->Time();
|
||||
}
|
||||
heatingUp = activeTemperature > temperature;
|
||||
}
|
||||
|
||||
inline void PID::Standby()
|
||||
{
|
||||
if (temperatureFault)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SwitchOn();
|
||||
active = false;
|
||||
if (!heatingUp)
|
||||
{
|
||||
timeSetHeating = platform->Time();
|
||||
}
|
||||
heatingUp = standbyTemperature > temperature;
|
||||
}
|
||||
|
||||
inline bool PID::FaultOccurred() const
|
||||
{
|
||||
return temperatureFault;
|
||||
}
|
||||
|
||||
inline void PID::ResetFault()
|
||||
{
|
||||
temperatureFault = false;
|
||||
timeSetHeating = platform->Time(); // otherwise we will get another timeout immediately
|
||||
badTemperatureCount = 0;
|
||||
}
|
||||
|
||||
inline void PID::SwitchOff()
|
||||
{
|
||||
SetHeater(0.0);
|
||||
active = false;
|
||||
switchedOff = true;
|
||||
heatingUp = false;
|
||||
}
|
||||
|
||||
inline bool PID::SwitchedOff() const
|
||||
{
|
||||
return switchedOff;
|
||||
|
|
|
@ -85,7 +85,7 @@ extern void pinModeNonDue(uint32_t ulPin, uint32_t ulMode, uint32_t debounceCuto
|
|||
return;
|
||||
}
|
||||
|
||||
const PinDescription& pinDesc = (ulPin >= X0) ? nonDuePinDescription[ulPin - X0] : g_APinDescription[ulPin];
|
||||
const PinDescription& pinDesc = GetPinDescription(ulPin);
|
||||
if (pinDesc.ulPinType == PIO_NOT_A_PIN)
|
||||
{
|
||||
return;
|
||||
|
@ -153,7 +153,7 @@ extern void digitalWriteNonDue(uint32_t ulPin, uint32_t ulVal)
|
|||
return;
|
||||
}
|
||||
|
||||
const PinDescription& pinDesc = (ulPin >= X0) ? nonDuePinDescription[ulPin - X0] : g_APinDescription[ulPin];
|
||||
const PinDescription& pinDesc = GetPinDescription(ulPin);
|
||||
if (pinDesc.ulPinType != PIO_NOT_A_PIN)
|
||||
{
|
||||
if (ulVal) // we make use of the fact that LOW is zero and HIGH is nonzero
|
||||
|
@ -179,7 +179,7 @@ extern int digitalReadNonDue( uint32_t ulPin )
|
|||
return LOW;
|
||||
}
|
||||
|
||||
const PinDescription& pinDesc = (ulPin >= X0) ? nonDuePinDescription[ulPin - X0] : g_APinDescription[ulPin];
|
||||
const PinDescription& pinDesc = GetPinDescription(ulPin);
|
||||
if (pinDesc.ulPinType == PIO_NOT_A_PIN)
|
||||
{
|
||||
return LOW ;
|
||||
|
@ -191,7 +191,7 @@ extern int digitalReadNonDue( uint32_t ulPin )
|
|||
// Build a short-form pin descriptor for a IO pin
|
||||
OutputPin::OutputPin(unsigned int pin)
|
||||
{
|
||||
const PinDescription& pinDesc = (pin >= X0) ? nonDuePinDescription[pin - X0] : g_APinDescription[pin];
|
||||
const PinDescription& pinDesc = GetPinDescription(pin);
|
||||
pPort = pinDesc.pPort;
|
||||
ulPin = pinDesc.ulPin;
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ void analogWriteNonDue(uint32_t ulPin, uint32_t ulValue, uint16_t freq)
|
|||
ulValue = 255;
|
||||
}
|
||||
|
||||
const PinDescription& pinDesc = (ulPin >= X0) ? nonDuePinDescription[ulPin - X0] : g_APinDescription[ulPin];
|
||||
const PinDescription& pinDesc = GetPinDescription(ulPin);
|
||||
uint32_t attr = pinDesc.ulPinAttribute;
|
||||
if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG)
|
||||
{
|
||||
|
|
|
@ -84,18 +84,22 @@ public:
|
|||
void SetLow() const { pPort->PIO_CODR = ulPin; }
|
||||
};
|
||||
|
||||
// struct used to hold the descriptions for the "non Arduino" pins.
|
||||
// from the Arduino.h files
|
||||
extern const PinDescription nonDuePinDescription[];
|
||||
extern void pinModeNonDue(uint32_t ulPin, uint32_t ulMode, uint32_t debounceCutoff = 0); // NB only one debounce cutoff frequency can be set per PIO
|
||||
extern void digitalWriteNonDue(uint32_t ulPin, uint32_t ulVal);
|
||||
extern int digitalReadNonDue(uint32_t ulPin);
|
||||
extern OutputPin getPioPin(uint32_t ulPin);
|
||||
extern void analogWriteNonDue(uint32_t ulPin, uint32_t ulValue, uint16_t freq);
|
||||
extern void analogOutputNonDue();
|
||||
extern void hsmciPinsinit();
|
||||
extern void ethPinsInit();
|
||||
extern adc_channel_num_t PinToAdcChannel(int pin); // convert an analog pin number to an ADC channel
|
||||
|
||||
inline const PinDescription& GetPinDescription(uint32_t ulPin)
|
||||
{
|
||||
return (ulPin >= X0) ? nonDuePinDescription[ulPin - X0] : g_APinDescription[ulPin];
|
||||
}
|
||||
|
||||
void pinModeNonDue(uint32_t ulPin, uint32_t ulMode, uint32_t debounceCutoff = 0); // NB only one debounce cutoff frequency can be set per PIO
|
||||
void digitalWriteNonDue(uint32_t ulPin, uint32_t ulVal);
|
||||
int digitalReadNonDue(uint32_t ulPin);
|
||||
OutputPin getPioPin(uint32_t ulPin);
|
||||
void analogWriteNonDue(uint32_t ulPin, uint32_t ulValue, uint16_t freq);
|
||||
void analogOutputNonDue();
|
||||
void hsmciPinsinit();
|
||||
void ethPinsInit();
|
||||
adc_channel_num_t PinToAdcChannel(int pin); // convert an analog pin number to an ADC channel
|
||||
|
||||
#endif /* SAM_NON_DUE_PIN_H */
|
||||
|
||||
|
|
165
Platform.cpp
165
Platform.cpp
|
@ -22,6 +22,10 @@
|
|||
#include "RepRapFirmware.h"
|
||||
#include "DueFlashStorage.h"
|
||||
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
#include "ExternalDrivers.h"
|
||||
#endif
|
||||
|
||||
extern char _end;
|
||||
extern "C" char *sbrk(int i);
|
||||
|
||||
|
@ -109,8 +113,7 @@ bool PidParameters::operator==(const PidParameters& other) const
|
|||
|
||||
Platform::Platform() :
|
||||
autoSaveEnabled(false), board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0),
|
||||
fileStructureInitialised(false), tickState(0), debugCode(0),
|
||||
messageString(messageStringBuffer, ARRAY_SIZE(messageStringBuffer))
|
||||
fileStructureInitialised(false), tickState(0), debugCode(0)
|
||||
{
|
||||
// Output
|
||||
auxOutput = new OutputStack();
|
||||
|
@ -148,7 +151,9 @@ void Platform::Init()
|
|||
|
||||
SERIAL_MAIN_DEVICE.begin(baudRates[0]);
|
||||
SERIAL_AUX_DEVICE.begin(baudRates[1]); // this can't be done in the constructor because the Arduino port initialisation isn't complete at that point
|
||||
#ifdef SERIAL_AUX2_DEVICE
|
||||
SERIAL_AUX2_DEVICE.begin(baudRates[2]);
|
||||
#endif
|
||||
|
||||
// Reconfigure the ADC to avoid crosstalk between channels (especially on Duet 0.8.5)
|
||||
adc_init(ADC, SystemCoreClock, ADC_FREQ_MIN, ADC_STARTUP_FAST); // reduce clock rate
|
||||
|
@ -240,7 +245,11 @@ void Platform::Init()
|
|||
{
|
||||
pinModeNonDue(directionPins[drive], OUTPUT);
|
||||
}
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
if (drive < FIRST_EXTERNAL_DRIVE && enablePins[drive] >= 0)
|
||||
#else
|
||||
if (enablePins[drive] >= 0)
|
||||
#endif
|
||||
{
|
||||
pinModeNonDue(enablePins[drive], OUTPUT);
|
||||
}
|
||||
|
@ -261,6 +270,10 @@ void Platform::Init()
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
ExternalDrivers::Init();
|
||||
#endif
|
||||
|
||||
extrusionAncilliaryPWM = 0.0;
|
||||
|
||||
// HEATERS - Bed is assumed to be index 0
|
||||
|
@ -275,14 +288,8 @@ void Platform::Init()
|
|||
thermistorAdcChannels[heater] = PinToAdcChannel(tempSensePins[heater]); // Translate the Arduino Due Analog pin number to the SAM ADC channel number
|
||||
SetThermistorNumber(heater, heater); // map the thermistor straight through
|
||||
thermistorFilters[heater].Init(analogRead(tempSensePins[heater]));
|
||||
|
||||
// Calculate and store the ADC average sum that corresponds to an overheat condition, so that we can check is quickly in the tick ISR
|
||||
float thermistorOverheatResistance = nvData.pidParams[heater].GetRInf()
|
||||
* exp(-nvData.pidParams[heater].GetBeta() / (BAD_HIGH_TEMPERATURE - ABS_ZERO));
|
||||
float thermistorOverheatAdcValue = (AD_RANGE_REAL + 1) * thermistorOverheatResistance
|
||||
/ (thermistorOverheatResistance + nvData.pidParams[heater].thermistorSeriesR);
|
||||
thermistorOverheatSums[heater] = (uint32_t) (thermistorOverheatAdcValue + 0.9) * THERMISTOR_AVERAGE_READINGS;
|
||||
}
|
||||
SetTemperatureLimit(DEFAULT_TEMPERATURE_LIMIT);
|
||||
|
||||
InitFans();
|
||||
|
||||
|
@ -338,6 +345,20 @@ void Platform::InvalidateFiles()
|
|||
}
|
||||
}
|
||||
|
||||
void Platform::SetTemperatureLimit(float t)
|
||||
{
|
||||
temperatureLimit = t;
|
||||
for (size_t heater = 0; heater < HEATERS; heater++)
|
||||
{
|
||||
// Calculate and store the ADC average sum that corresponds to an overheat condition, so that we can check it quickly in the tick ISR
|
||||
float thermistorOverheatResistance = nvData.pidParams[heater].GetRInf()
|
||||
* exp(-nvData.pidParams[heater].GetBeta() / (temperatureLimit - ABS_ZERO));
|
||||
float thermistorOverheatAdcValue = (AD_RANGE_REAL + 1) * thermistorOverheatResistance
|
||||
/ (thermistorOverheatResistance + nvData.pidParams[heater].thermistorSeriesR);
|
||||
thermistorOverheatSums[heater] = (uint32_t) (thermistorOverheatAdcValue + 0.9) * THERMISTOR_AVERAGE_READINGS;
|
||||
}
|
||||
}
|
||||
|
||||
// Specify which thermistor channel a particular heater uses
|
||||
void Platform::SetThermistorNumber(size_t heater, size_t thermistor)
|
||||
//pre(heater < HEATERS && thermistor < HEATERS)
|
||||
|
@ -781,6 +802,7 @@ void Platform::Spin()
|
|||
OutputBuffer *aux2OutputBuffer = aux2Output->GetFirstItem();
|
||||
if (aux2OutputBuffer != nullptr)
|
||||
{
|
||||
#ifdef SERIAL_AUX2_DEVICE
|
||||
size_t bytesToWrite = min<size_t>(SERIAL_AUX2_DEVICE.canWrite(), aux2OutputBuffer->BytesLeft());
|
||||
if (bytesToWrite > 0)
|
||||
{
|
||||
|
@ -792,6 +814,9 @@ void Platform::Spin()
|
|||
aux2OutputBuffer = OutputBuffer::Release(aux2OutputBuffer);
|
||||
aux2Output->SetFirstItem(aux2OutputBuffer);
|
||||
}
|
||||
#else
|
||||
aux2OutputBuffer = OutputBuffer::Release(aux2OutputBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write non-blocking data to the USB line
|
||||
|
@ -868,7 +893,11 @@ void Platform::SoftwareReset(uint16_t reason)
|
|||
{
|
||||
reason |= (uint16_t)SoftwareResetReason::inLwipSpin;
|
||||
}
|
||||
if (!SERIAL_AUX_DEVICE.canWrite() || !SERIAL_AUX2_DEVICE.canWrite())
|
||||
if (!SERIAL_AUX_DEVICE.canWrite()
|
||||
#ifdef SERIAL_AUX2_DEVICE
|
||||
|| !SERIAL_AUX2_DEVICE.canWrite()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
reason |= (uint16_t)SoftwareResetReason::inAuxOutput; // if we are resetting because we are stuck in a Spin function, record whether we are trying to send to aux
|
||||
}
|
||||
|
@ -880,15 +909,6 @@ void Platform::SoftwareReset(uint16_t reason)
|
|||
temp.magic = SoftwareResetData::magicValue;
|
||||
temp.resetReason = reason;
|
||||
GetStackUsage(NULL, NULL, &temp.neverUsedRam);
|
||||
if (reason != (uint16_t)SoftwareResetReason::user)
|
||||
{
|
||||
strncpy(temp.lastMessage, messageString.Pointer(), sizeof(temp.lastMessage) - 1);
|
||||
temp.lastMessage[sizeof(temp.lastMessage) - 1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.lastMessage[0] = 0;
|
||||
}
|
||||
|
||||
// Save diagnostics data to Flash and reset the software
|
||||
DueFlashStorage::write(SoftwareResetData::nvAddress, &temp, sizeof(SoftwareResetData));
|
||||
|
@ -1022,10 +1042,6 @@ void Platform::Diagnostics()
|
|||
{
|
||||
MessageF(GENERIC_MESSAGE, "Last software reset code & available RAM: 0x%04x, %u\n", temp.resetReason, temp.neverUsedRam);
|
||||
MessageF(GENERIC_MESSAGE, "Spinning module during software reset: %s\n", moduleName[temp.resetReason & 0x0F]);
|
||||
if (temp.lastMessage[0])
|
||||
{
|
||||
MessageF(GENERIC_MESSAGE, "Last message before reset: %s", temp.lastMessage); // usually ends with NL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1178,7 +1194,10 @@ float Platform::GetTemperature(size_t heater, TempError* err) const
|
|||
else
|
||||
{
|
||||
// thermistor short circuit, return a high temperature
|
||||
if (err) *err = TempError::errShort;
|
||||
if (err)
|
||||
{
|
||||
*err = TempError::errShort;
|
||||
}
|
||||
return BAD_ERROR_TEMPERATURE;
|
||||
}
|
||||
}
|
||||
|
@ -1216,6 +1235,7 @@ float Platform::GetTemperature(size_t heater, TempError* err) const
|
|||
case TempError::errShortVcc : return "sensor circuit is shorted to the voltage rail";
|
||||
case TempError::errShortGnd : return "sensor circuit is shorted to ground";
|
||||
case TempError::errOpen : return "sensor circuit is open/disconnected";
|
||||
case TempError::errTooHigh: return "temperature above safety limit";
|
||||
case TempError::errTimeout : return "communication error whilst reading sensor; read took too long";
|
||||
case TempError::errIO: return "communication error whilst reading sensor; check sensor connections";
|
||||
}
|
||||
|
@ -1238,6 +1258,7 @@ bool Platform::AnyHeaterHot(uint16_t heaters, float t) const
|
|||
return false;
|
||||
}
|
||||
|
||||
// Update the heater PID parameters or thermistor resistance etc.
|
||||
void Platform::SetPidParameters(size_t heater, const PidParameters& params)
|
||||
{
|
||||
if (heater < HEATERS && params != nvData.pidParams[heater])
|
||||
|
@ -1247,6 +1268,7 @@ void Platform::SetPidParameters(size_t heater, const PidParameters& params)
|
|||
{
|
||||
WriteNvData();
|
||||
}
|
||||
SetTemperatureLimit(temperatureLimit); // recalculate the thermistor resistance at max allowed temperature for the tick ISR
|
||||
}
|
||||
}
|
||||
const PidParameters& Platform::GetPidParameters(size_t heater) const
|
||||
|
@ -1329,11 +1351,22 @@ void Platform::EnableDrive(size_t drive)
|
|||
{
|
||||
UpdateMotorCurrent(driver); // the current may have been reduced by the idle timeout
|
||||
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
if (drive >= FIRST_EXTERNAL_DRIVE)
|
||||
{
|
||||
ExternalDrivers::EnableDrive(driver - FIRST_EXTERNAL_DRIVE, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
const int pin = enablePins[driver];
|
||||
if (pin >= 0)
|
||||
{
|
||||
digitalWriteNonDue(pin, enableValues[driver]);
|
||||
}
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1344,12 +1377,23 @@ void Platform::DisableDrive(size_t drive)
|
|||
if (drive < DRIVES)
|
||||
{
|
||||
const size_t driver = driverNumbers[drive];
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
if (drive >= FIRST_EXTERNAL_DRIVE)
|
||||
{
|
||||
ExternalDrivers::EnableDrive(driver - FIRST_EXTERNAL_DRIVE, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
const int pin = enablePins[driver];
|
||||
if (pin >= 0)
|
||||
{
|
||||
digitalWriteNonDue(pin, !enableValues[driver]);
|
||||
}
|
||||
driveState[drive] = DriveStatus::disabled;
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1387,9 +1431,17 @@ void Platform::UpdateMotorCurrent(size_t drive)
|
|||
{
|
||||
current *= idleCurrentFactor;
|
||||
}
|
||||
const size_t driver = driverNumbers[drive];
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
if (driver >= FIRST_EXTERNAL_DRIVE)
|
||||
{
|
||||
ExternalDrivers::SetCurrent(driver - FIRST_EXTERNAL_DRIVE, current);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
unsigned short pot = (unsigned short)((0.256*current*8.0*senseResistor + maxStepperDigipotVoltage/2)/maxStepperDigipotVoltage);
|
||||
unsigned short dac = (unsigned short)((0.256*current*8.0*senseResistor + maxStepperDACVoltage/2)/maxStepperDACVoltage);
|
||||
const size_t driver = driverNumbers[drive];
|
||||
if (driver < 4)
|
||||
{
|
||||
mcpDuet.setNonVolatileWiper(potWipes[driver], pot);
|
||||
|
@ -1416,6 +1468,9 @@ void Platform::UpdateMotorCurrent(size_t drive)
|
|||
mcpExpansion.setVolatileWiper(potWipes[driver], pot);
|
||||
}
|
||||
}
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1437,6 +1492,48 @@ void Platform::SetIdleCurrentFactor(float f)
|
|||
}
|
||||
}
|
||||
|
||||
// Set the microstepping, returning true if successful
|
||||
bool Platform::SetMicrostepping(size_t drive, int microsteps, int mode)
|
||||
{
|
||||
if (drive < DRIVES)
|
||||
{
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
const size_t driver = driverNumbers[drive];
|
||||
if (driver >= FIRST_EXTERNAL_DRIVE)
|
||||
{
|
||||
return ExternalDrivers::SetMicrostepping(driver - FIRST_EXTERNAL_DRIVE, microsteps, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
// On-board drivers only support x16 microstepping.
|
||||
// We ignore the interpolation on/off parameter so that e.g. M350 I1 E16:128 won't give an error if E1 supports interpolation but E0 doesn't.
|
||||
return microsteps == 16;
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int Platform::GetMicrostepping(size_t drive, bool& interpolation) const
|
||||
{
|
||||
#ifdef EXTERNAL_DRIVERS
|
||||
if (drive < DRIVES)
|
||||
{
|
||||
const size_t driver = driverNumbers[drive];
|
||||
if (driver >= FIRST_EXTERNAL_DRIVE)
|
||||
{
|
||||
return ExternalDrivers::GetMicrostepping(driver - FIRST_EXTERNAL_DRIVE, interpolation);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// On-board drivers only support x16 microstepping without interpolation
|
||||
interpolation = false;
|
||||
return 16;
|
||||
}
|
||||
|
||||
// Set the physical drive (i.e. axis or extruder) number used by this driver
|
||||
void Platform::SetPhysicalDrive(size_t driverNumber, int8_t physicalDrive)
|
||||
{
|
||||
|
@ -1513,7 +1610,7 @@ void Platform::InitFans()
|
|||
for (size_t i = 0; i < NUM_FANS; ++i)
|
||||
{
|
||||
// The cooling fan 0 output pin gets inverted if HEAT_ON == 0 on a Duet 0.4, 0.6 or 0.7
|
||||
fans[i].Init(COOLING_FAN_PINS[i], !HEAT_ON && board != BoardType::Duet_085);
|
||||
fans[i].Init(COOLING_FAN_PINS[i], !HEAT_ON && (board == BoardType::Duet_06 || board == BoardType::Duet_07));
|
||||
}
|
||||
|
||||
if (NUM_FANS > 1)
|
||||
|
@ -1711,6 +1808,7 @@ void Platform::Message(MessageType type, const char *message)
|
|||
break;
|
||||
|
||||
case AUX2_MESSAGE:
|
||||
#ifdef SERIAL_AUX2_DEVICE
|
||||
// Message that is to be sent to the second auxiliary device (blocking)
|
||||
if (!aux2Output->IsEmpty())
|
||||
{
|
||||
|
@ -1723,6 +1821,7 @@ void Platform::Message(MessageType type, const char *message)
|
|||
SERIAL_AUX2_DEVICE.write(message);
|
||||
SERIAL_AUX2_DEVICE.flush();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case DISPLAY_MESSAGE:
|
||||
|
@ -1965,10 +2064,12 @@ void Platform::ResetChannel(size_t chan)
|
|||
SERIAL_AUX_DEVICE.end();
|
||||
SERIAL_AUX_DEVICE.begin(baudRates[1]);
|
||||
break;
|
||||
#ifdef SERIAL_AUX2_DEVICE
|
||||
case 2:
|
||||
SERIAL_AUX2_DEVICE.end();
|
||||
SERIAL_AUX2_DEVICE.begin(baudRates[2]);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1981,7 +2082,7 @@ void Platform::SetBoardType(BoardType bt)
|
|||
// Determine whether this is a Duet 0.6 or a Duet 0.8.5 board.
|
||||
// If it is a 0.85 board then DAC0 (AKA digital pin 67) is connected to ground via a diode and a 2.15K resistor.
|
||||
// So we enable the pullup (value 150K-150K) on pin 67 and read it, expecting a LOW on a 0.8.5 board and a HIGH on a 0.6 board.
|
||||
// This may fail if anyone connects a load to the DAC0 pin on and Dur=et 0.6, hence we implement board selection in M115 as well.
|
||||
// This may fail if anyone connects a load to the DAC0 pin on and Duet 0.6, hence we implement board selection in M115 as well.
|
||||
pinModeNonDue(Dac0DigitalPin, INPUT_PULLUP);
|
||||
board = (digitalReadNonDue(Dac0DigitalPin)) ? BoardType::Duet_06 : BoardType::Duet_085;
|
||||
pinModeNonDue(Dac0DigitalPin, INPUT); // turn pullup off
|
||||
|
@ -2088,7 +2189,11 @@ bool Platform::GCodeAvailable(const SerialSource source) const
|
|||
return SERIAL_AUX_DEVICE.available() > 0;
|
||||
|
||||
case SerialSource::AUX2:
|
||||
#ifdef SERIAL_AUX2_DEVICE
|
||||
return SERIAL_AUX2_DEVICE.available() > 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2105,7 +2210,11 @@ char Platform::ReadFromSource(const SerialSource source)
|
|||
return static_cast<char>(SERIAL_AUX_DEVICE.read());
|
||||
|
||||
case SerialSource::AUX2:
|
||||
#ifdef SERIAL_AUX2_DEVICE
|
||||
return static_cast<char>(SERIAL_AUX2_DEVICE.read());
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2180,7 +2289,7 @@ void Platform::Tick()
|
|||
// averaging. As such, the temperature reading is taken directly by Platform::GetTemperature() and
|
||||
// periodically called by PID::Spin() where temperature fault handling is taken care of. However, we
|
||||
// must guard against overly long delays between successive calls of PID::Spin().
|
||||
|
||||
// Do not call Time() here, it isn't safe. We use millis() instead.
|
||||
StartAdcConversion(zProbeAdcChannel);
|
||||
if ((millis() - reprap.GetHeat()->GetLastSampleTime(currentHeater)) > maxPidSpinDelay)
|
||||
{
|
||||
|
|
19
Platform.h
19
Platform.h
|
@ -175,12 +175,6 @@ const uint8_t MAC_ADDRESS[6] = { 0xBE, 0xEF, 0xDE, 0xAD, 0xFE, 0xED };
|
|||
|
||||
/****************************************************************************************************/
|
||||
|
||||
// Miscellaneous...
|
||||
|
||||
const size_t messageStringLength = 256; // max length of a message chunk sent via Message or AppendMessage
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
enum class BoardType : uint8_t
|
||||
{
|
||||
Auto = 0,
|
||||
|
@ -423,7 +417,7 @@ public:
|
|||
enum class DriveStatus : uint8_t { disabled, idle, enabled };
|
||||
|
||||
// Error results generated by GetTemperature()
|
||||
enum class TempError : uint8_t { errOk, errShort, errShortVcc, errShortGnd, errOpen, errTimeout, errIO };
|
||||
enum class TempError : uint8_t { errOk, errShort, errShortVcc, errShortGnd, errOpen, errTooHigh, errTimeout, errIO };
|
||||
|
||||
Platform();
|
||||
|
||||
|
@ -515,6 +509,8 @@ public:
|
|||
float MotorCurrent(size_t drive) const;
|
||||
void SetIdleCurrentFactor(float f);
|
||||
float GetIdleCurrentFactor() const { return idleCurrentFactor; }
|
||||
bool SetMicrostepping(size_t drive, int microsteps, int mode);
|
||||
unsigned int GetMicrostepping(size_t drive, bool& interpolation) const;
|
||||
float DriveStepsPerUnit(size_t drive) const;
|
||||
const float *GetDriveStepsPerUnit() const { return driveStepsPerUnit; }
|
||||
void SetDriveStepsPerUnit(size_t drive, float value);
|
||||
|
@ -574,7 +570,8 @@ public:
|
|||
void SetThermistorNumber(size_t heater, size_t thermistor);
|
||||
int GetThermistorNumber(size_t heater) const;
|
||||
bool DoThermistorAdc(uint8_t heater) const;
|
||||
MAX31855 Max31855Devices[MAX31855_DEVICES];
|
||||
void SetTemperatureLimit(float t);
|
||||
float GetTemperatureLimit() const { return temperatureLimit; }
|
||||
static const char* TempErrorStr(TempError err);
|
||||
static bool TempErrorPermanent(TempError err);
|
||||
|
||||
|
@ -638,7 +635,6 @@ private:
|
|||
uint16_t magic;
|
||||
uint16_t resetReason; // this records why we did a software reset, for diagnostic purposes
|
||||
size_t neverUsedRam; // the amount of never used RAM at the last abnormal software reset
|
||||
char lastMessage[256]; // the last known message before a software reset occurred
|
||||
};
|
||||
|
||||
struct FlashData
|
||||
|
@ -759,11 +755,13 @@ private:
|
|||
|
||||
Pin tempSensePins[HEATERS];
|
||||
Pin heatOnPins[HEATERS];
|
||||
MAX31855 Max31855Devices[MAX31855_DEVICES];
|
||||
Pin max31855CsPins[MAX31855_DEVICES];
|
||||
float heatSampleTime;
|
||||
float standbyTemperatures[HEATERS];
|
||||
float activeTemperatures[HEATERS];
|
||||
float timeToHot;
|
||||
float temperatureLimit;
|
||||
|
||||
// Fans
|
||||
|
||||
|
@ -836,9 +834,6 @@ private:
|
|||
static uint16_t GetAdcReading(adc_channel_num_t chan);
|
||||
static void StartAdcConversion(adc_channel_num_t chan);
|
||||
|
||||
char messageStringBuffer[messageStringLength];
|
||||
StringRef messageString;
|
||||
|
||||
// Hotend configuration
|
||||
float filamentWidth;
|
||||
float nozzleDiameter;
|
||||
|
|
|
@ -723,9 +723,11 @@ float PrintMonitor::EstimateTimeLeft(PrintEstimationMethod method) const
|
|||
const float fractionPrinted = gCodes->FractionOfFilePrinted();
|
||||
if (numLayerSamples < 2 || !printingFileParsed || printingFileInfo.objectHeight == 0.0)
|
||||
{
|
||||
return (fractionPrinted < 0.01)
|
||||
? 0.0
|
||||
: realPrintDuration * (1.0 / fractionPrinted) - realPrintDuration;
|
||||
if (fractionPrinted < 0.01)
|
||||
{
|
||||
break;
|
||||
}
|
||||
return realPrintDuration * (1.0 / fractionPrinted) - realPrintDuration;
|
||||
}
|
||||
|
||||
// Work out how much progress we made in the layers we have data for, and how long it took.
|
||||
|
@ -736,10 +738,12 @@ float PrintMonitor::EstimateTimeLeft(PrintEstimationMethod method) const
|
|||
duration += layerDurations[layer];
|
||||
}
|
||||
const float fractionPrintedInLayers = fileProgressPerLayer[numLayerSamples - 1] - fileProgressPerLayer[0];
|
||||
return (fractionPrintedInLayers < 0.01)
|
||||
? 0.0
|
||||
: duration * (1.0 - fractionPrinted)/fractionPrintedInLayers;
|
||||
if (fractionPrintedInLayers >= 0.01)
|
||||
{
|
||||
return duration * (1.0 - fractionPrinted)/fractionPrintedInLayers;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case filamentBased:
|
||||
{
|
||||
|
@ -750,7 +754,7 @@ float PrintMonitor::EstimateTimeLeft(PrintEstimationMethod method) const
|
|||
#endif
|
||||
)
|
||||
{
|
||||
return 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Sum up the filament usage and the filament needed
|
||||
|
@ -770,22 +774,35 @@ float PrintMonitor::EstimateTimeLeft(PrintEstimationMethod method) const
|
|||
}
|
||||
if (extrRawTotal >= totalFilamentNeeded)
|
||||
{
|
||||
return 0.0; // Avoid division by zero, else the web interface will report AJAX errors
|
||||
break; // Avoid division by zero, else the web interface will report AJAX errors
|
||||
}
|
||||
|
||||
float filamentRate;
|
||||
if (numLayerSamples)
|
||||
if (numLayerSamples != 0)
|
||||
{
|
||||
filamentRate = 0.0;
|
||||
size_t numSamples = 0;
|
||||
for (size_t i = 0; i < numLayerSamples; i++)
|
||||
{
|
||||
if (layerDurations[i] > 0.0)
|
||||
{
|
||||
filamentRate += filamentUsagePerLayer[i] / layerDurations[i];
|
||||
++numSamples;
|
||||
}
|
||||
filamentRate /= numLayerSamples;
|
||||
}
|
||||
if (numSamples == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
filamentRate /= numSamples;
|
||||
}
|
||||
else if (firstLayerDuration > 0.0)
|
||||
{
|
||||
filamentRate = firstLayerFilament / firstLayerDuration;
|
||||
}
|
||||
else
|
||||
{
|
||||
filamentRate = firstLayerFilament / firstLayerDuration;
|
||||
break;
|
||||
}
|
||||
|
||||
return (totalFilamentNeeded - extrRawTotal) / filamentRate;
|
||||
|
|
BIN
Release/RepRapFirmware-1.09sbeta4-dc42.bin
Normal file
BIN
Release/RepRapFirmware-1.09sbeta4-dc42.bin
Normal file
Binary file not shown.
27
Reprap.cpp
27
Reprap.cpp
|
@ -163,7 +163,7 @@ void RepRap::Spin()
|
|||
{
|
||||
if (t->DisplayColdExtrudeWarning() && ToolWarningsAllowed())
|
||||
{
|
||||
platform->MessageF(GENERIC_MESSAGE, "Warning: Tool %d was not driven because its heater temperatures were not high enough\n", t->myNumber);
|
||||
platform->MessageF(GENERIC_MESSAGE, "Warning: Tool %d was not driven because its temperatures were not high enough or it has a heater fault\n", t->myNumber);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1341,19 +1341,28 @@ void RepRap::SetName(const char* nm)
|
|||
network->SetHostname(myName);
|
||||
}
|
||||
|
||||
// Given that we want to extrude/etract the specified extruder drives, check if they are allowed.
|
||||
// Given that we want to extrude/retract the specified extruder drives, check if they are allowed.
|
||||
// For each disallowed one, log an error to report later and return a bit in the bitmap.
|
||||
// This may be called by an ISR!
|
||||
unsigned int RepRap::GetProhibitedExtruderMovements(unsigned int extrusions, unsigned int retractions)
|
||||
{
|
||||
unsigned int result = 0;
|
||||
Tool *tool = toolList;
|
||||
while (tool != nullptr)
|
||||
if (GetHeat()->ColdExtrude())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Tool *tool = currentTool;
|
||||
if (tool == nullptr)
|
||||
{
|
||||
// This should not happen, but if on tool is selected then don't allow any extruder movement
|
||||
return extrusions | retractions;
|
||||
}
|
||||
|
||||
unsigned int result = 0;
|
||||
for (size_t driveNum = 0; driveNum < tool->DriveCount(); driveNum++)
|
||||
{
|
||||
const int extruderDrive = tool->Drive(driveNum);
|
||||
unsigned int mask = 1 << extruderDrive;
|
||||
const unsigned int extruderDrive = (unsigned int)(tool->Drive(driveNum));
|
||||
const unsigned int mask = 1 << extruderDrive;
|
||||
if (extrusions & mask)
|
||||
{
|
||||
if (!tool->ToolCanDrive(true))
|
||||
|
@ -1361,7 +1370,7 @@ unsigned int RepRap::GetProhibitedExtruderMovements(unsigned int extrusions, uns
|
|||
result |= mask;
|
||||
}
|
||||
}
|
||||
else if (retractions & (1 << extruderDrive))
|
||||
else if (retractions & mask)
|
||||
{
|
||||
if (!tool->ToolCanDrive(false))
|
||||
{
|
||||
|
@ -1370,8 +1379,6 @@ unsigned int RepRap::GetProhibitedExtruderMovements(unsigned int extrusions, uns
|
|||
}
|
||||
}
|
||||
|
||||
tool = tool->Next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
23
Tool.cpp
23
Tool.cpp
|
@ -31,13 +31,15 @@ Tool * Tool::freelist = nullptr;
|
|||
{
|
||||
if (dCount > DRIVES - AXES)
|
||||
{
|
||||
reprap.GetPlatform()->Message(GENERIC_MESSAGE, "Error: Tool creation: attempt to use more drives than there are in the RepRap");
|
||||
reprap.GetPlatform()->Message(GENERIC_MESSAGE,
|
||||
"Error: Tool creation: attempt to use more drives than there are in the RepRap");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (hCount > HEATERS)
|
||||
{
|
||||
reprap.GetPlatform()->Message(GENERIC_MESSAGE, "Error: Tool creation: attempt to use more heaters than there are in the RepRap");
|
||||
reprap.GetPlatform()->Message(GENERIC_MESSAGE,
|
||||
"Error: Tool creation: attempt to use more heaters than there are in the RepRap");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -120,8 +122,7 @@ void Tool::Print(StringRef& reply)
|
|||
{
|
||||
comma = ';';
|
||||
}
|
||||
reply.catf("%d (%.1f/%.1f)%c", heaters[heater],
|
||||
activeTemperatures[heater], standbyTemperatures[heater], comma);
|
||||
reply.catf("%d (%.1f/%.1f)%c", heaters[heater], activeTemperatures[heater], standbyTemperatures[heater], comma);
|
||||
}
|
||||
|
||||
reply.catf(" status: %s", active ? "selected" : "standby");
|
||||
|
@ -131,7 +132,8 @@ float Tool::MaxFeedrate() const
|
|||
{
|
||||
if (driveCount <= 0)
|
||||
{
|
||||
reprap.GetPlatform()->Message(GENERIC_MESSAGE, "Error: Attempt to get maximum feedrate for a tool with no drives.\n");
|
||||
reprap.GetPlatform()->Message(GENERIC_MESSAGE,
|
||||
"Error: Attempt to get maximum feedrate for a tool with no drives.\n");
|
||||
return 1.0;
|
||||
}
|
||||
float result = 0.0;
|
||||
|
@ -269,12 +271,12 @@ void Tool::SetVariables(const float* standby, const float* active)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (active[heater] < BAD_HIGH_TEMPERATURE)
|
||||
if (active[heater] < reprap.GetPlatform()->GetTemperatureLimit())
|
||||
{
|
||||
activeTemperatures[heater] = active[heater];
|
||||
reprap.GetHeat()->SetActiveTemperature(heaters[heater], activeTemperatures[heater]);
|
||||
}
|
||||
if (standby[heater] < BAD_HIGH_TEMPERATURE)
|
||||
if (standby[heater] < reprap.GetPlatform()->GetTemperatureLimit())
|
||||
{
|
||||
standbyTemperatures[heater] = standby[heater];
|
||||
reprap.GetHeat()->SetStandbyTemperature(heaters[heater], standbyTemperatures[heater]);
|
||||
|
@ -295,11 +297,10 @@ void Tool::GetVariables(float* standby, float* active) const
|
|||
// May be called from ISR
|
||||
bool Tool::ToolCanDrive(bool extrude)
|
||||
{
|
||||
if (heaterFault)
|
||||
return false;
|
||||
|
||||
if (reprap.GetHeat()->ColdExtrude() || AllHeatersAtHighTemperature(extrude))
|
||||
if (!heaterFault && AllHeatersAtHighTemperature(extrude))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
displayColdExtrudeWarning = true;
|
||||
return false;
|
||||
|
|
|
@ -96,8 +96,8 @@
|
|||
|
||||
//***************************************************************************************************
|
||||
|
||||
static const char* overflowResponse = "overflow";
|
||||
static const char* badEscapeResponse = "bad escape";
|
||||
const char* overflowResponse = "overflow";
|
||||
const char* badEscapeResponse = "bad escape";
|
||||
|
||||
|
||||
//********************************************************************************************
|
||||
|
|
Reference in a new issue