diff options
author | David Crocker <dcrocker@eschertech.com> | 2017-09-21 21:27:40 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2017-09-21 21:29:52 +0300 |
commit | 370060e84b9f30dd5d9edff817baaba154106c7c (patch) | |
tree | aa399d680427189e6a8c62572c304b9b16118406 /src/Platform.cpp | |
parent | 77d6718860bd6ad383d29e0708c600fcba855116 (diff) |
Version 1.20 alpha 2
Removed define of printf=iprintf in build settings
Removed Platform::Time() function, use millis() or millis64() instead
Added event logging to SD card. MessageType is now a bitmap. Implemented
M929.
Enable pullup resistors on endstops 10 and 11
SCARA printers can now use the manual bed levelling assistant
When using the manual bed levelling assitant, don't give an error if the
bed screw corrections were out of range, and always leave the first
screw alone
M552 now supports connection to a specified SSID
M572 now allows multiple D values
Thermocouple type letter in M305 command may now be in lower case
Bug fix: G29 bed probing on a SCARA printer gave spurious "not
reachable" warnings and skipped probe points
Protect against a dud command line containing the letter M being
interpreted as a M0 command
Fix reference to towers in the error message when trying to move a SCARA
printer before homing it
When updating firmware, warn that USB will disconnect
Fix duplicate error messatge when opening a gcode file fails
Diffstat (limited to 'src/Platform.cpp')
-rw-r--r-- | src/Platform.cpp | 468 |
1 files changed, 285 insertions, 183 deletions
diff --git a/src/Platform.cpp b/src/Platform.cpp index 90126cd1..7e761302 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -251,7 +251,7 @@ bool ZProbeParameters::WriteParameters(FileStore *f, unsigned int probeType) con // Platform class Platform::Platform() : - board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0), lastFanCheckTime(0), + logger(nullptr), lastLogFlushTime(0), board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0), lastFanCheckTime(0), auxGCodeReply(nullptr), fileStructureInitialised(false), tickState(0), debugCode(0) #ifdef DUET_NG , lastWarningMillis(0), nextDriveToPoll(0), @@ -266,7 +266,6 @@ Platform::Platform() : usbOutput = new OutputStack(); // Files - massStorage = new MassStorage(this); for (size_t i = 0; i < MAX_FILES; i++) @@ -345,16 +344,6 @@ void Platform::Init() ARRAY_INIT(macAddress, DefaultMacAddress); #endif - zProbeType = 0; // Default is to use no Z probe switch - zProbeAxes = Z_PROBE_AXES; - SetZProbeDefaults(); - - // We need to initialise at least some of the time stuff before we call MassStorage::Init() - addToTime = 0.0; - lastTimeCall = 0; - lastTime = Time(); - longWait = lastTime; - // File management massStorage->Init(); @@ -408,15 +397,18 @@ void Platform::Init() #endif // Z PROBE + zProbeType = 0; // default is to use no Z probe + zProbeAxes = Z_PROBE_AXES; zProbePin = Z_PROBE_PIN; zProbeAdcChannel = PinToAdcChannel(zProbePin); - InitZProbe(); // this also sets up zProbeModulationPin + SetZProbeDefaults(); + InitZProbe(); // this also sets up zProbeModulationPin // AXES ARRAY_INIT(axisMaxima, AXIS_MAXIMA); ARRAY_INIT(axisMinima, AXIS_MINIMA); - idleCurrentFactor = DEFAULT_IDLE_CURRENT_FACTOR; + idleCurrentFactor = DefaultIdleCurrentFactor; // SD card interfaces for (size_t i = 0; i < NumSdCards; ++i) @@ -434,6 +426,9 @@ void Platform::Init() PIOB->PIO_OWDR = 0xFFFFFFFF; PIOC->PIO_OWDR = 0xFFFFFFFF; PIOD->PIO_OWDR = 0xFFFFFFFF; +#ifdef PIOE + PIOE->PIO_OWDR = 0xFFFFFFFF; +#endif for (size_t drive = 0; drive < DRIVES; drive++) { @@ -469,6 +464,20 @@ void Platform::Init() motorCurrents[drive] = 0.0; motorCurrentFraction[drive] = 1.0; driverState[drive] = DriverStatus::disabled; + + // Enable pullup resistors on endstop inputs here if necessary. +#if defined(DUET_NG) + // The Duets have hardware pullup resistors/LEDs except for the two on the CONN_LCD connector. + // They have RC filtering on the main endstop inputs, so best not to enable the pullup resistors on these. + if (drive >= 10) + { + setPullup(endStopPins[drive], true); // enable pullup on CONN_LCD endstop input + } +#endif +#if defined(__RADDS__) || defined(__ALLIGATOR__) + // I don't know whether RADDS and Alligator have hardware pullup resistors or not. I'll assume they might not. + setPullup(endStopPins[drive], true); +#endif } slowDriverStepPulseClocks = 0; // no extended driver timing configured yet @@ -624,8 +633,7 @@ void Platform::Init() memset(logicalPinModes, PIN_MODE_NOT_CONFIGURED, sizeof(logicalPinModes)); // set all pins to "not configured" // Kick everything off - lastTime = Time(); - longWait = lastTime; + longWait = millis(); InitialiseInterrupts(); // also sets 'active' to true } @@ -702,12 +710,6 @@ void Platform::InitZProbe() pinMode(endStopPins[E0_AXIS + 1], INPUT); pinMode(zProbeModulationPin, OUTPUT_LOW); // we now set the modulation output high during probing only when using probe types 4 and higher break; - - case 7: - AnalogInEnableChannel(zProbeAdcChannel, false); - pinMode(zProbePin, INPUT_PULLUP); - pinMode(zProbeModulationPin, OUTPUT_LOW); // we now set the modulation output high during probing only when using probe types 4 and higher - break; //TODO (DeltaProbe) } } @@ -734,10 +736,6 @@ int Platform::GetZProbeReading() const zProbeVal = (int) (((int32_t) zProbeOnFilter.GetSum() - (int32_t) zProbeOffFilter.GetSum()) / (int)(4 * Z_PROBE_AVERAGE_READINGS)); break; - case 7: // Delta humming probe - zProbeVal = (int) ((zProbeOnFilter.GetSum() + zProbeOffFilter.GetSum()) / (8 * Z_PROBE_AVERAGE_READINGS)); //TODO this is temporary - break; - default: return 0; } @@ -829,7 +827,6 @@ const ZProbeParameters& Platform::GetZProbeParameters(int32_t probeType) const case 5: return irZProbeParameters; case 3: - case 7: return alternateZProbeParameters; case 4: case 6: @@ -849,7 +846,6 @@ void Platform::SetZProbeParameters(int32_t probeType, const ZProbeParameters& pa break; case 3: - case 7: alternateZProbeParameters = params; break; @@ -902,10 +898,10 @@ bool Platform::HomingZWithProbe() const // Check the prerequisites for updating the main firmware. Return True if satisfied, else print as message and return false. bool Platform::CheckFirmwareUpdatePrerequisites() { - FileStore * const firmwareFile = GetFileStore(GetSysDir(), IAP_FIRMWARE_FILE, false); + FileStore * const firmwareFile = GetFileStore(GetSysDir(), IAP_FIRMWARE_FILE, OpenMode::read); if (firmwareFile == nullptr) { - MessageF(GENERIC_MESSAGE, "Error: Firmware binary \"%s\" not found\n", IAP_FIRMWARE_FILE); + MessageF(ErrorMessage, "Firmware binary \"%s\" not found\n", IAP_FIRMWARE_FILE); return false; } @@ -920,13 +916,13 @@ bool Platform::CheckFirmwareUpdatePrerequisites() #endif ) { - MessageF(GENERIC_MESSAGE, "Error: Firmware binary \"%s\" is not valid for this electronics\n", IAP_FIRMWARE_FILE); + MessageF(ErrorMessage, "Firmware binary \"%s\" is not valid for this electronics\n", IAP_FIRMWARE_FILE); return false; } if (!GetMassStorage()->FileExists(GetSysDir(), IAP_UPDATE_FILE)) { - MessageF(GENERIC_MESSAGE, "Error: In-application programming binary \"%s\" not found\n", IAP_UPDATE_FILE); + MessageF(ErrorMessage, "In-application programming binary \"%s\" not found\n", IAP_UPDATE_FILE); return false; } @@ -936,10 +932,10 @@ bool Platform::CheckFirmwareUpdatePrerequisites() // Update the firmware. Prerequisites should be checked before calling this. void Platform::UpdateFirmware() { - FileStore * const iapFile = GetFileStore(GetSysDir(), IAP_UPDATE_FILE, false); + FileStore * const iapFile = GetFileStore(GetSysDir(), IAP_UPDATE_FILE, OpenMode::read); if (iapFile == nullptr) { - MessageF(FIRMWARE_UPDATE_MESSAGE, "IAP not found\n"); + MessageF(FirmwareUpdateMessage, "IAP not found\n"); return; } @@ -982,13 +978,13 @@ void Platform::UpdateFirmware() if (rc != FLASH_RC_OK) { - MessageF(FIRMWARE_UPDATE_MESSAGE, "Error: Flash write failed, code=%u, address=0x%08x\n", rc, flashAddr); + MessageF(FirmwareUpdateErrorMessage, "flash write failed, code=%u, address=0x%08x\n", rc, flashAddr); return; } // Verify written data if (memcmp(reinterpret_cast<void *>(flashAddr), data, bytesRead) != 0) { - MessageF(FIRMWARE_UPDATE_MESSAGE, "Error: Verify during flash write failed, address=0x%08x\n", flashAddr); + MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08x\n", flashAddr); return; } } @@ -1039,13 +1035,13 @@ void Platform::UpdateFirmware() if (rc != FLASH_RC_OK) { - MessageF(FIRMWARE_UPDATE_MESSAGE, "Error: Flash %s failed, code=%u, address=0x%08x\n", op, rc, flashAddr); + MessageF(FirmwareUpdateErrorMessage, "flash %s failed, code=%u, address=0x%08x\n", op, rc, flashAddr); return; } // Verify written data if (memcmp(reinterpret_cast<void *>(flashAddr), data, bytesRead) != 0) { - MessageF(FIRMWARE_UPDATE_MESSAGE, "Error: Verify during flash write failed, address=0x%08x\n", flashAddr); + MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08x\n", flashAddr); return; } } @@ -1063,7 +1059,9 @@ void Platform::UpdateFirmware() #endif iapFile->Close(); - Message(FIRMWARE_UPDATE_MESSAGE, "Updating main firmware\n"); + + Message(LcdMessage, "Updating main firmware\n"); + Message(UsbMessage, "Shutting down USB interface to update main firmware. Try reconnecting after 30 seconds.\n"); // Allow time for the firmware update message to be sent const uint32_t now = millis(); @@ -1132,7 +1130,7 @@ void Platform::UpdateFirmware() // Send the beep command to the aux channel. There is no flow control on this port, so it can't block for long. void Platform::Beep(int freq, int ms) { - MessageF(AUX_MESSAGE, "{\"beep_freq\":%d,\"beep_length\":%d}\n", freq, ms); + MessageF(LcdMessage, "{\"beep_freq\":%d,\"beep_length\":%d}\n", freq, ms); } // Send a short message to the aux channel. There is no flow control on this port, so it can't block for long. @@ -1144,27 +1142,14 @@ void Platform::SendAuxMessage(const char* msg) buf->copy("{\"message\":"); buf->EncodeString(msg, strlen(msg), false, true); buf->cat("}\n"); - Message(AUX_MESSAGE, buf); - } -} - -// Note: the use of floating point time will cause the resolution to degrade over time. -// For example, 1ms time resolution will only be available for about half an hour from startup. -// Personally, I (dc42) would rather just maintain and provide the time in milliseconds in a uint32_t. -// This would wrap round after about 49 days, but that isn't difficult to handle. -float Platform::Time() -{ - unsigned long now = micros(); - if (now < lastTimeCall) // Has timer overflowed? - { - addToTime += ((float) ULONG_MAX) * TIME_FROM_REPRAP; + Message(LcdMessage, buf); } - lastTimeCall = now; - return addToTime + TIME_FROM_REPRAP * (float) now; } void Platform::Exit() { + StopLogging(); + // Close all files for (FileStore*& f : files) { @@ -1201,14 +1186,16 @@ void Platform::SetEmulating(Compatibility c) { if (c != me && c != reprapFirmware && c != marlin) { - Message(GENERIC_MESSAGE, "Attempt to emulate unsupported firmware.\n"); - return; + Message(ErrorMessage, "Attempt to emulate unsupported firmware.\n"); } - if (c == reprapFirmware) + else { - c = me; + if (c == reprapFirmware) + { + c = me; + } + compatibility = c; } - compatibility = c; } void Platform::UpdateNetworkAddress(byte dst[4], const byte src[4]) @@ -1415,8 +1402,19 @@ void Platform::Spin() TMC2660::SetDriversPowered(driversPowered); #endif - // Thermostatically-controlled fans (do this after getting TMC driver status) const uint32_t now = millis(); + + // Update the time + if (realTime != 0) + { + if (now - timeLastUpdatedMillis >= 1000) + { + ++realTime; // this assumes that time_t is a seconds-since-epoch counter, which is not guaranteed by the C standard + timeLastUpdatedMillis += 1000; + } + } + + // Thermostatically-controlled fans (do this after getting TMC driver status) if (now - lastFanCheckTime >= FanCheckInterval) { lastFanCheckTime = now; @@ -1452,7 +1450,7 @@ void Platform::Spin() // Check for a VSSA fault if (vssaSenseWorking && digitalRead(VssaSensePin)) { - Message(GENERIC_MESSAGE, "Error: VSSA fault, check thermistor wiring\n"); + Message(ErrorMessage, "VSSA fault, check thermistor wiring\n"); reported = true; } @@ -1464,16 +1462,6 @@ void Platform::Spin() #endif } - // Update the time - if (realTime != 0) - { - if (millis() - timeLastUpdatedMillis >= 1000) - { - ++realTime; // this assumes that time_t is a seconds-since-epoch counter, which is not guaranteed by the C standard - timeLastUpdatedMillis += 1000; - } - } - #ifdef DUET_NG // Check for auto-pause, shutdown or resume if (autoSaveEnabled) @@ -1530,6 +1518,16 @@ void Platform::Spin() } #endif + // Flush the log file it it is time. This may take some time, so do it last. + if (logger != nullptr) + { + if (now - lastLogFlushTime >= LogFlushInterval) + { + logger->Flush(); + lastLogFlushTime = now; + } + } + ClassReport(longWait); } @@ -1550,21 +1548,22 @@ void Platform::ReportDrivers(uint16_t whichDrivers, const char* text, bool& repo } whichDrivers >>= 1; } - MessageF(GENERIC_MESSAGE, "%s\n", scratchString); + MessageF(GenericMessage, "%s\n", scratchString); reported = true; } } // Configure auto save on power fail -void Platform::ConfigureAutoSave(GCodeBuffer& gb, StringRef& reply, bool& error) +bool Platform::ConfigureAutoSave(GCodeBuffer& gb, StringRef& reply) { bool seen = false; float autoSaveVoltages[3]; if (gb.TryGetFloatArray('S', 3, autoSaveVoltages, reply, seen)) { - error = true; + return true; } - else if (seen) + + if (seen) { autoSaveEnabled = (autoSaveVoltages[0] >= 5.0 && autoSaveVoltages[1] > autoSaveVoltages[0] && autoSaveVoltages[2] > autoSaveVoltages[1]); if (autoSaveEnabled) @@ -1583,6 +1582,7 @@ void Platform::ConfigureAutoSave(GCodeBuffer& gb, StringRef& reply, bool& error) reply.printf(" Auto shutdown at %.1fV, save/pause at %.1fV, resume at %.1fV", AdcReadingToPowerVoltage(autoShutdownReading), AdcReadingToPowerVoltage(autoPauseReading), AdcReadingToPowerVoltage(autoResumeReading)); } + return false; } // Save some resume information @@ -1903,7 +1903,7 @@ void Platform::Diagnostics(MessageType mtype) MessageF(mtype, "Never used ram: %u\n", neverUsed); // Show the up time and reason for the last reset - const uint32_t now = (uint32_t)Time(); // get up time in seconds + const uint32_t now = (uint32_t)(millis64()/1000u); // get up time in seconds const char* resetReasons[8] = { "power up", "backup", "watchdog", "software", #ifdef DUET_NG // On the SAM4E a watchdog reset may be reported as a user reset because of the capacitor on the NRST pin @@ -2122,7 +2122,7 @@ void Platform::DiagnosticTest(int d) const uint32_t now2 = Platform::GetInterruptClocks(); const uint32_t num2a = isqrt64((uint64_t)num2 * num2); const uint32_t tim2 = Platform::GetInterruptClocks() - now2; - MessageF(GENERIC_MESSAGE, "Square roots: 64-bit %.1fus %s, 32-bit %.1fus %s\n", + MessageF(GenericMessage, "Square roots: 64-bit %.1fus %s, 32-bit %.1fus %s\n", (float)(tim1 * 1000000)/DDA::stepClockRate, (num1a == num1) ? "ok" : "ERROR", (float)(tim2 * 1000000)/DDA::stepClockRate, (num2a == num2) ? "ok" : "ERROR"); } @@ -2130,7 +2130,7 @@ void Platform::DiagnosticTest(int d) #ifdef DUET_NG case (int)DiagnosticTestType::PrintExpanderStatus: - MessageF(GENERIC_MESSAGE, "Expander status %04X\n", DuetExpansion::DiagnosticRead()); + MessageF(GenericMessage, "Expander status %04X\n", DuetExpansion::DiagnosticRead()); break; #endif @@ -2157,15 +2157,16 @@ void Platform::GetStackUsage(uint32_t* currentStack, uint32_t* maxStack, uint32_ if (neverUsed != nullptr) { *neverUsed = stack_lwm - heapend; } } -void Platform::ClassReport(float &lastTime) +void Platform::ClassReport(uint32_t &lastTime) { const Module spinningModule = reprap.GetSpinningModule(); if (reprap.Debug(spinningModule)) { - if (Time() - lastTime >= LONG_TIME) + const uint32_t now = millis(); + if (now - lastTime >= LongTime) { - lastTime = Time(); - MessageF(HOST_MESSAGE, "Class %s spinning.\n", moduleName[spinningModule]); + lastTime = now; + MessageF(UsbMessage, "Class %s spinning\n", moduleName[spinningModule]); } } } @@ -2398,6 +2399,16 @@ void Platform::DisableDrive(size_t drive) } } +// Disable all drives +void Platform::DisableAllDrives() +{ + for (size_t drive = 0; drive < DRIVES; drive++) + { + SetDriverCurrent(drive, 0.0, false); + DisableDriver(drive); + } +} + // Set drives to idle hold if they are enabled. If a drive is disabled, leave it alone. // Must not be called from an ISR, or with interrupts disabled. void Platform::SetDriversIdle() @@ -2781,7 +2792,7 @@ void Platform::SetMACAddress(uint8_t mac[]) //----------------------------------------------------------------------------------------------------- -FileStore* Platform::GetFileStore(const char* directory, const char* fileName, bool write) +FileStore* Platform::GetFileStore(const char* directory, const char* fileName, OpenMode mode) { if (!fileStructureInitialised) { @@ -2792,7 +2803,7 @@ FileStore* Platform::GetFileStore(const char* directory, const char* fileName, b { if (!files[i]->inUse) { - if (files[i]->Open(directory, fileName, write)) + if (files[i]->Open(directory, fileName, mode)) { files[i]->inUse = true; return files[i]; @@ -2803,7 +2814,7 @@ FileStore* Platform::GetFileStore(const char* directory, const char* fileName, b } } } - Message(HOST_MESSAGE, "Max open file count exceeded.\n"); + Message(UsbMessage, "Max open file count exceeded.\n"); return nullptr; } @@ -2862,15 +2873,37 @@ void Platform::AppendAuxReply(OutputBuffer *reply) } } -void Platform::Message(MessageType type, const char *message) +// Send the specified message to the specified destinations. The Error and Warning flags have already been handled. +void Platform::RawMessage(MessageType type, const char *message) { - switch (type) + // Deal with logging + if ((type & LogMessage) != 0 && logger != nullptr) + { + logger->LogMessage(realTime, message); + } + + // Send the nessage to the destinations + if ((type & ImmediateLcdMessage) != 0) + { + SendAuxMessage(message); + } + else if ((type & LcdMessage) != 0) { - case AUX_MESSAGE: AppendAuxReply(message); - break; + } - case AUX2_MESSAGE: + if ((type & HttpMessage) != 0) + { + reprap.GetNetwork().HandleHttpGCodeReply(message); + } + + if ((type & TelnetMessage) != 0) + { + reprap.GetNetwork().HandleTelnetGCodeReply(message); + } + + if ((type & AuxMessage) != 0) + { #ifdef SERIAL_AUX2_DEVICE // Message that is to be sent to the second auxiliary device (blocking) if (!aux2Output->IsEmpty()) @@ -2885,15 +2918,16 @@ void Platform::Message(MessageType type, const char *message) SERIAL_AUX2_DEVICE.flush(); } #endif - break; + } - case DEBUG_MESSAGE: + if ((type & BlockingUsbMessage) != 0) + { // Debug messages in blocking mode - potentially DANGEROUS, use with care! SERIAL_MAIN_DEVICE.write(message); SERIAL_MAIN_DEVICE.flush(); - break; - - case HOST_MESSAGE: + } + else if ((type & UsbMessage) != 0) + { // Message that is to be sent via the USB line (non-blocking) #if SUPPORT_SCANNER if (!reprap.GetScanner().IsRegistered() || reprap.GetScanner().DoingGCodes()) @@ -2914,101 +2948,94 @@ void Platform::Message(MessageType type, const char *message) // Append the message string usbOutputBuffer->cat(message); } - break; - - case HTTP_MESSAGE: - reprap.GetNetwork().HandleHttpGCodeReply(message); - break; - - case TELNET_MESSAGE: - reprap.GetNetwork().HandleTelnetGCodeReply(message); - break; - - case FIRMWARE_UPDATE_MESSAGE: - Message(HOST_MESSAGE, message); // send message to USB - SendAuxMessage(message); // send message to aux - break; - - case GENERIC_MESSAGE: - // Message that is to be sent to the web & host. Make this the default one, too. - default: - Message(HTTP_MESSAGE, message); - Message(TELNET_MESSAGE, message); - // no break - case NETWORK_INFO_MESSAGE: - Message(HOST_MESSAGE, message); - Message(AUX_MESSAGE, message); - break; } } +// Note: this overload of Platform::Message does not process the special action flags in the MessageType. +// Also it treats calls to send a blocking USB message the same as ordinary USB messages, +// and calls to send an immediate LCD message the same as ordinary LCD messages void Platform::Message(const MessageType type, OutputBuffer *buffer) { - switch (type) + // First deal with logging because it doesn't hand on to the buffer + if ((type & LogMessage) != 0 && logger != nullptr) { - case AUX_MESSAGE: - AppendAuxReply(buffer); - break; + logger->LogMessage(realTime, buffer); + } + + // Now send the message to all the destinations + size_t numDestinations = 0; + if ((type & (LcdMessage | ImmediateLcdMessage)) != 0) + { + ++numDestinations; + } + if ((type & (UsbMessage | BlockingUsbMessage)) != 0) + { + ++numDestinations; + } + if ((type & HttpMessage) != 0) + { + ++numDestinations; + } + if ((type & TelnetMessage) != 0) + { + ++numDestinations; + } - case AUX2_MESSAGE: #ifdef SERIAL_AUX2_DEVICE - // Send this message to the second UART device - aux2Output->Push(buffer); -#else - OutputBuffer::ReleaseAll(buffer); + if ((type & AuxMessage) != 0) + { + ++numDestinations; + } #endif - break; - case DEBUG_MESSAGE: - // Probably rarely used, but supported. - while (buffer != nullptr) - { - SERIAL_MAIN_DEVICE.write(buffer->Data(), buffer->DataLength()); - SERIAL_MAIN_DEVICE.flush(); + if (numDestinations == 0) + { + OutputBuffer::ReleaseAll(buffer); + } + else + { + buffer->IncreaseReferences(numDestinations - 1); - buffer = OutputBuffer::Release(buffer); + if ((type & (LcdMessage | ImmediateLcdMessage)) != 0) + { + AppendAuxReply(buffer); } - break; - case HOST_MESSAGE: - if ( !SERIAL_MAIN_DEVICE -#if SUPPORT_SCANNER - || (reprap.GetScanner().IsRegistered() && !reprap.GetScanner().DoingGCodes()) -#endif - ) + if ((type & HttpMessage) != 0) { - // If the serial USB line is not open, discard the message right away - OutputBuffer::ReleaseAll(buffer); + reprap.GetNetwork().HandleHttpGCodeReply(buffer); } - else + + if ((type & TelnetMessage) != 0) { - // Else append incoming data to the stack - usbOutput->Push(buffer); + reprap.GetNetwork().HandleTelnetGCodeReply(buffer); } - break; - - case HTTP_MESSAGE: - reprap.GetNetwork().HandleHttpGCodeReply(buffer); - break; - case TELNET_MESSAGE: - reprap.GetNetwork().HandleTelnetGCodeReply(buffer); - break; - - case GENERIC_MESSAGE: - // Message that is to be sent to the web & host. - buffer->IncreaseReferences(3); // This one is handled by three additional destinations - Message(HTTP_MESSAGE, buffer); - Message(TELNET_MESSAGE, buffer); - Message(HOST_MESSAGE, buffer); - Message(AUX_MESSAGE, buffer); - break; +#ifdef SERIAL_AUX2_DEVICE + if ((type & AuxMessage) != 0) + { + // Send this message to the second UART device + aux2Output->Push(buffer); + } +#endif - default: - // Everything else is unsupported (and probably not used) - OutputBuffer::ReleaseAll(buffer); - MessageF(HOST_MESSAGE, "Error: Unsupported Message call for type %u!\n", type); - break; + if ((type & (UsbMessage | BlockingUsbMessage)) != 0) + { + if ( !SERIAL_MAIN_DEVICE +#if SUPPORT_SCANNER + || (reprap.GetScanner().IsRegistered() && !reprap.GetScanner().DoingGCodes()) +#endif + ) + { + // If the serial USB line is not open, discard the message right away + OutputBuffer::ReleaseAll(buffer); + } + else + { + // Else append incoming data to the stack + usbOutput->Push(buffer); + } + } } } @@ -3016,22 +3043,46 @@ void Platform::MessageF(MessageType type, const char *fmt, va_list vargs) { char formatBuffer[FORMAT_STRING_LENGTH]; StringRef formatString(formatBuffer, ARRAY_SIZE(formatBuffer)); - formatString.vprintf(fmt, vargs); + if ((type & ErrorMessageFlag) != 0) + { + formatString.copy("Error: "); + formatString.vcatf(fmt, vargs); + } + else if ((type & WarningMessageFlag) != 0) + { + formatString.copy("Warning: "); + formatString.vcatf(fmt, vargs); + } + else + { + formatString.vprintf(fmt, vargs); + } - Message(type, formatBuffer); + RawMessage((MessageType)(type & ~(ErrorMessageFlag | WarningMessageFlag)), formatBuffer); } void Platform::MessageF(MessageType type, const char *fmt, ...) { - char formatBuffer[FORMAT_STRING_LENGTH]; - StringRef formatString(formatBuffer, ARRAY_SIZE(formatBuffer)); - va_list vargs; va_start(vargs, fmt); - formatString.vprintf(fmt, vargs); + MessageF(type, fmt, vargs); va_end(vargs); +} - Message(type, formatBuffer); +void Platform::Message(MessageType type, const char *message) +{ + if ((type & (ErrorMessageFlag | WarningMessageFlag)) == 0) + { + RawMessage(type, message); + } + else + { + char formatBuffer[FORMAT_STRING_LENGTH]; + StringRef formatString(formatBuffer, ARRAY_SIZE(formatBuffer)); + formatString.copy(((type & ErrorMessageFlag) != 0) ? "Error: " : "Warning: "); + formatString.cat(message); + RawMessage((MessageType)(type & ~(ErrorMessageFlag | WarningMessageFlag)), formatBuffer); + } } // Send a message box, which may require an acknowledgement @@ -3043,9 +3094,9 @@ void Platform::SendAlert(MessageType mt, const char *message, const char *title, { switch (mt) { - case HTTP_MESSAGE: - case AUX_MESSAGE: - case GENERIC_MESSAGE: + case HttpMessage: + case LcdMessage: + case GenericMessage: // Make the RepRap class cache this message until it's picked up by the HTTP clients and/or PanelDue reprap.SetAlert(message, title, sParam, tParam, controls); break; @@ -3068,6 +3119,57 @@ void Platform::SendAlert(MessageType mt, const char *message, const char *title, } } +// Configure logging according to the M929 command received, returning true if error +bool Platform::ConfigureLogging(GCodeBuffer& gb, StringRef& reply) +{ + if (gb.Seen('S')) + { + StopLogging(); + if (gb.GetIValue() > 0) + { + // Start logging + if (logger == nullptr) + { + logger = new Logger(); + } + else + { + StopLogging(); + } + + char buf[FILENAME_LENGTH + 1]; + StringRef filename(buf, ARRAY_SIZE(buf)); + if (gb.Seen('P')) + { + if (!gb.GetQuotedString(filename)) + { + reply.copy("Missing filename in M929 command"); + return true; + } + } + else + { + filename.copy(DEFAULT_LOG_FILE); + } + logger->Start(realTime, filename); + } + } + else + { + reply.printf("Event logging is %s", (logger != nullptr && logger->IsActive()) ? "enabled" : "disabled"); + } + return false; +} + +// This is called form EmergencyStop. It closes the log file and stops logging. +void Platform::StopLogging() +{ + if (logger != nullptr) + { + logger->Stop(realTime); + } +} + bool Platform::AtxPower() const { return ReadPin(ATX_POWER_PIN); |