diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Configuration.h | 4 | ||||
-rw-r--r-- | src/Duet/Webserver.cpp | 4 | ||||
-rw-r--r-- | src/DuetNG/DueXn.cpp | 35 | ||||
-rw-r--r-- | src/DuetNG/Pins_DuetNG.h | 1 | ||||
-rw-r--r-- | src/DuetNG/TMC2660.cpp | 15 | ||||
-rw-r--r-- | src/DuetNG/TMC2660.h | 9 | ||||
-rw-r--r-- | src/DuetNG/Webserver.cpp | 2 | ||||
-rw-r--r-- | src/Fan.cpp | 51 | ||||
-rw-r--r-- | src/Fan.h | 2 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 13 | ||||
-rw-r--r-- | src/Libraries/Fatfs/fattime_rtc.c | 4 | ||||
-rw-r--r-- | src/Platform.cpp | 47 | ||||
-rw-r--r-- | src/Platform.h | 26 | ||||
-rw-r--r-- | src/PrintMonitor.cpp | 14 | ||||
-rw-r--r-- | src/PrintMonitor.h | 1 | ||||
-rw-r--r-- | src/Reprap.cpp | 18 | ||||
-rw-r--r-- | src/Storage/MassStorage.cpp | 55 | ||||
-rw-r--r-- | src/Storage/MassStorage.h | 3 |
18 files changed, 209 insertions, 95 deletions
diff --git a/src/Configuration.h b/src/Configuration.h index 9ebe291e..26982b4f 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -26,11 +26,11 @@ Licence: GPL // Firmware name is now defined in the Pins file #ifndef VERSION -# define VERSION "1.16rc1" +# define VERSION "1.16rc2" #endif #ifndef DATE -# define DATE "2016-11-03" +# define DATE "2016-11-05" #endif #define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman" diff --git a/src/Duet/Webserver.cpp b/src/Duet/Webserver.cpp index 15c21edc..8db33a5e 100644 --- a/src/Duet/Webserver.cpp +++ b/src/Duet/Webserver.cpp @@ -964,6 +964,7 @@ void Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuff if (numQualKeys > 1 && StringEquals(qualifiers[1].key, "time") && !platform->IsDateTimeSet()) { struct tm timeInfo; + memset(&timeInfo, 0, sizeof(timeInfo)); if (strptime(qualifiers[1].value, "%Y-%m-%dT%H:%M:%S", &timeInfo) != nullptr) { time_t newTime = mktime(&timeInfo); @@ -1589,6 +1590,7 @@ bool Webserver::HttpInterpreter::ProcessMessage() if (numQualKeys > 1 && StringEquals(qualifiers[1].key, "time")) { struct tm timeInfo; + memset(&timeInfo, 0, sizeof(timeInfo)); if (strptime(qualifiers[1].value, "%Y-%m-%dT%H:%M:%S", &timeInfo) != nullptr) { fileLastModified = mktime(&timeInfo); @@ -2333,7 +2335,7 @@ void Webserver::FtpInterpreter::ProcessLine() // Example for a typical UNIX-like file list: // "drwxr-xr-x 2 ftp ftp 0 Apr 11 2013 bin\r\n" const char dirChar = (fileInfo.isDirectory) ? 'd' : '-'; - struct tm *timeInfo = localtime(&fileInfo.lastModified); + const struct tm * const timeInfo = gmtime(&fileInfo.lastModified); dataTransaction->Printf("%crw-rw-rw- 1 ftp ftp %13lu %s %02d %04d %s\r\n", dirChar, fileInfo.size, platform->GetMassStorage()->GetMonthName(timeInfo->tm_mon + 1), timeInfo->tm_mday, timeInfo->tm_year + 1900, fileInfo.fileName); diff --git a/src/DuetNG/DueXn.cpp b/src/DuetNG/DueXn.cpp index a0f1c11b..ac6f0785 100644 --- a/src/DuetNG/DueXn.cpp +++ b/src/DuetNG/DueXn.cpp @@ -7,12 +7,14 @@ #include "DueXn.h" #include "SX1509.h" +#include "Platform.h" namespace DuetExpansion { static SX1509 expander; static uint16_t inputMask; static ExpansionBoardType boardType = ExpansionBoardType::none; + static uint16_t inputBits; const uint8_t DueXnAddress = 0x3E; // address of the SX1509B on the DueX0/DueX2/DueX5 @@ -33,7 +35,8 @@ namespace DuetExpansion const unsigned int E4StopBit = 2; const unsigned int E5StopBit = 1; const unsigned int E6StopBit = 13; - const uint16_t AllStopBits = (1u << E2StopBit) | (1u << E3StopBit) | (1u << E4StopBit) | (1u << E5StopBit) | (1u << E6StopBit); + const uint16_t AllStopBitsX2 = (1u << E2StopBit) | (1u << E3StopBit); + const uint16_t AllStopBitsX5 = AllStopBitsX2 | (1u << E4StopBit) | (1u << E5StopBit) | (1u << E6StopBit); const unsigned int Gpio1Bit = 11; const unsigned int Gpio2Bit = 10; @@ -64,16 +67,21 @@ namespace DuetExpansion if (boardType != ExpansionBoardType::none) { + pinMode(DueX_INT, INPUT_PULLUP); + pinMode(DueX_SG, INPUT_PULLUP); + expander.pinModeMultiple(AllFanBits, OUTPUT_PWM); // Initialise the PWM pins - expander.pinModeMultiple(AllStopBits, INPUT); // Initialise the endstop inputs (no pullups because 5V-tolerant) + const uint16_t stopBits = (boardType == ExpansionBoardType::DueX5) ? AllStopBitsX5 : AllStopBitsX2; // I am assuming that the X0 has 2 endstop inputs + expander.pinModeMultiple(stopBits, INPUT); // Initialise the endstop inputs (no pullups because 5V-tolerant) expander.pinModeMultiple(AllGpioBits, INPUT); // Initialise the GPIO pins as inputs // Set up the interrupt on any input change - inputMask = AllStopBits | AllGpioBits; + inputMask = stopBits | AllGpioBits; expander.enableInterruptMultiple(inputMask, CHANGE); // Clear any initial interrupts - expander.interruptSource(true); + (void)expander.interruptSource(true); + inputBits = expander.digitalReadAll(); } return boardType; @@ -114,6 +122,10 @@ namespace DuetExpansion case OUTPUT_PWM: mode = OUTPUT_PWM_OPEN_DRAIN; break; + case INPUT_PULLUP: + case INPUT_PULLDOWN: + mode = INPUT; // we are using 5rV-tolerant input with external pullup resistors, so don't enable internal pullup/pulldown resistors + break; default: break; } @@ -127,9 +139,18 @@ namespace DuetExpansion // We need to use the SX15089 interrupt to read the data register using interrupts, and just retrieve that value here. bool DigitalRead(Pin pin) { - return (boardType != ExpansionBoardType::none) - ? expander.digitalRead(pin) - : false; + if (boardType == ExpansionBoardType::none || pin >= 16) + { + return false; + } + + if (!digitalRead(DueX_INT)) + { + // Interrupt is active, so input data may have changed + inputBits = expander.digitalReadAll(); + } + + return (inputBits & (1 << pin)) != 0; } // Write a pin diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h index f312eb2c..841aeb47 100644 --- a/src/DuetNG/Pins_DuetNG.h +++ b/src/DuetNG/Pins_DuetNG.h @@ -54,7 +54,6 @@ const Pin DueX_INT = 17; // DueX interrupt pin = PA17 (was E6_STOP) // Endstops // RepRapFirmware only has a single endstop per axis. // Gcode defines if it is a max ("high end") or min ("low end") endstop and sets if it is active HIGH or LOW. -//const Pin END_STOP_PINS[DRIVES] = { 46, 02, 93, 74, 48, 96, 97, 98, 99, 17 }; const Pin END_STOP_PINS[DRIVES] = { 46, 02, 93, 74, 48, 200, 203, 202, 201, 213 }; // HEATERS diff --git a/src/DuetNG/TMC2660.cpp b/src/DuetNG/TMC2660.cpp index 84c69e9b..fbf96771 100644 --- a/src/DuetNG/TMC2660.cpp +++ b/src/DuetNG/TMC2660.cpp @@ -6,6 +6,7 @@ */ #include "RepRapFirmware.h" +#include "TMC2660.h" #if !defined(PROTOTYPE_1) @@ -25,7 +26,8 @@ const Pin DriversSclkPin = 23; // PA23 #define TMC_CLOCK_CHAN 1 #define TMC_CLOCK_ID ID_TC1 // this is channel 1 on TC0 -const uint32_t DriversSpiClockFrequency = 1000000; // 1MHz SPI clock for now +const uint32_t DriversSpiClockFrequency = 4000000; // 4MHz SPI clock +const int StallGuardThreshold = 1; // Range is -64..63. Zero seems to be too sensitive. Higher values reduce sensitivity of stall detection. // TMC2660 registers const uint32_t TMC_REG_DRVCTRL = 0; @@ -100,15 +102,6 @@ const uint32_t TMC_SMARTEN_SEDN_1 = 3 << 13; const uint32_t TMC_SMARTEN_SEIMIN_HALF = 0 << 15; const uint32_t TMC_SMARTEN_SEIMIN_QTR = 1 << 15; -// Read response. The microstep counter can also be read, but we don't include that here. -const uint32_t TMC_RR_SG = 1 << 0; // stall detected -const uint32_t TMC_RR_OT = 1 << 1; // over temperature shutdown -const uint32_t TMC_RR_OTPW = 1 << 2; // over temperature warning -const uint32_t TMC_RR_S2G = 3 << 3; // short to ground counter (2 bits) -const uint32_t TMC_RR_OLA = 1 << 5; // open load A -const uint32_t TMC_RR_OLB = 1 << 6; // open load B -const uint32_t TMC_RR_STST = 1 << 7; // standstill detected - const unsigned int NumWriteRegisters = 5; // Chopper control register defaults @@ -125,7 +118,7 @@ const uint32_t defaultChopConfToff = 4; // default value for TOFF when drive is // StallGuard configuration register const uint32_t defaultSgscConfReg = TMC_REG_SGCSCONF - | 0; // minimum current until user has set it + | TMC_SGCSCONF_SGT(StallGuardThreshold); // Driver configuration register const uint32_t defaultDrvConfReg = diff --git a/src/DuetNG/TMC2660.h b/src/DuetNG/TMC2660.h index 33510340..8fcb267b 100644 --- a/src/DuetNG/TMC2660.h +++ b/src/DuetNG/TMC2660.h @@ -10,6 +10,15 @@ #include "Pins.h" +// TMC2660 Read response. The microstep counter can also be read, but we don't include that here. +const uint32_t TMC_RR_SG = 1 << 0; // stall detected +const uint32_t TMC_RR_OT = 1 << 1; // over temperature shutdown +const uint32_t TMC_RR_OTPW = 1 << 2; // over temperature warning +const uint32_t TMC_RR_S2G = 3 << 3; // short to ground counter (2 bits) +const uint32_t TMC_RR_OLA = 1 << 5; // open load A +const uint32_t TMC_RR_OLB = 1 << 6; // open load B +const uint32_t TMC_RR_STST = 1 << 7; // standstill detected + namespace TMC2660 { void Init(const Pin[DRIVES], size_t numTmcDrivers) diff --git a/src/DuetNG/Webserver.cpp b/src/DuetNG/Webserver.cpp index 0b949c1f..5f67e9f2 100644 --- a/src/DuetNG/Webserver.cpp +++ b/src/DuetNG/Webserver.cpp @@ -544,6 +544,7 @@ bool Webserver::ProcessFirstFragment(HttpSession& session, const char* command, if (timeVal != nullptr && !platform->IsDateTimeSet()) { struct tm timeInfo; + memset(&timeInfo, 0, sizeof(timeInfo)); if (strptime(timeVal, "%Y-%m-%dT%H:%M:%S", &timeInfo) != nullptr) { time_t newTime = mktime(&timeInfo); @@ -623,6 +624,7 @@ bool Webserver::ProcessFirstFragment(HttpSession& session, const char* command, // Try to obtain the last modified time time_t fileLastModified = 0; struct tm timeInfo; + memset(&timeInfo, 0, sizeof(timeInfo)); if (timeVal != nullptr && strptime(timeVal, "%Y-%m-%dT%H:%M:%S", &timeInfo) != nullptr) { fileLastModified = mktime(&timeInfo); diff --git a/src/Fan.cpp b/src/Fan.cpp index b4358238..89e2f972 100644 --- a/src/Fan.cpp +++ b/src/Fan.cpp @@ -12,13 +12,13 @@ void Fan::Init(Pin p_pin, bool hwInverted) val = 0.0; minVal = 0.1; // 10% minimum fan speed blipTime = 100; // 100ms fan blip - blipStartTime = 0; freq = DefaultFanPwmFreq; pin = p_pin; hardwareInverted = hwInverted; - inverted = false; + inverted = blipping = false; heatersMonitored = 0; triggerTemperature = HOT_END_FAN_TEMPERATURE; + lastPwm = -1.0; Refresh(); } @@ -28,10 +28,11 @@ void Fan::SetValue(float speed) { speed /= 255.0; } - const float newVal = (speed > 0.0) ? constrain<float>(speed, minVal, 1.0) : 0.0; - if (val == 0.0 && newVal < 1.0 && blipTime != 0) + const float newVal = constrain<float>(speed, 0.0, 1.0); + if (val == 0.0 && newVal > 0.0 && newVal < 1.0 && blipTime != 0) { // Starting the fan from standstill, so blip the fan + blipping = true; blipStartTime = millis(); } val = newVal; @@ -68,7 +69,17 @@ void Fan::SetHardwarePwm(float pwmVal) { invert = !invert; } - Platform::WriteAnalog(pin, (invert) ? (1.0 - pwmVal) : pwmVal, freq); + if (invert) + { + pwmVal = 1.0 - pwmVal; + } + + // Only set the PWM if it has changed, to avoid a lot of I2C traffic when we have a DueX5 connected + if (pwmVal != lastPwm) + { + lastPwm = pwmVal; + Platform::WriteAnalog(pin, pwmVal, freq); + } } } @@ -91,23 +102,31 @@ void Fan::Refresh() : (reprap.GetPlatform()->AnyHeaterHot(heatersMonitored, triggerTemperature)) ? max<float>(0.5, val) // make sure that thermostatic fans always run at 50% speed or more : 0.0; - if (reqVal > 0.0 && millis() - blipStartTime < blipTime) - { - SetHardwarePwm(1.0); - } - else if (reqVal > 0.0 && reqVal < minVal) + if (reqVal > 0.0) { - SetHardwarePwm(minVal); - } - else - { - SetHardwarePwm(reqVal); + if (reqVal < minVal) + { + reqVal = minVal; + } + + if (blipping) + { + if (millis() - blipStartTime < blipTime) + { + reqVal = 1.0; + } + else + { + blipping = false; + } + } } + SetHardwarePwm(reqVal); } void Fan::Check() { - if (heatersMonitored != 0 || blipTime != 0) + if (heatersMonitored != 0 || blipping) { Refresh(); } @@ -16,6 +16,7 @@ private: float val; float minVal; float triggerTemperature; + float lastPwm; uint32_t blipTime; // in milliseconds uint32_t blipStartTime; uint16_t freq; @@ -23,6 +24,7 @@ private: Pin pin; bool inverted; bool hardwareInverted; + bool blipping; void Refresh(); void SetHardwarePwm(float pwmVal); diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 0b0a2a0f..c65b0d01 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -3237,7 +3237,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) const int logicalPin = gb->GetIValue(); Pin pin; bool invert; - if (platform->GetFirmwarePin(logicalPin, PinAccess::write, pin, invert)) + if (platform->GetFirmwarePin(logicalPin, PinAccess::pwm, pin, invert)) { if (gb->Seen('S')) { @@ -4313,7 +4313,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) } else if (!model.IsEnabled()) { - reply.printf("Heater %u is disabled"); + reply.printf("Heater %u is disabled", heater); } else { @@ -5071,10 +5071,9 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) { bool seen = false; bool logicLevel = (gb->Seen('S')) ? (gb->GetIValue() != 0) : true; - for (size_t axis = 0; axis <= numAxes; ++axis) + for (size_t axis = 0; axis < numAxes; ++axis) { - const char letter = (axis == numAxes) ? extrudeLetter : axisLetters[axis]; - if (gb->Seen(letter)) + if (gb->Seen(axisLetters[axis])) { int ival = gb->GetIValue(); if (ival >= 0 && ival <= 3) @@ -5096,8 +5095,6 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) (config == EndStopType::highEndStop) ? "high end" : (config == EndStopType::lowEndStop) ? "low end" : "none", (config == EndStopType::noEndStop) ? "" : (logic) ? "high" : "low"); } - platform->GetEndStopConfiguration(E0_AXIS, config, logic); - reply.catf(" E (active %s)", (logic) ? "high" : "low"); } } break; @@ -5634,7 +5631,7 @@ bool GCodes::HandleMcode(GCodeBuffer* gb, StringRef& reply) case 905: // Set current RTC date and time { const time_t now = platform->GetDateTime(); - struct tm * const timeInfo = localtime(&now); + struct tm * const timeInfo = gmtime(&now); bool seen = false; if (gb->Seen('P')) diff --git a/src/Libraries/Fatfs/fattime_rtc.c b/src/Libraries/Fatfs/fattime_rtc.c index fc46396f..392e6373 100644 --- a/src/Libraries/Fatfs/fattime_rtc.c +++ b/src/Libraries/Fatfs/fattime_rtc.c @@ -60,7 +60,7 @@ uint32_t get_fattime(void); * * bit10:5 Minute (0..59) * - * bit4:0 Second (0..59) + * bit4:0 Second/2 (0..29) * * \return Current time. */ @@ -84,7 +84,7 @@ uint32_t get_fattime(void) | (ul_day << 16) | (ul_hour << 11) | (ul_minute << 5) - | (ul_second << 0); + | (ul_second >> 1); return ul_time; } diff --git a/src/Platform.cpp b/src/Platform.cpp index 5a9106ce..bbbf0573 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -339,8 +339,8 @@ void Platform::Init() // Test for presence of a DueX2 or DueX5 expansion board and work out how many TMC2660 drivers we have // The SX1509B has an independent power on reset, so give it some time delay(200); - ExpansionBoardType et = DuetExpansion::Init(); - switch (et) + expansionBoard = DuetExpansion::Init(); + switch (expansionBoard) { case ExpansionBoardType::DueX2: numTMC2660Drivers = 7; @@ -578,7 +578,7 @@ int Platform::ZProbe() const } } - return (GetZProbeParameters().invertReading) ? 1023 - zProbeVal : zProbeVal; + return (GetZProbeParameters().invertReading) ? 1000 - zProbeVal : zProbeVal; } // Return the Z probe secondary values. @@ -1439,11 +1439,34 @@ void Platform::Diagnostics(MessageType mtype) AdcReadingToPowerVoltage(lowestVin), AdcReadingToPowerVoltage(currentVin), AdcReadingToPowerVoltage(highestVin), numUnderVoltageEvents, numOverVoltageEvents); lowestVin = highestVin = currentVin; + + // Show the motor stall status + if (expansionBoard == ExpansionBoardType::DueX2 || expansionBoard == ExpansionBoardType::DueX5) + { + const bool stalled = digitalRead(DueX_SG); + MessageF(mtype, "Expansion motor(s) stall indication: %s\n", (stalled) ? "yes" : "no"); + } + + for (size_t drive = 0; drive < numTMC2660Drivers; ++drive) + { + const uint32_t stat = TMC2660::GetStatus(drive); + MessageF(mtype, "Driver %d:%s%s%s%s%s%s\n", drive, + (stat & TMC_RR_SG) ? " stalled" : "", + (stat & TMC_RR_OT) ? " temperature-shutdown!" + : (stat & TMC_RR_OTPW) ? " temperature-warning" : "", + (stat & TMC_RR_S2G) ? " short-to-ground" : "", + ((stat & TMC_RR_OLA) && !(stat & TMC_RR_STST)) ? " open-load-A" : "", + ((stat & TMC_RR_OLB) && !(stat & TMC_RR_STST)) ? " open-load-B" : "", + (stat & TMC_RR_STST) ? " standstill" + : (stat & (TMC_RR_SG | TMC_RR_OT | TMC_RR_OTPW | TMC_RR_S2G | TMC_RR_OLA | TMC_RR_OLB)) + ? "" : " ok" + ); + } #endif // Show current RTC time const time_t timeNow = RTCDue::GetDateTime(); - const struct tm * const timeInfo = localtime(&timeNow); + const struct tm * const timeInfo = gmtime(&timeNow); MessageF(mtype, "Current date and time: %04u-%02u-%02u %02u:%02u:%02u\n", timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec); @@ -2165,9 +2188,14 @@ void Platform::InitFans() if (NUM_FANS > 1) { +#ifdef DUET_NG // Set fan 1 to be thermostatic by default, monitoring all heaters except the default bed heater fans[1].SetHeatersMonitored(0xFFFF & ~(1 << BED_HEATER)); fans[1].SetValue(1.0); // set it full on +#else + // Fan 1 on the Duet 0.8.5 shares its control pin with heater 6. Set it full on to make sure the heater (if present) is off. + fans[1].SetValue(1.0); // set it full on +#endif } coolingFanRpmPin = COOLING_FAN_RPM_PIN; @@ -2655,9 +2683,8 @@ bool Platform::GetFirmwarePin(int logicalPin, PinAccess access, Pin& firmwarePin firmwarePin = SpecialPinMap[logicalPin - 60]; } #ifdef DUET_NG - else if (logicalPin >= 100 && logicalPin <= 103) // Pins 100-103 are the GPIO pins on the DueX2/X5 + else if (logicalPin >= 100 && logicalPin < 100 + (int)ARRAY_SIZE(DueX5GpioPinMap)) // Pins 100-103 are the GPIO pins on the DueX2/X5 { - static const Pin DueX5GpioPinMap[] = { 211, 210, 209, 208 }; if (access != PinAccess::servo) { firmwarePin = DueX5GpioPinMap[logicalPin - 100]; @@ -2669,9 +2696,13 @@ bool Platform::GetFirmwarePin(int logicalPin, PinAccess access, Pin& firmwarePin { // Check that the pin mode has been defined suitably PinMode desiredMode; - if (access == PinAccess::write || access == PinAccess::servo) + if (access == PinAccess::write) + { + desiredMode = (invert) ? OUTPUT_HIGH : OUTPUT_LOW; + } + else if (access == PinAccess::pwm || access == PinAccess::servo) { - desiredMode = (firmwarePin >= 100) ? OUTPUT_PWM : OUTPUT_LOW; + desiredMode = OUTPUT_PWM; } else { diff --git a/src/Platform.h b/src/Platform.h index bb274044..e80704d2 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -244,6 +244,7 @@ enum class PinAccess : int { read, write, + pwm, servo }; @@ -734,6 +735,9 @@ private: bool autoSaveEnabled; BoardType board; +#ifdef DUET_NG + ExpansionBoardType expansionBoard; +#endif float lastTime; float longWait; @@ -802,8 +806,8 @@ private: float axisMaxima[MAX_AXES]; float axisMinima[MAX_AXES]; - EndStopType endStopType[MAX_AXES+1]; - bool endStopLogicLevel[MAX_AXES+1]; + EndStopType endStopType[MAX_AXES]; + bool endStopLogicLevel[MAX_AXES]; // Heaters - bed is assumed to be the first @@ -1215,14 +1219,14 @@ inline float Platform::GetPressureAdvance(size_t extruder) const } inline void Platform::SetEndStopConfiguration(size_t axis, EndStopType esType, bool logicLevel) -pre(axis < AXES) +pre(axis < MAX_AXES) { endStopType[axis] = esType; endStopLogicLevel[axis] = logicLevel; } inline void Platform::GetEndStopConfiguration(size_t axis, EndStopType& esType, bool& logicLevel) const -pre(axis < AXES) +pre(axis < MAX_AXES) { esType = endStopType[axis]; logicLevel = endStopLogicLevel[axis]; @@ -1241,19 +1245,21 @@ inline uint16_t Platform::GetRawZProbeReading() const { case 4: { - bool b = ReadPin(endStopPins[E0_AXIS]); - if (!endStopLogicLevel[MAX_AXES]) - { - b = !b; - } + const bool b = ReadPin(endStopPins[E0_AXIS]); return (b) ? 4000 : 0; } case 5: return (ReadPin(zProbePin)) ? 4000 : 0; + case 6: + { + const bool b = ReadPin(endStopPins[E0_AXIS + 1]); + return (b) ? 4000 : 0; + } + default: - return AnalogInReadChannel(zProbeAdcChannel); + return min<uint16_t>(AnalogInReadChannel(zProbeAdcChannel), 4000); } } diff --git a/src/PrintMonitor.cpp b/src/PrintMonitor.cpp index c6b92d9a..67dd85a7 100644 --- a/src/PrintMonitor.cpp +++ b/src/PrintMonitor.cpp @@ -297,6 +297,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod // Set up the info struct parsedFileInfo.isValid = true; parsedFileInfo.fileSize = fileBeingParsed->Length(); + parsedFileInfo.lastModifiedTime = reprap.GetPlatform()->GetMassStorage()->GetLastModifiedTime(directory, fileName); parsedFileInfo.firstLayerHeight = 0.0; parsedFileInfo.objectHeight = 0.0; parsedFileInfo.layerHeight = 0.0; @@ -613,8 +614,17 @@ bool PrintMonitor::GetFileInfoResponse(const char *filename, OutputBuffer *&resp return false; } - response->printf("{\"err\":0,\"size\":%lu,\"height\":%.2f,\"firstLayerHeight\":%.2f,\"layerHeight\":%.2f,\"filament\":", - info.fileSize, info.objectHeight, info.firstLayerHeight, info.layerHeight); + response->printf("{\"err\":0,\"size\":%lu,",info.fileSize); + const struct tm * const timeInfo = gmtime(&info.lastModifiedTime); + if (timeInfo->tm_year > /*19*/80) + { + response->catf("\"lastModified\":\"%04u-%02u-%02uT%02u:%02u:%02u\",", + timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, + timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec); + } + + response->catf("\"height\":%.2f,\"firstLayerHeight\":%.2f,\"layerHeight\":%.2f,\"filament\":", + info.objectHeight, info.firstLayerHeight, info.layerHeight); char ch = '['; if (info.numFilaments == 0) { diff --git a/src/PrintMonitor.h b/src/PrintMonitor.h index 875d43eb..c71770f0 100644 --- a/src/PrintMonitor.h +++ b/src/PrintMonitor.h @@ -53,6 +53,7 @@ struct GCodeFileInfo { bool isValid; FilePosition fileSize; + time_t lastModifiedTime; float firstLayerHeight; float objectHeight; float filamentNeeded[DRIVES - MIN_AXES]; diff --git a/src/Reprap.cpp b/src/Reprap.cpp index 5fd174bc..a0a9300e 100644 --- a/src/Reprap.cpp +++ b/src/Reprap.cpp @@ -1353,7 +1353,7 @@ OutputBuffer *RepRap::GetFilelistResponse(const char *dir) if (fileInfo.fileName[0] != '.') // ignore Mac resource files and Linux hidden files { // Make sure we can end this response properly - if (bytesLeft < strlen(fileInfo.fileName) + 80) + if (bytesLeft < strlen(fileInfo.fileName) + 70) { // No more space available - stop here break; @@ -1371,10 +1371,18 @@ OutputBuffer *RepRap::GetFilelistResponse(const char *dir) bytesLeft -= response->EncodeString(fileInfo.fileName, FILENAME_LENGTH, false); bytesLeft -= response->catf(",\"size\":%u", fileInfo.size); - struct tm *timeInfo = localtime(&fileInfo.lastModified); - bytesLeft -= response->catf(",\"lastModified\":\"%04u-%02u-%02uT%02u:%02u:%02u\"}", - timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, - timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec); + const struct tm * const timeInfo = gmtime(&fileInfo.lastModified); + if (timeInfo->tm_year <= /*19*/80) + { + // Don't send the last modified date if it is invalid + bytesLeft -= response->cat('}'); + } + else + { + bytesLeft -= response->catf(",\"date\":\"%04u-%02u-%02uT%02u:%02u:%02u\"}", + timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, + timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec); + } } gotFile = platform->GetMassStorage()->FindNext(fileInfo); } diff --git a/src/Storage/MassStorage.cpp b/src/Storage/MassStorage.cpp index 5df45663..945045c9 100644 --- a/src/Storage/MassStorage.cpp +++ b/src/Storage/MassStorage.cpp @@ -159,16 +159,7 @@ bool MassStorage::FindFirst(const char *directory, FileInfo &file_info) } file_info.size = entry.fsize; - - struct tm timeInfo; - timeInfo.tm_year = (entry.fdate >> 9) + 80; - timeInfo.tm_mon = (entry.fdate & 0x1DF) >> 5; - timeInfo.tm_mday = max<int>(entry.fdate & 0x1F, 1); - timeInfo.tm_hour = (entry.ftime >> 11) & 0x1F; - timeInfo.tm_min = (entry.ftime >> 5) & 0x3F; - timeInfo.tm_sec = entry.ftime & 0x1F; - timeInfo.tm_isdst = -1; - file_info.lastModified = mktime(&timeInfo); + file_info.lastModified = ConvertTimeStamp(entry.fdate, entry.ftime); return true; } @@ -199,16 +190,7 @@ bool MassStorage::FindNext(FileInfo &file_info) strncpy(file_info.fileName, entry.fname, ARRAY_SIZE(file_info.fileName)); } - struct tm timeInfo; - timeInfo.tm_year = (entry.fdate >> 9) + 80; - timeInfo.tm_mon = (entry.fdate & 0x1DF) >> 5; - timeInfo.tm_mday = max<int>(entry.fdate & 0x1F, 1); - timeInfo.tm_hour = (entry.ftime >> 11) & 0x1F; - timeInfo.tm_min = (entry.ftime >> 5) & 0x3F; - timeInfo.tm_sec = entry.ftime & 0x1F; - timeInfo.tm_isdst = -1; - file_info.lastModified = mktime(&timeInfo); - + file_info.lastModified = ConvertTimeStamp(entry.fdate, entry.ftime); return true; } @@ -297,14 +279,28 @@ bool MassStorage::DirectoryExists(const char* directory, const char* subDirector return DirectoryExists(CombineName(directory, subDirectory)); } +// Return the last modified time of a file, or zero if failure +time_t MassStorage::GetLastModifiedTime(const char* directory, const char *fileName) const +{ + const char *location = (directory != nullptr) + ? platform->GetMassStorage()->CombineName(directory, fileName) + : fileName; + FILINFO fil; + fil.lfname = nullptr; + if (f_stat(location, &fil) == FR_OK) + { + return ConvertTimeStamp(fil.fdate, fil.ftime); + } + return 0; +} + bool MassStorage::SetLastModifiedTime(const char *file, time_t time) { FILINFO fno; - const struct tm * const timeInfo = localtime(&time); + const struct tm * const timeInfo = gmtime(&time); fno.fdate = (WORD)(((timeInfo->tm_year - 80) * 512U) | (timeInfo->tm_mon + 1) * 32U | timeInfo->tm_mday); fno.ftime = (WORD)(timeInfo->tm_hour * 2048U | timeInfo->tm_min * 32U | timeInfo->tm_sec / 2U); - const bool ok = (f_utime(file, &fno) == FR_OK); if (!ok) { @@ -426,4 +422,19 @@ bool MassStorage::CheckDriveMounted(const char* path) return card < NumSdCards && isMounted[card]; } +/*static*/ time_t MassStorage::ConvertTimeStamp(uint16_t fdate, uint16_t ftime) +{ + struct tm timeInfo; + memset(&timeInfo, 0, sizeof(timeInfo)); + timeInfo.tm_year = (fdate >> 9) + 80; + const uint16_t month = (fdate >> 5) & 0x0F; + timeInfo.tm_mon = (month == 0) ? month : month - 1; // month is 1..12 in FAT but 0..11 in struct tm + timeInfo.tm_mday = max<int>(fdate & 0x1F, 1); + timeInfo.tm_hour = (ftime >> 11) & 0x1F; + timeInfo.tm_min = (ftime >> 5) & 0x3F; + timeInfo.tm_sec = ftime & 0x1F; + timeInfo.tm_isdst = 0; + return mktime(&timeInfo); +} + // End diff --git a/src/Storage/MassStorage.h b/src/Storage/MassStorage.h index 0d17b439..3ccf973d 100644 --- a/src/Storage/MassStorage.h +++ b/src/Storage/MassStorage.h @@ -30,6 +30,7 @@ public: bool FileExists(const char* directory, const char *fileName) const; bool DirectoryExists(const char *path) const; bool DirectoryExists(const char* directory, const char* subDirectory); + time_t GetLastModifiedTime(const char* directory, const char *fileName) const; bool SetLastModifiedTime(const char *file, time_t time); bool Mount(size_t card, StringRef& reply, bool reportSuccess); bool Unmount(size_t card, StringRef& reply); @@ -44,6 +45,8 @@ protected: void Init(); private: + static time_t ConvertTimeStamp(uint16_t fdate, uint16_t ftime); + Platform* platform; FATFS fileSystems[NumSdCards]; DIR findDir; |