Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cproject132
-rw-r--r--.settings/language.settings.xml11
-rw-r--r--src/BugList.txt42
-rw-r--r--src/Configuration.h1
-rw-r--r--src/Display/ST7920/lcd7920.cpp4
-rw-r--r--src/DuetM/Pins_DuetM.h1
-rw-r--r--src/Fan.cpp2
-rw-r--r--src/Fan.h3
-rw-r--r--src/GCodes/GCodeBuffer.cpp64
-rw-r--r--src/GCodes/GCodes.cpp167
-rw-r--r--src/GCodes/GCodes.h67
-rw-r--r--src/GCodes/GCodes2.cpp184
-rw-r--r--src/GCodes/GCodes3.cpp65
-rw-r--r--src/Heating/Heat.cpp7
-rw-r--r--src/Heating/Heat.h3
-rw-r--r--src/Heating/Sensors/CurrentLoopTemperatureSensor.cpp4
-rw-r--r--src/Heating/Sensors/CurrentLoopTemperatureSensor.h2
-rw-r--r--src/Heating/Sensors/DhtSensor.cpp7
-rw-r--r--src/Heating/Sensors/DhtSensor.h2
-rw-r--r--src/Heating/Sensors/RtdSensor31865.cpp4
-rw-r--r--src/Heating/Sensors/RtdSensor31865.h2
-rw-r--r--src/Heating/Sensors/TemperatureSensor.cpp4
-rw-r--r--src/Heating/Sensors/TemperatureSensor.h3
-rw-r--r--src/Heating/Sensors/Thermistor.cpp4
-rw-r--r--src/Heating/Sensors/Thermistor.h2
-rw-r--r--src/Heating/Sensors/ThermocoupleSensor31856.cpp6
-rw-r--r--src/Heating/Sensors/ThermocoupleSensor31856.h2
-rw-r--r--src/Libraries/General/IP4String.cpp1
-rw-r--r--src/Libraries/General/SafeStrtod.cpp (renamed from src/Libraries/General/strtod.cpp)18
-rw-r--r--src/Libraries/General/SafeStrtod.h30
-rw-r--r--src/Libraries/General/SafeVsnprintf.cpp636
-rw-r--r--src/Libraries/General/SafeVsnprintf.h20
-rw-r--r--src/Libraries/General/StringRef.cpp31
-rw-r--r--src/Libraries/General/StringRef.h5
-rw-r--r--src/Movement/BedProbing/Grid.cpp100
-rw-r--r--src/Movement/BedProbing/Grid.h3
-rw-r--r--src/Movement/Move.cpp88
-rw-r--r--src/Movement/Move.h12
-rw-r--r--src/Networking/NetworkResponder.h2
-rw-r--r--src/Platform.cpp72
-rw-r--r--src/Platform.h59
-rw-r--r--src/RepRap.cpp35
-rw-r--r--src/RepRapFirmware.h2
-rw-r--r--src/Scanner.cpp2
-rw-r--r--src/Spindle.cpp57
-rw-r--r--src/Spindle.h41
-rw-r--r--src/Storage/FileInfoParser.cpp26
-rw-r--r--src/Version.h4
-rw-r--r--src/ZProbe.h3
49 files changed, 1596 insertions, 446 deletions
diff --git a/.cproject b/.cproject
index e14a0429..18e776b4 100644
--- a/.cproject
+++ b/.cproject
@@ -219,7 +219,6 @@
<option id="gnu.cpp.compiler.option.preprocessor.def.1610427238" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols">
<listOptionValue builtIn="false" value="__SAM4E8E__"/>
<listOptionValue builtIn="false" value="DUET_NG"/>
- <listOptionValue builtIn="false" value="DUET_WIFI"/>
<listOptionValue builtIn="false" value="_XOPEN_SOURCE"/>
</option>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.151249281" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
@@ -768,7 +767,7 @@
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.c.linker.1102044150" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"/>
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.1402882499" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
- <tool command="gcc" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${LinkFlags1} &quot;${workspace_loc}/${CoreName}/SAM4E8E/cores/arduino/syscalls.o&quot; ${INPUTS} ${LinkFlags2}" id="cdt.managedbuild.tool.gnu.cross.cpp.linker.1768134875" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
+ <tool command="gcc" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${LinkFlags1} &quot;${workspace_loc}/${CoreName}/SAM4E8E_RTOS/cores/arduino/syscalls.o&quot; ${INPUTS} ${LinkFlags2}" id="cdt.managedbuild.tool.gnu.cross.cpp.linker.1768134875" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
<option id="gnu.cpp.link.option.nostdlibs.399544265" name="No startup or default libs (-nostdlib)" superClass="gnu.cpp.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
<option id="gnu.cpp.link.option.paths.605414111" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" useByScannerDiscovery="false" valueType="libPaths">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/SAM4E8E_RTOS/}&quot;"/>
@@ -776,9 +775,9 @@
</option>
<option id="gnu.cpp.link.option.libs.847860449" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" useByScannerDiscovery="false" valueType="libs">
<listOptionValue builtIn="false" value="${CoreName}"/>
- <listOptionValue builtIn="false" value="FreeRtos"/>
+ <listOptionValue builtIn="false" value="FreeRTOS"/>
</option>
- <option id="gnu.cpp.link.option.flags.161856294" name="Linker flags" superClass="gnu.cpp.link.option.flags" useByScannerDiscovery="false" value="-Os --specs=nano.specs -u _printf_float -u _scanf_float -Wl,--gc-sections -Wl,--fatal-warnings -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -T${workspace_loc:/${CoreName}/variants/duetNG/linker_scripts/gcc/flash.ld} -Wl,-Map,${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.map" valueType="string"/>
+ <option id="gnu.cpp.link.option.flags.161856294" name="Linker flags" superClass="gnu.cpp.link.option.flags" useByScannerDiscovery="false" value="-Os --specs=nano.specs -Wl,--gc-sections -Wl,--fatal-warnings -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -T${workspace_loc:/${CoreName}/variants/duetNG/linker_scripts/gcc/flash.ld} -Wl,-Map,${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.map" valueType="string"/>
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1270956612" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
@@ -818,7 +817,6 @@
<listOptionValue builtIn="false" value="__SAM4E8E__"/>
<listOptionValue builtIn="false" value="RTOS"/>
<listOptionValue builtIn="false" value="DUET_NG"/>
- <listOptionValue builtIn="false" value="DUET_WIFI"/>
<listOptionValue builtIn="false" value="_XOPEN_SOURCE"/>
</option>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.65828751" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
@@ -832,16 +830,138 @@
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
+ <cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786" moduleId="org.eclipse.cdt.core.settings" name="DuetM_RTOS">
+ <macros>
+ <stringMacro name="LinkFlags2" type="VALUE_TEXT" value="-Wl,--end-group -lm"/>
+ <stringMacro name="LinkFlags1" type="VALUE_TEXT" value="-mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group"/>
+ <stringMacro name="CoreName" type="VALUE_TEXT" value="CoreNG"/>
+ <stringMacro name="GccPath" type="VALUE_TEXT" value="C:\Program Files (x86)\GNU Tools ARM Embedded\6 2017-q2-update\bin"/>
+ </macros>
+ <externalSettings/>
+ <extensions>
+ <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactExtension="elf" artifactName="DuetMaestroFirmware" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786" name="DuetM_RTOS" parent="cdt.managedbuild.config.gnu.cross.exe.release" postannouncebuildStep="Generating binary file" postbuildStep="arm-none-eabi-objcopy -O binary ${workspace_loc:/${ProjName}/${ConfigName}}/DuetMaestroFirmware.elf ${workspace_loc:/${ProjName}/${ConfigName}}/DuetMaestroFirmware.bin">
+ <folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786." name="/" resourcePath="">
+ <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.1494327638" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release">
+ <option id="cdt.managedbuild.option.gnu.cross.path.1101985181" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path" useByScannerDiscovery="false" value="${GccPath}" valueType="string"/>
+ <option id="cdt.managedbuild.option.gnu.cross.prefix.455634880" name="Prefix" superClass="cdt.managedbuild.option.gnu.cross.prefix" useByScannerDiscovery="false" value="arm-none-eabi-" valueType="string"/>
+ <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.1648156947" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
+ <builder buildPath="${workspace_loc:/RepRapFirmware}/Release" id="cdt.managedbuild.builder.gnu.cross.1787405692" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="cdt.managedbuild.builder.gnu.cross"/>
+ <tool id="cdt.managedbuild.tool.gnu.cross.assembler.1187253546" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
+ <inputType id="cdt.managedbuild.tool.gnu.assembler.input.456980885" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+ </tool>
+ <tool commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" id="cdt.managedbuild.tool.gnu.cross.c.compiler.1037043643" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
+ <option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.option.optimization.level.293020747" name="Optimization Level" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.c.optimization.level.more" valueType="enumerated"/>
+ <option id="gnu.c.compiler.option.debugging.level.1647722987" name="Debug Level" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.none" valueType="enumerated"/>
+ <option id="gnu.c.compiler.option.misc.verbose.412653021" name="Verbose (-v)" superClass="gnu.c.compiler.option.misc.verbose" useByScannerDiscovery="false" value="false" valueType="boolean"/>
+ <option id="gnu.c.compiler.option.misc.other.1084863157" name="Other flags" superClass="gnu.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-c -std=gnu99 -mcpu=cortex-m4 -mthumb -ffunction-sections -fdata-sections -nostdlib -Wdouble-promotion -fsingle-precision-constant &quot;-Wa,-ahl=$*.s&quot;" valueType="string"/>
+ <option id="gnu.c.compiler.option.include.paths.275997920" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/cores/arduino}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/libraries/Storage}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/common/utils}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/common/services/ioport}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/drivers}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils/cmsis/sam4s/include}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils/header_files}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils/preprocessor}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/thirdparty/CMSIS/Include}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/variants/sam4s}&quot;"/>
+ </option>
+ <option id="gnu.c.compiler.option.preprocessor.def.symbols.833298868" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="__SAM4S8C__"/>
+ <listOptionValue builtIn="false" value="RTOS"/>
+ <listOptionValue builtIn="false" value="DUET_M"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.667707888" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+ </tool>
+ <tool id="cdt.managedbuild.tool.gnu.cross.c.linker.411798791" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"/>
+ <tool id="cdt.managedbuild.tool.gnu.cross.archiver.2116733751" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
+ <tool command="gcc" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${LinkFlags1} &quot;${workspace_loc}/${CoreName}/SAM4S_RTOS/cores/arduino/syscalls.o&quot; ${INPUTS} ${LinkFlags2}" id="cdt.managedbuild.tool.gnu.cross.cpp.linker.1011842834" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
+ <option id="gnu.cpp.link.option.nostdlibs.91014132" name="No startup or default libs (-nostdlib)" superClass="gnu.cpp.link.option.nostdlibs" useByScannerDiscovery="false" value="false" valueType="boolean"/>
+ <option id="gnu.cpp.link.option.paths.2085138159" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths" useByScannerDiscovery="false" valueType="libPaths">
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/SAM4S_RTOS/}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/FreeRTOS/SAM4S}&quot;"/>
+ </option>
+ <option id="gnu.cpp.link.option.libs.214117190" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" useByScannerDiscovery="false" valueType="libs">
+ <listOptionValue builtIn="false" value="${CoreName}"/>
+ <listOptionValue builtIn="false" value="FreeRTOS"/>
+ </option>
+ <option id="gnu.cpp.link.option.flags.1077151865" name="Linker flags" superClass="gnu.cpp.link.option.flags" useByScannerDiscovery="false" value="-Os --specs=nano.specs -Wl,--gc-sections -Wl,--fatal-warnings -mcpu=cortex-m4 -T${workspace_loc:/${CoreName}/variants/sam4s/linker_scripts/gcc/flash.ld} -Wl,-Map,${workspace_loc:/${ProjName}/${ConfigName}}/${BuildArtifactFileBaseName}.map" valueType="string"/>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.480654714" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+ <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+ <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+ </inputType>
+ </tool>
+ <tool command="g++" id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.1849650984" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
+ <option id="gnu.cpp.compiler.option.optimization.level.1017091230" name="Optimization Level" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.more" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.option.debugging.level.326047343" name="Debug Level" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
+ <option id="gnu.cpp.compiler.option.other.verbose.1316817271" name="Verbose (-v)" superClass="gnu.cpp.compiler.option.other.verbose" useByScannerDiscovery="false" value="false" valueType="boolean"/>
+ <option id="gnu.cpp.compiler.option.other.other.434744183" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" useByScannerDiscovery="false" value="-c -std=gnu++14 -mcpu=cortex-m4 -mthumb -ffunction-sections -fdata-sections -fno-threadsafe-statics -fno-rtti -fno-exceptions -nostdlib -Wdouble-promotion -fsingle-precision-constant &quot;-Wa,-ahl=$*.s&quot;" valueType="string"/>
+ <option id="gnu.cpp.compiler.option.include.paths.1102345734" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" useByScannerDiscovery="false" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/cores/arduino}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/libraries/Flash}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/libraries/SharedSpi}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/libraries/Storage}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/libraries/Wire}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/common/utils}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/common/services/clock}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/common/services/ioport}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/drivers}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/services/flash_efc}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils/cmsis/sam4s/include}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils/header_files}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/sam/utils/preprocessor}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/asf/thirdparty/CMSIS/Include}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${CoreName}/variants/sam4s}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/src}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/src/DuetM}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/src/Networking}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/DuetWiFiSocketServer/src/include}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/FreeRTOS/src/include}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/FreeRTOS/src/portable/GCC/ARM_CM3}&quot;"/>
+ </option>
+ <option id="gnu.cpp.compiler.option.preprocessor.def.1832014133" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="__SAM4S8C__"/>
+ <listOptionValue builtIn="false" value="RTOS"/>
+ <listOptionValue builtIn="false" value="DUET_M"/>
+ <listOptionValue builtIn="false" value="_XOPEN_SOURCE"/>
+ </option>
+ <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1979789995" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ <sourceEntries>
+ <entry excluding="src/DuetNG|src/Networking/ESP8266WiFi|src/Networking/LwipEthernet|src/Alligator|src/SAME70_TEST|src/Duet|src/RADDS" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
+ </sourceEntries>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="RepRapFirmware.cdt.managedbuild.target.gnu.cross.exe.1494358155" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="refreshScope" versionNumber="2">
+ <configuration configurationName="DuetM_RTOS"/>
<configuration configurationName="Alligator"/>
<configuration configurationName="SAME70"/>
- <configuration configurationName="RADDS"/>
<configuration configurationName="Duet2"/>
+ <configuration configurationName="RADDS"/>
+ <configuration configurationName="Duet2_RTOS"/>
<configuration configurationName="DuetM"/>
<configuration configurationName="Duet085"/>
</storageModule>
diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
index c7d9cc75..da7dcfe5 100644
--- a/.settings/language.settings.xml
+++ b/.settings/language.settings.xml
@@ -77,4 +77,15 @@
</provider>
</extension>
</configuration>
+ <configuration id="cdt.managedbuild.config.gnu.cross.exe.release.516195201.976458850.241502451.170574622.649587786" name="DuetM_RTOS">
+ <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+ <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+ <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+ <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="1189573167678144698" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
+ <language-scope id="org.eclipse.cdt.core.gcc"/>
+ <language-scope id="org.eclipse.cdt.core.g++"/>
+ </provider>
+ </extension>
+ </configuration>
</project>
diff --git a/src/BugList.txt b/src/BugList.txt
index 9b77d7cc..fdcfa1d3 100644
--- a/src/BugList.txt
+++ b/src/BugList.txt
@@ -97,11 +97,15 @@ Done in 1.21 release:
- [done] configuration and readback of pulse-type filament monitors is wrong
- [done] Terminate WiFi sockets that abort
- [done similar, ok] PR to report actual fan speed
-- DWC Machine properties doesn't show correct state of active low endstops
-- Use machine coordinates when runninng system macros
+- [done] DWC Machine properties doesn't show correct state of active low endstops
+- [done] Use machine coordinates when runninng system macros
+- [done] Axis limits on arc moves
Investigations:
-SCARA https://www.duet3d.com/forum/thread.php?pid=43636#p43636
+[awaiting reply] SCARA https://www.duet3d.com/forum/thread.php?pid=43636#p43636
+[can't reproduce - printing over USB?] Jerky printing https://forum.duet3d.com/topic/4502/jerk-accel-settings-not-working-for-me/38
+BLTouch deploying an extra time, https://www.duet3d.com/forum/thread.php?pid=44891#p44891
+Printer stall, https://forum.duet3d.com/topic/4862/duet-wifi-printer-stalls-stops-no-errors/4
Remaining:
- [done in 2.0] BUG: G1 E5 S1 on delta says "Error: G0/G1: attempt to move delta motors to absolute positions"
@@ -110,12 +114,17 @@ Remaining:
- [done in 2.0, test] M114 to report user coordinates first, https://www.duet3d.com/forum/thread.php?pid=43073#p43073
- [done in 2.0, test] Allow Z jerk down to 0.2mm/sec
- [done in 2.0, ok] BUG: no call to HttpResponder::CheckSessions
-- BUG: G29 height map is way below bed. Happened on Ormerod. When probing the bed with simple G30 and compensation is applied, correct for the height map offset
-- Motor stall detection Z probe. Run deploy/retract macros before/after each probe, as for bltouch, or not?
+- [done in 2.0] Update user coordinates after using G10 to change offsets, https://www.duet3d.com/forum/thread.php?pid=44900#p44900
+- [done in 2.0, test] G2/G3: allow X and Y to be not specified, and I or J not to be specified, see https://www.duet3d.com/forum/thread.php?pid=44915#p44915
+- [done in 2.0, test] BUG: G29 height map is way below bed. Happened on Ormerod. When probing the bed with simple G30 and compensation is applied, correct for the height map offset
+- [done in 2.0] Motor stall detection Z probe. Run deploy/retract macros before/after each probe, as for bltouch, or not?
+- [done in 2.0] Simulation to assume machine starts homed, restore homed status at end
+- [done in 2.0] more changes from chrishamm (multiple spindles, fan map)
+- [no fault] Report workspace coordinates to 2dp not 1dp to DWC (https://www.duet3d.com/forum/thread.php?pid=43789#p43789)
+- [done in 2.0] G0 not to use G1 F parameter, move at machine limits instead (CNC, https://www.duet3d.com/forum/thread.php?pid=43825#p43825)
+
- Unexpected heaters off/tool selection behaviour, https://www.duet3d.com/forum/thread.php?pid=43059#p43059
- warn when using : where ; was probably meant
-- check out G30 H parameter, https://www.duet3d.com/forum/thread.php?pid=42322#p42322
-- another chrishamm change, in his branch
- Error message if you attempt movement with VIN < minimum
- min/max RSSI display?
- save theta, phi in move and then in DDA?
@@ -125,19 +134,17 @@ Remaining:
- Return "Powered down" status when VIN power has never been seen or has gone down after sending M81
- Auto mount main SD card when inserted
- Workplace offsets are supposed to be persistant (check NIST), https://www.duet3d.com/forum/thread.php?pid=43755#p43755
-- [no fault] Report workspace coordinates to 2dp not 1dp to DWC (https://www.duet3d.com/forum/thread.php?pid=43789#p43789)
- At the end of a simulation, restore the original workplace coordinate selection
-- Simulation to assume machine starts homed, restore homed status at end
-- G0 not to use G1 F parameter, move at machine limits instead (CNC, https://www.duet3d.com/forum/thread.php?pid=43825#p43825)
- apostrophe in quoted filename
- looks like we get a Pop underflow message when you send DWC jog commands and axes are not homed
- Add warning message when print exceeds bounds
- Does bltouch need a default recovery time?
- Should bltouch use digital probe mode? Some users having problems with P25 in G31 command.
+- M584 when assigning a drive, unmap any existing assignment. Also allow an axis to be mapped to driver -1.
+- Add S4 option to G1 command, like S1 but no endstop checks (needed for CoreXY, CoreXZ)
-- How should we lift X on a CoreXZ printer before homing?
- if a homing command in an SD print file is aborted due to e.g. G1 Z5 in the homing file, error message should be written to both DWC and PanelDue
-- stall detect on Z axis
+- [no fault] stall detect on Z axis
- Files generated by Cura doesn't detect layer changes, see https://www.duet3d.com/forum/thread.php?pid=40865#p40865
- [re-test using new DuetWiFiServer] "Failed to change mode" messages after M552 S2/S0/S1 cycle
- [can't reproduce] "Attempt to seek on a non-open file", https://www.duet3d.com/forum/thread.php?pid=41175#p41175
@@ -160,21 +167,20 @@ Remaining:
- Add timeout to hsmci_send_cmd_execute, see https://www.duet3d.com/forum/thread.php?pid=35654#p35654
- Bug: pressure advance attempts high speed or acceleration extruder movements on bench setup (was it caused by hitting limits?)
- Bug: https://www.duet3d.com/forum/thread.php?pid=34772#p34772 (needs RRF fix too?)
-- M40 to run eject.g [don't do, not NIST standard]
+- M40 to run eject.g [don't do, not NIST standard?]
- configurable minimum extrusion temperature (per extruder?)
- case-insensitive http headers
-Remaining:
- Send reduce power command to PanelDue when main power turned off?
- Document multiple bed and chamber heaters
-- Check all classes for correct initialisation
+- [mostly done] Check all classes for correct initialisation
- sd_mmc_spi doesn't acquire/release the SPI bus. Need to change this for RTOS.
- If wifi module gets stuck in starting state, reset it again
+- If wifi disconnects when in client mode, keep retrying the connection
Bug investigations:
- [done] step errors, https://www.duet3d.com/forum/thread.php?pid=33741#p33741
-- SeeMeCNC scaling problem, see email of 2018-04-01
-- dual Z motors, https://www.duet3d.com/forum/thread.php?pid=44396#p44396
+- [no fault, possibly related to low extruder steps/mm] SeeMeCNC scaling problem, see email of 2018-04-01
Investigations:
@@ -201,8 +207,8 @@ Later versions:
- Implement G1 S4? (like S2 but always relative)
- Add work coordinates? https://www.duet3d.com/forum/thread.php?pid=27128#p27128
- Don't do pressure advance during accel/decel of sequences of short segments
-- Axis limits on arc moves
- Arc move with same finish and start coordinates to do complete circle
- Add T parameter to M207
- look at supporting SIZE in FTP
- Make mp.delta.hmz0sK, hmz0scK and dsk 64-bit in SAM4E versions, to increase movement limit - also increase K2?
+
diff --git a/src/Configuration.h b/src/Configuration.h
index 89d1555d..4de9d976 100644
--- a/src/Configuration.h
+++ b/src/Configuration.h
@@ -228,6 +228,7 @@ constexpr float FILAMENT_WIDTH = 1.75; // Millimetres
constexpr unsigned int MaxStackDepth = 5; // Maximum depth of stack
// CNC and laser support
+constexpr size_t MaxSpindles = 4; // Maximum number of configurable spindles
constexpr float DefaultMaxSpindleRpm = 10000; // Default spindle RPM at full PWM
constexpr float DefaultMaxLaserPower = 255.0; // Power setting in M3 command for full power
diff --git a/src/Display/ST7920/lcd7920.cpp b/src/Display/ST7920/lcd7920.cpp
index 08efe23f..da560b22 100644
--- a/src/Display/ST7920/lcd7920.cpp
+++ b/src/Display/ST7920/lcd7920.cpp
@@ -3,6 +3,7 @@
#include "RepRapFirmware.h"
#include "Pins.h"
+#include "Tasks.h"
#if SUPPORT_12864_LCD
@@ -537,7 +538,7 @@ void Lcd7920::sendLcdData(uint8_t data)
// Send a command to the lcd. Data1 is sent as-is, data2 is split into 2 bytes, high nibble first.
void Lcd7920::sendLcd(uint8_t data1, uint8_t data2)
{
- sspi_acquire(); // TODO when using RTOS, wait for shared SPI to be available
+ MutexLocker lock(Tasks::GetSpiMutex());
sspi_master_setup_device(&device);
delayMicroseconds(1);
sspi_select_device(&device);
@@ -550,7 +551,6 @@ void Lcd7920::sendLcd(uint8_t data1, uint8_t data2)
delayMicroseconds(1);
sspi_deselect_device(&device);
delayMicroseconds(1);
- sspi_release();
}
void Lcd7920::ensureBasicMode()
diff --git a/src/DuetM/Pins_DuetM.h b/src/DuetM/Pins_DuetM.h
index 0f5cd8ae..23c7dec0 100644
--- a/src/DuetM/Pins_DuetM.h
+++ b/src/DuetM/Pins_DuetM.h
@@ -112,6 +112,7 @@ constexpr float PowerMonitorVoltageRange = 11.0 * 3.3; // We use an 11:1 vo
// Digital pin number to turn the IR LED on (high) or off (low), also controls the DIAG LED
constexpr Pin Z_PROBE_MOD_PIN = 62;
+constexpr Pin DiagPin = Z_PROBE_MOD_PIN;
// Cooling fans
constexpr size_t NUM_FANS = 3;
diff --git a/src/Fan.cpp b/src/Fan.cpp
index 95f26850..c472456f 100644
--- a/src/Fan.cpp
+++ b/src/Fan.cpp
@@ -13,6 +13,7 @@
void Fan::Init(Pin p_pin, bool hwInverted)
{
+ isConfigured = false;
val = lastVal = 0.0;
minVal = 0.1; // 10% minimum fan speed
blipTime = 100; // 100ms fan blip
@@ -129,6 +130,7 @@ bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const Strin
if (seen)
{
+ isConfigured = true;
Refresh();
}
else if (!gb.Seen('R') && !gb.Seen('S'))
diff --git a/src/Fan.h b/src/Fan.h
index 9fb9d9ad..c78d6ff7 100644
--- a/src/Fan.h
+++ b/src/Fan.h
@@ -23,12 +23,14 @@ public:
// If errors were discovered while processing parameters, put an appropriate error message in 'reply' and set 'error' to true.
// If no relevant parameters are found, print the existing ones to 'reply' and return false.
bool Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const StringRef& reply, bool& error);
+ bool IsConfigured() const { return isConfigured && IsEnabled(); }
bool IsEnabled() const { return pin != NoPin; }
float GetConfiguredPwm() const { return val; } // returns the configured PWM. Actual PWM may be different, e.g. due to blipping or for thermostatic fans.
void Init(Pin p_pin, bool hwInverted);
void SetPwm(float speed);
+ bool HasMonitoredHeaters() const { return heatersMonitored != 0; }
void SetHeatersMonitored(HeatersMonitoredBitmap h);
bool Check(); // update the fan PWM returning true if it is a thermostatic fan that is on
void Disable();
@@ -46,6 +48,7 @@ private:
HeatersMonitoredBitmap heatersMonitored;
PwmFrequency freq;
Pin pin;
+ bool isConfigured;
bool inverted;
bool hardwareInverted;
bool blipping;
diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp
index 8877a83a..afdcae81 100644
--- a/src/GCodes/GCodeBuffer.cpp
+++ b/src/GCodes/GCodeBuffer.cpp
@@ -437,7 +437,7 @@ float GCodeBuffer::GetFValue()
{
if (readPointer >= 0)
{
- const float result = strtof(&gcodeBuffer[readPointer + 1], 0);
+ const float result = SafeStrtof(&gcodeBuffer[readPointer + 1], 0);
readPointer = -1;
return result;
}
@@ -453,8 +453,8 @@ const void GCodeBuffer::GetFloatArray(float arr[], size_t& returnedLength, bool
if (readPointer >= 0)
{
size_t length = 0;
- bool inList = true;
- while (inList)
+ const char *p = gcodeBuffer + readPointer + 1;
+ for (;;)
{
if (length >= returnedLength) // array limit has been set in here
{
@@ -463,16 +463,14 @@ const void GCodeBuffer::GetFloatArray(float arr[], size_t& returnedLength, bool
returnedLength = 0;
return;
}
- arr[length] = strtof(&gcodeBuffer[readPointer + 1], 0);
+ const char *q;
+ arr[length] = SafeStrtof(p, &q);
length++;
- do
- {
- readPointer++;
- } while(gcodeBuffer[readPointer] && (gcodeBuffer[readPointer] != ' ') && (gcodeBuffer[readPointer] != LIST_SEPARATOR));
- if (gcodeBuffer[readPointer] != LIST_SEPARATOR)
+ if (*q != LIST_SEPARATOR)
{
- inList = false;
+ break;
}
+ p = q + 1;
}
// Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
@@ -503,8 +501,8 @@ const void GCodeBuffer::GetIntArray(int32_t arr[], size_t& returnedLength, bool
if (readPointer >= 0)
{
size_t length = 0;
- bool inList = true;
- while(inList)
+ const char *p = gcodeBuffer + readPointer + 1;
+ for (;;)
{
if (length >= returnedLength) // Array limit has been set in here
{
@@ -513,16 +511,14 @@ const void GCodeBuffer::GetIntArray(int32_t arr[], size_t& returnedLength, bool
returnedLength = 0;
return;
}
- arr[length] = strtol(&gcodeBuffer[readPointer + 1], 0, 0);
+ const char *q;
+ arr[length] = SafeStrtol(p, &q);
length++;
- do
- {
- readPointer++;
- } while(gcodeBuffer[readPointer] != 0 && (gcodeBuffer[readPointer] != ' ') && (gcodeBuffer[readPointer] != LIST_SEPARATOR));
- if (gcodeBuffer[readPointer] != LIST_SEPARATOR)
+ if (*q != LIST_SEPARATOR)
{
- inList = false;
+ break;
}
+ p = q + 1;
}
// Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
@@ -552,8 +548,8 @@ const void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& returnedLength,
if (readPointer >= 0)
{
size_t length = 0;
- bool inList = true;
- while(inList)
+ const char *p = gcodeBuffer + readPointer + 1;
+ for (;;)
{
if (length >= returnedLength) // Array limit has been set in here
{
@@ -562,16 +558,14 @@ const void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& returnedLength,
returnedLength = 0;
return;
}
- arr[length] = strtoul(&gcodeBuffer[readPointer + 1], 0, 0);
+ const char *q;
+ arr[length] = SafeStrtoul(p, &q);
length++;
- do
- {
- readPointer++;
- } while(gcodeBuffer[readPointer] != 0 && (gcodeBuffer[readPointer] != ' ') && (gcodeBuffer[readPointer] != LIST_SEPARATOR));
- if (gcodeBuffer[readPointer] != LIST_SEPARATOR)
+ if (*q != LIST_SEPARATOR)
{
- inList = false;
+ break;
}
+ p = q + 1;
}
// Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
@@ -703,7 +697,7 @@ int32_t GCodeBuffer::GetIValue()
{
if (readPointer >= 0)
{
- const int32_t result = strtol(&gcodeBuffer[readPointer + 1], 0, 0);
+ const int32_t result = SafeStrtol(&gcodeBuffer[readPointer + 1]);
readPointer = -1;
return result;
}
@@ -717,7 +711,7 @@ uint32_t GCodeBuffer::GetUIValue()
{
if (readPointer >= 0)
{
- const uint32_t result = strtoul(&gcodeBuffer[readPointer + 1], 0, 0);
+ const uint32_t result = SafeStrtoul(&gcodeBuffer[readPointer + 1]);
readPointer = -1;
return result;
}
@@ -815,8 +809,8 @@ bool GCodeBuffer::GetIPAddress(uint8_t ip[4])
unsigned int n = 0;
for (;;)
{
- char *pp;
- const unsigned long v = strtoul(p, &pp, 10);
+ const char *pp;
+ const unsigned long v = SafeStrtoul(p, &pp);
if (pp == p || v > 255)
{
readPointer = -1;
@@ -867,12 +861,12 @@ bool GCodeBuffer::GetMacAddress(uint8_t mac[6])
return false;
}
- const char* p = &gcodeBuffer[readPointer + 1];
+ const char* p = gcodeBuffer + readPointer + 1;
unsigned int n = 0;
for (;;)
{
- char *pp;
- const unsigned long v = strtoul(p, &pp, 16);
+ const char *pp;
+ const unsigned long v = SafeStrtoul(p, &pp, 16);
if (pp == p || v > 255)
{
readPointer = -1;
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 3872a734..73d2af62 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -115,8 +115,6 @@ void GCodes::Init()
isRetracted = false;
lastAuxStatusReportType = -1; // no status reports requested yet
- spindleRpm = 0.0;
- spindleMaxRpm = DefaultMaxSpindleRpm;
laserMaxPower = DefaultMaxLaserPower;
heaterFaultState = HeaterFaultState::noFault;
@@ -872,7 +870,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply)
if (platform.GetZProbeType() == ZProbeType::blTouch)
{
- DoFileMacro(gb, RETRACTPROBE_G, false); // bltouch needs to be retracted whehn it triggers
+ DoFileMacro(gb, RETRACTPROBE_G, false); // bltouch needs to be retracted when it triggers
}
}
break;
@@ -1144,10 +1142,10 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply)
if (tapsDone == 1 && !hadProbingError)
{
// Reset the Z axis origin according to the height error so that we can move back up to the dive height
- moveBuffer.coords[Z_AXIS] -= g30zHeightError;
- g30zHeightError = 0; // there is no zero height error form this probe
+ moveBuffer.coords[Z_AXIS] = platform.ZProbeStopHeight();
reprap.GetMove().SetNewPosition(moveBuffer.coords, false);
- ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition);
+ reprap.GetMove().SetZeroHeightError(moveBuffer.coords);
+ g30zHeightError = 0; // there is no longer any height error from this probe
SetAxisIsHomed(Z_AXIS); // this is only correct if the Z axis is Cartesian-like, but other architectures must be homed before probing anyway
}
}
@@ -1215,6 +1213,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply)
// Setting the Z height with G30
moveBuffer.coords[Z_AXIS] -= g30zHeightError;
reprap.GetMove().SetNewPosition(moveBuffer.coords, false);
+ reprap.GetMove().SetZeroHeightError(moveBuffer.coords);
ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition);
}
gb.AdvanceState();
@@ -1523,6 +1522,7 @@ void GCodes::EndSimulation(GCodeBuffer *gb)
RestorePosition(simulationRestorePoint, gb);
ToolOffsetTransform(currentUserPosition, moveBuffer.coords);
reprap.GetMove().SetNewPosition(simulationRestorePoint.moveCoords, true);
+ axesHomed = axesHomedBeforeSimulation;
}
// Check for and execute triggers
@@ -2108,7 +2108,7 @@ void GCodes::Pop(GCodeBuffer& gb)
// Set up the extrusion and feed rate of a move for the Move class
// 'moveType' is the S parameter in the G0 or G1 command, or zero for a G2 or G3 command
// Returns true if this gcode is valid so far, false if it should be discarded
-bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType)
+bool GCodes::LoadExtrusionFromGCode(GCodeBuffer& gb)
{
// Zero every extruder drive as some drives may not be moved
for (size_t drive = numTotalAxes; drive < DRIVES; drive++)
@@ -2117,16 +2117,6 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType)
}
moveBuffer.hasExtrusion = false;
- // Deal with feed rate
- if (moveType >= 0 && gb.Seen(feedrateLetter))
- {
- const float rate = gb.GetFValue() * distanceScale;
- gb.MachineState().feedrate = (moveType == 0)
- ? rate * speedFactor
- : rate * SecondsToMinutes; // don't apply the speed factor to homing and other special moves
- }
- moveBuffer.feedRate = gb.MachineState().feedrate;
-
// If we are extruding, check that we have a tool to extrude with
if (gb.Seen(extrudeLetter))
{
@@ -2227,6 +2217,20 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType)
return true;
}
+// Set up the feed rate of a move
+// 'moveType' is the S parameter in the G1 command, or zero for a G2 or G3 command
+void GCodes::LoadFeedrateFromGCode(GCodeBuffer& gb)
+{
+ if (moveBuffer.moveType >= 0 && gb.Seen(feedrateLetter))
+ {
+ const float rate = gb.GetFValue() * distanceScale;
+ gb.MachineState().feedrate = (moveBuffer.moveType == 0)
+ ? rate * speedFactor
+ : rate * SecondsToMinutes; // don't apply the speed factor to homing and other special moves
+ }
+ moveBuffer.feedRate = gb.MachineState().feedrate;
+}
+
// Check that enough axes have been homed, returning true if insufficient axes homed
bool GCodes::CheckEnoughAxesHomed(AxesBitmap axesMoved)
{
@@ -2378,9 +2382,17 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated)
}
// Deal with extrusion and feed rate
- LoadExtrusionAndFeedrateFromGCode(gb, moveBuffer.moveType);
+ if (isCoordinated)
+ {
+ LoadExtrusionFromGCode(gb);
+ LoadFeedrateFromGCode(gb);
+ }
+ else
+ {
+ moveBuffer.feedRate = platform.GetMaxTravelAcceleration();
+ }
- // Set up the move. We must assign segmentsLeft last, so that when we move to RTOS, the move won't be picked up by the Move process before it is complete.
+ // Set up the move. We must assign segmentsLeft last, so that when Move runs as a separate task the move won't be picked up by the Move process before it is complete.
// Note that if this is an extruder-only move, we don't do axis movements to allow for tool offset changes, we defer those until an axis moves.
if (moveBuffer.moveType != 0)
{
@@ -2450,16 +2462,55 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated)
// Currently, we do not process new babystepping when executing an arc move
const char* GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise)
{
- // Get the axis parameters. X Y I J are compulsory, Z is optional.
- const char* const missingParameter = "G2/G3: missing parameter";
- if (!gb.Seen('X')) return missingParameter;
- const float xParam = gb.GetFValue() * distanceScale;
- if (!gb.Seen('Y')) return missingParameter;
- const float yParam = gb.GetFValue() * distanceScale;
- if (!gb.Seen('I')) return missingParameter;
- const float iParam = gb.GetFValue() * distanceScale;
- if (!gb.Seen('J')) return missingParameter;
- const float jParam = gb.GetFValue() * distanceScale;
+ // Get the axis parameters
+ float xParam, yParam;
+ bool seenXY = false;
+ if (gb.Seen('X'))
+ {
+ xParam = gb.GetFValue() * distanceScale;
+ seenXY = true;
+ }
+ else
+ {
+ xParam = currentUserPosition[X_AXIS];
+ }
+
+ if (gb.Seen('Y'))
+ {
+ yParam = gb.GetFValue() * distanceScale;
+ seenXY = true;
+ }
+ else
+ {
+ yParam = currentUserPosition[Y_AXIS];
+ }
+
+ float iParam, jParam;
+ bool seenIJ = false;
+ if (gb.Seen('I'))
+ {
+ iParam = gb.GetFValue() * distanceScale;
+ seenIJ = true;
+ }
+ else
+ {
+ iParam = 0.0;
+ }
+
+ if (gb.Seen('J'))
+ {
+ jParam = gb.GetFValue() * distanceScale;
+ seenIJ = true;
+ }
+ else
+ {
+ jParam = 0.0;
+ }
+
+ if (!seenXY && seenIJ) // at least one of XY and IJ must be specified
+ {
+ return "G2/G3: missing parameter";
+ }
memcpy(moveBuffer.initialCoords, moveBuffer.coords, numVisibleAxes * sizeof(moveBuffer.initialCoords[0]));
@@ -2543,7 +2594,9 @@ const char* GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise)
}
}
- LoadExtrusionAndFeedrateFromGCode(gb, moveBuffer.moveType);
+ LoadExtrusionFromGCode(gb);
+ LoadFeedrateFromGCode(gb);
+
moveBuffer.usePressureAdvance = moveBuffer.hasExtrusion;
arcRadius = sqrtf(iParam * iParam + jParam * jParam);
@@ -2921,10 +2974,8 @@ GCodeResult GCodes::ProbeGrid(GCodeBuffer& gb, const StringRef& reply)
return GCodeResult::error;
}
- Move& move = reprap.GetMove();
- move.AccessHeightMap().SetGrid(defaultGrid);
- move.AccessHeightMap().ClearGridHeights();
- move.SetIdentityTransform();
+ reprap.GetMove().AccessHeightMap().SetGrid(defaultGrid);
+ ClearBedMapping();
gridXindex = gridYindex = 0;
gb.SetState(GCodeState::gridProbing1);
@@ -2935,9 +2986,9 @@ GCodeResult GCodes::ProbeGrid(GCodeBuffer& gb, const StringRef& reply)
return GCodeResult::ok;
}
-bool GCodes::LoadHeightMap(GCodeBuffer& gb, const StringRef& reply) const
+GCodeResult GCodes::LoadHeightMap(GCodeBuffer& gb, const StringRef& reply)
{
- reprap.GetMove().SetIdentityTransform(); // stop using old-style bed compensation and clear the height map
+ ClearBedMapping();
String<MaxFilenameLength> heightMapFileName;
bool seen = false;
@@ -2951,24 +3002,23 @@ bool GCodes::LoadHeightMap(GCodeBuffer& gb, const StringRef& reply) const
if (f == nullptr)
{
reply.printf("Height map file %s not found", heightMapFileName.c_str());
- return true;
+ return GCodeResult::error;
}
reply.printf("Failed to load height map from file %s: ", heightMapFileName.c_str()); // set up error message to append to
- HeightMap& heightMap = reprap.GetMove().AccessHeightMap();
- const bool err = heightMap.LoadFromFile(f, reply);
+ const bool err = reprap.GetMove().LoadHeightMapFromFile(f, reply);
f->Close();
- if (err)
- {
- heightMap.ClearGridHeights(); // make sure we don't end up with a partial height map
- }
- else
+ reprap.GetMove().UseMesh(!err);
+
+ if (!err)
{
- reply.Clear(); // wipe the error message
+ reply.Clear(); // wipe the error message
+ // Update the current position to allow for any bed compensation at the current XY coordinates
+ reprap.GetMove().GetCurrentUserPosition(moveBuffer.coords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes());
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // update user coordinates to reflect any height map offset at the current position
}
- reprap.GetMove().UseMesh(!err);
- return err;
+ return (err) ? GCodeResult::error : GCodeResult::ok;
}
// Save the height map and append the success or error message to 'reply', returning true if an error occurred
@@ -2992,7 +3042,7 @@ bool GCodes::SaveHeightMap(GCodeBuffer& gb, const StringRef& reply) const
}
else
{
- err = reprap.GetMove().AccessHeightMap().SaveToFile(f);
+ err = reprap.GetMove().SaveHeightMapToFile(f);
f->Close();
if (err)
{
@@ -3007,6 +3057,13 @@ bool GCodes::SaveHeightMap(GCodeBuffer& gb, const StringRef& reply) const
return err;
}
+// Stop using bed compensation
+void GCodes::ClearBedMapping()
+{
+ reprap.GetMove().SetIdentityTransform();
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // update user coordinates to remove any height map offset there was at the current position
+}
+
// Return the current coordinates as a printable string.
// Coordinates are updated at the end of each movement, so this won't tell you where you are mid-movement.
void GCodes::GetCurrentCoordinates(const StringRef& s) const
@@ -3309,6 +3366,11 @@ GCodeResult GCodes::SetOrReportOffsets(GCodeBuffer &gb, const StringRef& reply)
}
}
+ if (settingOffset)
+ {
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // update user coordinates to reflect the new tool offset, in case we have this tool selected
+ }
+
// Deal with setting temperatures
bool settingTemps = false;
size_t hCount = tool->HeaterCount();
@@ -3924,9 +3986,7 @@ GCodeResult GCodes::SetHeaterParameters(GCodeBuffer& gb, const StringRef& reply)
}
}
- bool hadError = false;
- heat.ConfigureHeaterSensor(305, (unsigned int)heater, gb, reply, hadError);
- return GetGCodeResultFromError(hadError);
+ return heat.ConfigureHeaterSensor(305, (unsigned int)heater, gb, reply);
}
else
{
@@ -4209,7 +4269,10 @@ void GCodes::StopPrint(StopPrintReason reason)
switch (machineType)
{
case MachineType::cnc:
- platform.SetSpindlePwm(0);
+ for (size_t i = 0; i < MaxSpindles; i++)
+ {
+ platform.AccessSpindle(i).TurnOff();
+ }
break;
case MachineType::laser:
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index 9cbe4d5c..dd516481 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -203,8 +203,6 @@ public:
const char *GetAxisLetters() const { return axisLetters; } // Return a null-terminated string of axis letters indexed by drive
- const float GetSpindleRpm() const { return spindleRpm; }
-
#if SUPPORT_12864_LCD
bool ProcessCommandFromLcd(const char *cmd); // Process a GCode command from the 12864 LCD returning true if the command was accepted
#endif
@@ -247,41 +245,42 @@ private:
bool HandleMcode(GCodeBuffer& gb, const StringRef& reply); // Do an M code
bool HandleTcode(GCodeBuffer& gb, const StringRef& reply); // Do a T code
bool HandleResult(GCodeBuffer& gb, GCodeResult rslt, const StringRef& reply);
- void HandleReply(GCodeBuffer& gb, GCodeResult rslt, const char *reply); // Handle G-Code replies
+ void HandleReply(GCodeBuffer& gb, GCodeResult rslt, const char *reply); // Handle G-Code replies
void HandleReply(GCodeBuffer& gb, bool error, OutputBuffer *reply);
const char* DoStraightMove(GCodeBuffer& gb, bool isCoordinated) __attribute__((hot)); // Execute a straight move returning any error message
- const char* DoArcMove(GCodeBuffer& gb, bool clockwise) // Execute an arc move returning any error message
+ const char* DoArcMove(GCodeBuffer& gb, bool clockwise) // Execute an arc move returning any error message
pre(segmentsLeft == 0; resourceOwners[MoveResource] == &gb);
- void FinaliseMove(const GCodeBuffer& gb); // Adjust the move parameters to account for segmentation and/or part of the move having been done already
- bool CheckEnoughAxesHomed(AxesBitmap axesMoved); // Check that enough axes have been homed
- void AbortPrint(GCodeBuffer& gb); // Cancel any print in progress
-
- GCodeResult DoDwell(GCodeBuffer& gb); // Wait for a bit
- GCodeResult DoDwellTime(GCodeBuffer& gb, uint32_t dwellMillis); // Really wait for a bit
- GCodeResult DoHome(GCodeBuffer& gb, const StringRef& reply); // Home some axes
- GCodeResult ExecuteG30(GCodeBuffer& gb, const StringRef& reply); // Probes at a given position - see the comment at the head of the function itself
- void InitialiseTaps(); // Set up to do the first of a possibly multi-tap probe
- void SetBedEquationWithProbe(int sParam, const StringRef& reply); // Probes a series of points and sets the bed equation
+ void FinaliseMove(const GCodeBuffer& gb); // Adjust the move parameters to account for segmentation and/or part of the move having been done already
+ bool CheckEnoughAxesHomed(AxesBitmap axesMoved); // Check that enough axes have been homed
+ void AbortPrint(GCodeBuffer& gb); // Cancel any print in progress
+
+ GCodeResult DoDwell(GCodeBuffer& gb); // Wait for a bit
+ GCodeResult DoDwellTime(GCodeBuffer& gb, uint32_t dwellMillis); // Really wait for a bit
+ GCodeResult DoHome(GCodeBuffer& gb, const StringRef& reply); // Home some axes
+ GCodeResult ExecuteG30(GCodeBuffer& gb, const StringRef& reply); // Probes at a given position - see the comment at the head of the function itself
+ void InitialiseTaps(); // Set up to do the first of a possibly multi-tap probe
+ void SetBedEquationWithProbe(int sParam, const StringRef& reply); // Probes a series of points and sets the bed equation
GCodeResult SetPrintZProbe(GCodeBuffer& gb, const StringRef& reply); // Either return the probe value, or set its threshold
GCodeResult SetOrReportOffsets(GCodeBuffer& gb, const StringRef& reply); // Deal with a G10
- GCodeResult SetPositions(GCodeBuffer& gb); // Deal with a G92
- GCodeResult DoDriveMapping(GCodeBuffer& gb, const StringRef& reply); // Deal with a M584
- GCodeResult ProbeTool(GCodeBuffer& gb, const StringRef& reply); // Deal with a M585
- GCodeResult SetDateTime(GCodeBuffer& gb,const StringRef& reply); // Deal with a M905
- GCodeResult SavePosition(GCodeBuffer& gb,const StringRef& reply); // Deal with G60
-
- bool LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, int moveType); // Set up the extrusion and feed rate of a move for the Move class
-
- bool Push(GCodeBuffer& gb); // Push feedrate etc on the stack
- void Pop(GCodeBuffer& gb); // Pop feedrate etc
- void DisableDrives(); // Turn the motors off
+ GCodeResult SetPositions(GCodeBuffer& gb); // Deal with a G92
+ GCodeResult DoDriveMapping(GCodeBuffer& gb, const StringRef& reply); // Deal with a M584
+ GCodeResult ProbeTool(GCodeBuffer& gb, const StringRef& reply); // Deal with a M585
+ GCodeResult SetDateTime(GCodeBuffer& gb,const StringRef& reply); // Deal with a M905
+ GCodeResult SavePosition(GCodeBuffer& gb,const StringRef& reply); // Deal with G60
+
+ bool LoadExtrusionFromGCode(GCodeBuffer& gb); // Set up the extrusion of a move
+ void LoadFeedrateFromGCode(GCodeBuffer& gb); // Set up the feed rate of a move
+
+ bool Push(GCodeBuffer& gb); // Push feedrate etc on the stack
+ void Pop(GCodeBuffer& gb); // Pop feedrate etc
+ void DisableDrives(); // Turn the motors off
bool OpenFileToWrite(GCodeBuffer& gb, const char* directory, const char* fileName, const FilePosition size, const bool binaryWrite, const uint32_t fileCRC32);
- // Start saving GCodes in a file
- void FinishWrite(GCodeBuffer& gb); // Finish writing to the file and respond
- bool SendConfigToLine(); // Deal with M503
+ // Start saving GCodes in a file
+ void FinishWrite(GCodeBuffer& gb); // Finish writing to the file and respond
+ bool SendConfigToLine(); // Deal with M503
- GCodeResult OffsetAxes(GCodeBuffer& gb); // Set offsets
+ GCodeResult OffsetAxes(GCodeBuffer& gb); // Set offsets
#if SUPPORT_WORKPLACE_COORDINATES
GCodeResult GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& reply, bool compute); // Set workspace coordinates
@@ -328,13 +327,16 @@ private:
GCodeResult SetOrReportZProbe(GCodeBuffer& gb, const StringRef &reply); // Handle M558
GCodeResult DefineGrid(GCodeBuffer& gb, const StringRef &reply); // Define the probing grid, returning true if error
- bool LoadHeightMap(GCodeBuffer& gb, const StringRef& reply) const; // Load the height map from file
+ GCodeResult LoadHeightMap(GCodeBuffer& gb, const StringRef& reply); // Load the height map from file
bool SaveHeightMap(GCodeBuffer& gb, const StringRef& reply) const; // Save the height map to file
+ void ClearBedMapping(); // Stop using bed compensation
GCodeResult ProbeGrid(GCodeBuffer& gb, const StringRef& reply); // Start probing the grid, returning true if we didn't because of an error
GCodeResult CheckOrConfigureTrigger(GCodeBuffer& gb, const StringRef& reply, int code); // Handle M581 and M582
GCodeResult UpdateFirmware(GCodeBuffer& gb, const StringRef &reply); // Handle M997
GCodeResult SendI2c(GCodeBuffer& gb, const StringRef &reply); // Handle M260
GCodeResult ReceiveI2c(GCodeBuffer& gb, const StringRef &reply); // Handle M261
+ GCodeResult SimulateFile(GCodeBuffer& gb, const StringRef &reply, const StringRef& file); // Handle M37 to simulate a whole file
+ GCodeResult ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, uint32_t newSimulationMode); // handle M37 to change the simulation mode
GCodeResult WriteConfigOverrideFile(GCodeBuffer& gb, const StringRef& reply) const; // Write the config-override file
void CopyConfigFinalValues(GCodeBuffer& gb); // Copy the feed rate etc. from the daemon to the input channels
@@ -421,6 +423,7 @@ private:
bool doingArcMove;
bool abortedArcMove;
+ AxesBitmap axesHomedBeforeSimulation; // axes that were homed when we started the simulation
RestorePoint simulationRestorePoint; // The position and feed rate when we started a simulation
RestorePoint numberedRestorePoints[NumRestorePoints]; // Restore points accessible using the R parameter in the G0/G1 command
@@ -521,9 +524,7 @@ private:
FilamentSensorStatus lastFilamentError;
size_t lastFilamentErrorExtruder;
- // CNC and laser
- float spindleRpm;
- float spindleMaxRpm;
+ // Laser
float laserMaxPower;
// Heater fault handler
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index 7ffafebf..01a694a8 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -225,11 +225,11 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply)
break;
case 1: // load height map file
- result = GetGCodeResultFromError(LoadHeightMap(gb, reply));
+ result = LoadHeightMap(gb, reply);
break;
default: // clear height map
- reprap.GetMove().SetIdentityTransform();
+ ClearBedMapping();
break;
}
}
@@ -394,8 +394,19 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
switch (machineType)
{
case MachineType::cnc:
- spindleRpm = gb.GetFValue();
- platform.SetSpindlePwm(spindleRpm/spindleMaxRpm);
+ {
+ const float rpm = gb.GetFValue();
+ const uint32_t slot = gb.Seen('P') ? gb.GetUIValue() : 0;
+ if (slot >= MaxSpindles)
+ {
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ }
+ else
+ {
+ platform.AccessSpindle(slot).SetRpm(rpm);
+ }
+ }
break;
case MachineType::laser:
@@ -423,7 +434,17 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
{
if (machineType == MachineType::cnc)
{
- platform.SetSpindlePwm(-gb.GetFValue()/spindleMaxRpm);
+ const float rpm = gb.GetFValue();
+ const uint32_t slot = gb.Seen('P') ? gb.GetUIValue() : 0;
+ if (slot >= MaxSpindles)
+ {
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ }
+ else
+ {
+ platform.AccessSpindle(slot).SetRpm(-rpm);
+ }
}
else
{
@@ -436,7 +457,28 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
switch (machineType)
{
case MachineType::cnc:
- platform.SetSpindlePwm(0.0);
+ if (gb.Seen('P'))
+ {
+ // Turn off specific spindle
+ const uint32_t slot = gb.GetUIValue();
+ if (slot >= MaxSpindles)
+ {
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ }
+ else
+ {
+ platform.AccessSpindle(slot).TurnOff();
+ }
+ }
+ else
+ {
+ // Turn off every spindle if no 'P' parameter is present
+ for (size_t i = 0; i < MaxSpindles; i++)
+ {
+ platform.AccessSpindle(i).TurnOff();
+ }
+ }
break;
case MachineType::laser:
@@ -859,78 +901,27 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
case 37: // Simulation mode on/off, or simulate a whole file
{
bool seen = false;
- uint32_t newSimulationMode;
String<MaxFilenameLength> simFileName;
gb.TryGetPossiblyQuotedString('P', simFileName.GetRef(), seen);
if (seen)
{
- newSimulationMode = 1; // default to simulation mode 1 when a filename is given
+ result = SimulateFile(gb, reply, simFileName.GetRef());
}
else
{
+ uint32_t newSimulationMode;
gb.TryGetUIValue('S', newSimulationMode, seen);
- }
-
- if (seen && newSimulationMode != simulationMode)
- {
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
-
- const bool wasSimulating = (simulationMode != 0);
- simulationMode = (uint8_t)newSimulationMode;
- reprap.GetMove().Simulate(simulationMode);
- if (simFileName.IsEmpty() || simulationMode == 0)
+ if (seen)
{
- // It's a simulation mode change command
- exitSimulationWhenFileComplete = false;
- if (simulationMode != 0)
- {
- simulationTime = 0.0;
- if (!wasSimulating)
- {
- // Starting a new simulation, so save the current position
- reprap.GetMove().GetCurrentUserPosition(simulationRestorePoint.moveCoords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes());
- simulationRestorePoint.feedRate = gb.MachineState().feedrate;
- }
- }
- else if (wasSimulating)
- {
- EndSimulation(&gb);
- }
+ result = ChangeSimulationMode(gb, reply, newSimulationMode);
}
else
{
- // Simulate a whole file and then stop simulating
- simulationTime = 0.0;
- if (!wasSimulating)
- {
- // Starting a new simulation, so save the current position
- reprap.GetMove().GetCurrentUserPosition(simulationRestorePoint.moveCoords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes());
- simulationRestorePoint.feedRate = gb.MachineState().feedrate;
- }
- if (QueueFileToPrint(simFileName.c_str(), reply))
- {
- exitSimulationWhenFileComplete = true;
- reprap.GetPrintMonitor().StartingPrint(simFileName.c_str());
- StartPrinting(true);
- reply.printf("Simulating print of file %s", simFileName.c_str());
- }
- else
- {
- simulationMode = 0;
- reprap.GetMove().Simulate(0);
- result = GCodeResult::error;
- }
+ reply.printf("Simulation mode: %s, move time: %.1f sec, other time: %.1f sec",
+ (simulationMode != 0) ? "on" : "off", (double)reprap.GetMove().GetSimulationTime(), (double)simulationTime);
}
}
- else
- {
- reply.printf("Simulation mode: %s, move time: %.1f sec, other time: %.1f sec",
- (simulationMode != 0) ? "on" : "off", (double)reprap.GetMove().GetSimulationTime(), (double)simulationTime);
- }
}
break;
@@ -2443,7 +2434,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
{
return false;
}
- result = GetGCodeResultFromError(LoadHeightMap(gb, reply));
+ result = LoadHeightMap(gb, reply);
break;
case 376: // Set taper height
@@ -2568,38 +2559,55 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
case 453: // Select CNC mode
- machineType = MachineType::cnc;
- if (gb.Seen('P'))
{
- uint32_t pins[2] = { NoLogicalPin, NoLogicalPin };
- size_t numPins = 2;
- gb.GetUnsignedArray(pins, numPins, false);
- if (pins[0] > 65535)
+ uint32_t slot = gb.Seen('S') ? gb.GetUIValue() : 0;
+ if (slot >= MaxSpindles)
{
- pins[0] = NoLogicalPin;
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ break;
}
- if (numPins < 2 || pins[1] < 0 || pins[1] > 65535)
+
+ Spindle& spindle = platform.AccessSpindle(slot);
+ if (gb.Seen('P'))
{
- pins[1] = NoLogicalPin;
+ uint32_t pins[2] = { NoLogicalPin, NoLogicalPin };
+ size_t numPins = 2;
+ gb.GetUnsignedArray(pins, numPins, false);
+ if (pins[0] > 65535)
+ {
+ pins[0] = NoLogicalPin;
+ }
+ if (numPins < 2 || pins[1] < 0 || pins[1] > 65535)
+ {
+ pins[1] = NoLogicalPin;
+ }
+ const bool invert = (gb.Seen('I') && gb.GetIValue() > 0);
+ if (!spindle.SetPins(pins[0], pins[1], invert))
+ {
+ reply.copy("Bad P parameter");
+ result = GCodeResult::error;
+ break;
+ }
}
- const bool invert = (gb.Seen('I') && gb.GetIValue() > 0);
- if (platform.SetSpindlePins(pins[0], pins[1], invert))
+ if (gb.Seen('F'))
{
- reply.copy("CNC mode selected");
+ spindle.SetPwmFrequency(gb.GetFValue());
}
- else
+ if (gb.Seen('R'))
{
- reply.copy("Bad P parameter");
- result = GCodeResult::error;
+ spindle.SetMaxRpm(max<float>(1.0, gb.GetFValue()));
+ }
+ if (gb.Seen('T'))
+ {
+ spindle.SetToolNumber(gb.GetIValue());
+ }
+
+ if (machineType != MachineType::cnc)
+ {
+ machineType = MachineType::cnc;
+ reply.copy("CNC mode selected");
}
- }
- if (result == GCodeResult::ok && gb.Seen('F'))
- {
- platform.SetSpindlePwmFrequency(gb.GetFValue());
- }
- if (result == GCodeResult::ok && gb.Seen('R'))
- {
- spindleMaxRpm = max<float>(1.0, gb.GetFValue());
}
break;
@@ -2927,7 +2935,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
case 561: // Set identity transform (also clears bed probe grid)
- reprap.GetMove().SetIdentityTransform();
+ ClearBedMapping();
break;
case 562: // Reset temperature fault - use with great caution
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index 1575faf8..3d300246 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -13,6 +13,7 @@
#include "Movement/Move.h"
#include "RepRap.h"
#include "Tools/Tool.h"
+#include "PrintMonitor.h"
#if HAS_WIFI_NETWORKING
# include "FirmwareUpdater.h"
@@ -335,6 +336,70 @@ GCodeResult GCodes::DefineGrid(GCodeBuffer& gb, const StringRef &reply)
return GCodeResult::error;
}
+// Handle M37 to simulate a whole file
+GCodeResult GCodes::SimulateFile(GCodeBuffer& gb, const StringRef &reply, const StringRef& file)
+{
+ if (reprap.GetPrintMonitor().IsPrinting())
+ {
+ reply.copy("cannot simulate while a file is being printed");
+ return GCodeResult::error;
+ }
+
+ if (QueueFileToPrint(file.c_str(), reply))
+ {
+ if (simulationMode == 0)
+ {
+ axesHomedBeforeSimulation = axesHomed;
+ axesHomed = LowestNBits<AxesBitmap>(numVisibleAxes); // pretend all axes are homed
+ reprap.GetMove().GetCurrentUserPosition(simulationRestorePoint.moveCoords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes());
+ simulationRestorePoint.feedRate = gb.MachineState().feedrate;
+ }
+ simulationTime = 0.0;
+ exitSimulationWhenFileComplete = true;
+ simulationMode = 1;
+ reprap.GetMove().Simulate(simulationMode);
+ reprap.GetPrintMonitor().StartingPrint(file.c_str());
+ StartPrinting(true);
+ reply.printf("Simulating print of file %s", file.c_str());
+ return GCodeResult::ok;
+ }
+
+ return GCodeResult::error;
+}
+
+// handle M37 to change the simulation mode
+GCodeResult GCodes::ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, uint32_t newSimulationMode)
+{
+ if (newSimulationMode != simulationMode)
+ {
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return GCodeResult::notFinished;
+ }
+
+ if (newSimulationMode == 0)
+ {
+ EndSimulation(&gb);
+ }
+ else
+ {
+ if (simulationMode == 0)
+ {
+ // Starting a new simulation, so save the current position
+ axesHomedBeforeSimulation = axesHomed;
+ axesHomed = LowestNBits<AxesBitmap>(numVisibleAxes); // pretend all axes are homed
+ reprap.GetMove().GetCurrentUserPosition(simulationRestorePoint.moveCoords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes());
+ simulationRestorePoint.feedRate = gb.MachineState().feedrate;
+ }
+ simulationTime = 0.0;
+ }
+ exitSimulationWhenFileComplete = false;
+ simulationMode = (uint8_t)newSimulationMode;
+ reprap.GetMove().Simulate(simulationMode);
+ }
+ return GCodeResult::ok;
+}
+
// Handle M558
GCodeResult GCodes::SetOrReportZProbe(GCodeBuffer& gb, const StringRef &reply)
{
diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp
index 9db52383..4d803c9c 100644
--- a/src/Heating/Heat.cpp
+++ b/src/Heating/Heat.cpp
@@ -577,17 +577,16 @@ bool Heat::SetHeaterChannel(size_t heater, int channel)
}
// Configure the temperature sensor for a channel
-bool Heat::ConfigureHeaterSensor(unsigned int mcode, size_t heater, GCodeBuffer& gb, const StringRef& reply, bool& error)
+GCodeResult Heat::ConfigureHeaterSensor(unsigned int mcode, size_t heater, GCodeBuffer& gb, const StringRef& reply)
{
TemperatureSensor ** const spp = GetSensor(heater);
if (spp == nullptr || *spp == nullptr)
{
reply.printf("heater %d is not configured", heater);
- error = true;
- return false;
+ return GCodeResult::error;
}
- return (*spp)->Configure(mcode, heater, gb, reply, error);
+ return (*spp)->Configure(mcode, heater, gb, reply);
}
// Get a pointer to the temperature sensor entry, or nullptr if the heater number is bad
diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h
index 620987de..e813f821 100644
--- a/src/Heating/Heat.h
+++ b/src/Heating/Heat.h
@@ -28,6 +28,7 @@ Licence: GPL
#include "RepRapFirmware.h"
#include "Pid.h"
#include "MessageType.h"
+#include "GCodes/GCodeResult.h"
class TemperatureSensor;
class HeaterProtection;
@@ -127,7 +128,7 @@ public:
int GetHeaterChannel(size_t heater) const; // Return the channel used by a particular heater, or -1 if not configured
bool SetHeaterChannel(size_t heater, int channel); // Set the channel used by a heater, returning true if bad heater or channel number
- bool ConfigureHeaterSensor(size_t heater, unsigned int mcode, GCodeBuffer& gb, const StringRef& reply, bool& error); // Configure the temperature sensor for a channel
+ GCodeResult ConfigureHeaterSensor(size_t heater, unsigned int mcode, GCodeBuffer& gb, const StringRef& reply); // Configure the temperature sensor for a channel
const char *GetHeaterName(size_t heater) const; // Get the name of a heater, or nullptr if it hasn't been named
HeaterProtection& AccessHeaterProtection(size_t index) const; // Return the protection parameters of the given index
diff --git a/src/Heating/Sensors/CurrentLoopTemperatureSensor.cpp b/src/Heating/Sensors/CurrentLoopTemperatureSensor.cpp
index dec51ba3..98e59374 100644
--- a/src/Heating/Sensors/CurrentLoopTemperatureSensor.cpp
+++ b/src/Heating/Sensors/CurrentLoopTemperatureSensor.cpp
@@ -49,7 +49,7 @@ void CurrentLoopTemperatureSensor::Init()
}
// Configure this temperature sensor
-bool CurrentLoopTemperatureSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error)
+GCodeResult CurrentLoopTemperatureSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply)
{
if (mCode == 305)
{
@@ -68,7 +68,7 @@ bool CurrentLoopTemperatureSensor::Configure(unsigned int mCode, unsigned int he
reply.catf(", temperature range %.1f to %.1fC", (double)tempAt4mA, (double)tempAt20mA);
}
}
- return false;
+ return GCodeResult::ok;
}
TemperatureError CurrentLoopTemperatureSensor::GetTemperature(float& t)
diff --git a/src/Heating/Sensors/CurrentLoopTemperatureSensor.h b/src/Heating/Sensors/CurrentLoopTemperatureSensor.h
index 79e67978..24c51e5a 100644
--- a/src/Heating/Sensors/CurrentLoopTemperatureSensor.h
+++ b/src/Heating/Sensors/CurrentLoopTemperatureSensor.h
@@ -14,7 +14,7 @@ class CurrentLoopTemperatureSensor : public SpiTemperatureSensor
{
public:
CurrentLoopTemperatureSensor(unsigned int channel);
- bool Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error) override;
+ GCodeResult Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply) override;
void Init() override;
TemperatureError GetTemperature(float& t) override;
diff --git a/src/Heating/Sensors/DhtSensor.cpp b/src/Heating/Sensors/DhtSensor.cpp
index 49e99d65..dec683cf 100644
--- a/src/Heating/Sensors/DhtSensor.cpp
+++ b/src/Heating/Sensors/DhtSensor.cpp
@@ -38,8 +38,9 @@ DhtSensor::~DhtSensor()
numInstances--;
}
-bool DhtSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error)
+GCodeResult DhtSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply)
{
+ GCodeResult rslt = GCodeResult::ok;
if (mCode == 305)
{
bool seen = false;
@@ -62,8 +63,8 @@ bool DhtSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer&
type = DhtSensorType::Dht22;
break;
default:
- error = true;
reply.copy("Invalid DHT sensor type");
+ rslt = GCodeResult::error;
break;
}
}
@@ -91,7 +92,7 @@ bool DhtSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer&
reply.catf(", sensor type %s", sensorTypeString);
}
}
- return false;
+ return rslt;
}
void DhtSensor::Init()
diff --git a/src/Heating/Sensors/DhtSensor.h b/src/Heating/Sensors/DhtSensor.h
index cd02e64e..ad748ee1 100644
--- a/src/Heating/Sensors/DhtSensor.h
+++ b/src/Heating/Sensors/DhtSensor.h
@@ -29,7 +29,7 @@ public:
DhtSensor(unsigned int channel);
~DhtSensor();
- bool Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error) override;
+ GCodeResult Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply) override;
void Init() override;
TemperatureError GetTemperature(float& t) override;
diff --git a/src/Heating/Sensors/RtdSensor31865.cpp b/src/Heating/Sensors/RtdSensor31865.cpp
index 7c3077de..fba74178 100644
--- a/src/Heating/Sensors/RtdSensor31865.cpp
+++ b/src/Heating/Sensors/RtdSensor31865.cpp
@@ -42,7 +42,7 @@ RtdSensor31865::RtdSensor31865(unsigned int channel)
}
// Configure this temperature sensor
-bool RtdSensor31865::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error)
+GCodeResult RtdSensor31865::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply)
{
if (mCode == 305)
{
@@ -86,7 +86,7 @@ bool RtdSensor31865::Configure(unsigned int mCode, unsigned int heater, GCodeBuf
reply.catf(", %s wires, reject %dHz, reference resistor %u ohms", (cr0 & 0x10) ? "3" : "2/4", (cr0 & 0x01) ? 50 : 60, (unsigned int)rref);
}
}
- return false;
+ return GCodeResult::ok;
}
// Perform the actual hardware initialization for attaching and using this device on the SPI hardware bus.
diff --git a/src/Heating/Sensors/RtdSensor31865.h b/src/Heating/Sensors/RtdSensor31865.h
index 81b343b7..316007d4 100644
--- a/src/Heating/Sensors/RtdSensor31865.h
+++ b/src/Heating/Sensors/RtdSensor31865.h
@@ -14,7 +14,7 @@ class RtdSensor31865 : public SpiTemperatureSensor
{
public:
RtdSensor31865(unsigned int channel);
- bool Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error) override;
+ GCodeResult Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply) override;
void Init() override;
TemperatureError GetTemperature(float& t) override;
diff --git a/src/Heating/Sensors/TemperatureSensor.cpp b/src/Heating/Sensors/TemperatureSensor.cpp
index 37e100aa..04815119 100644
--- a/src/Heating/Sensors/TemperatureSensor.cpp
+++ b/src/Heating/Sensors/TemperatureSensor.cpp
@@ -44,7 +44,7 @@ void TemperatureSensor::SetHeaterName(const char *newName)
}
// Default implementation of Configure, for sensors that have no configurable parameters
-bool TemperatureSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error)
+GCodeResult TemperatureSensor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply)
{
bool seen = false;
if (mCode == 305)
@@ -56,7 +56,7 @@ bool TemperatureSensor::Configure(unsigned int mCode, unsigned int heater, GCode
CopyBasicHeaterDetails(heater, reply);
}
}
- return seen;
+ return GCodeResult::ok;
}
void TemperatureSensor::CopyBasicHeaterDetails(unsigned int heater, const StringRef& reply) const
diff --git a/src/Heating/Sensors/TemperatureSensor.h b/src/Heating/Sensors/TemperatureSensor.h
index bd14618c..fdb04775 100644
--- a/src/Heating/Sensors/TemperatureSensor.h
+++ b/src/Heating/Sensors/TemperatureSensor.h
@@ -3,6 +3,7 @@
#include "RepRapFirmware.h"
#include "Heating/TemperatureError.h" // for result codes
+#include "GCodes/GCodeResult.h"
class GCodeBuffer;
@@ -14,7 +15,7 @@ public:
// Configure the sensor from M305 parameters.
// If we find any parameters, process them and return true. If an error occurs while processing them, set 'error' to true and write an error message to 'reply.
// if we find no relevant parameters, report the current parameters to 'reply' and return 'false'.
- virtual bool Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error);
+ virtual GCodeResult Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply);
// Initialise or re-initialise the temperature sensor
virtual void Init() = 0;
diff --git a/src/Heating/Sensors/Thermistor.cpp b/src/Heating/Sensors/Thermistor.cpp
index cccd2c1f..009a5402 100644
--- a/src/Heating/Sensors/Thermistor.cpp
+++ b/src/Heating/Sensors/Thermistor.cpp
@@ -39,7 +39,7 @@ void Thermistor::Init()
}
// Configure the temperature sensor
-bool Thermistor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error)
+GCodeResult Thermistor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply)
{
bool seen = false;
if (mCode == 305)
@@ -93,7 +93,7 @@ bool Thermistor::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer&
}
}
- return seen;
+ return GCodeResult::ok;
}
// Get the temperature
diff --git a/src/Heating/Sensors/Thermistor.h b/src/Heating/Sensors/Thermistor.h
index e2081f3a..e733417e 100644
--- a/src/Heating/Sensors/Thermistor.h
+++ b/src/Heating/Sensors/Thermistor.h
@@ -22,7 +22,7 @@ class Thermistor : public TemperatureSensor
{
public:
Thermistor(unsigned int channel, bool p_isPT1000); // create an instance with default values
- bool Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error) override; // configure the sensor from M305 parameters
+ GCodeResult Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply) override; // configure the sensor from M305 parameters
void Init() override;
TemperatureError GetTemperature(float& t) override;
diff --git a/src/Heating/Sensors/ThermocoupleSensor31856.cpp b/src/Heating/Sensors/ThermocoupleSensor31856.cpp
index 118415f6..97b66269 100644
--- a/src/Heating/Sensors/ThermocoupleSensor31856.cpp
+++ b/src/Heating/Sensors/ThermocoupleSensor31856.cpp
@@ -60,7 +60,7 @@ ThermocoupleSensor31856::ThermocoupleSensor31856(unsigned int channel)
}
// Configure this temperature sensor
-bool ThermocoupleSensor31856::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error)
+GCodeResult ThermocoupleSensor31856::Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply)
{
if (mCode == 305)
{
@@ -90,7 +90,7 @@ bool ThermocoupleSensor31856::Configure(unsigned int mCode, unsigned int heater,
else
{
reply.copy("Bad thermocouple type letter in M305 command");
- return true;
+ return GCodeResult::error;
}
}
@@ -100,7 +100,7 @@ bool ThermocoupleSensor31856::Configure(unsigned int mCode, unsigned int heater,
reply.catf(", thermocouple type %c, reject %dHz", TypeLetters[thermocoupleType], (cr0 & 0x01) ? 50 : 60);
}
}
- return false;
+ return GCodeResult::ok;
}
// Perform the actual hardware initialization for attaching and using this device on the SPI hardware bus.
diff --git a/src/Heating/Sensors/ThermocoupleSensor31856.h b/src/Heating/Sensors/ThermocoupleSensor31856.h
index 09b61baf..777e9f02 100644
--- a/src/Heating/Sensors/ThermocoupleSensor31856.h
+++ b/src/Heating/Sensors/ThermocoupleSensor31856.h
@@ -14,7 +14,7 @@ class ThermocoupleSensor31856 : public SpiTemperatureSensor
{
public:
ThermocoupleSensor31856(unsigned int channel);
- bool Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply, bool& error) override;
+ GCodeResult Configure(unsigned int mCode, unsigned int heater, GCodeBuffer& gb, const StringRef& reply) override;
void Init() override;
TemperatureError GetTemperature(float& t) override;
diff --git a/src/Libraries/General/IP4String.cpp b/src/Libraries/General/IP4String.cpp
index 722e5fa2..c085f089 100644
--- a/src/Libraries/General/IP4String.cpp
+++ b/src/Libraries/General/IP4String.cpp
@@ -7,6 +7,7 @@
#include "IP4String.h"
#include "StringRef.h"
+#include "SafeVsnprintf.h"
IP4String::IP4String(const uint8_t ip[4])
{
diff --git a/src/Libraries/General/strtod.cpp b/src/Libraries/General/SafeStrtod.cpp
index 8cc7b963..c1eb03cc 100644
--- a/src/Libraries/General/strtod.cpp
+++ b/src/Libraries/General/SafeStrtod.cpp
@@ -18,8 +18,14 @@
#include <cmath>
#include <climits>
-extern "C" double strtod(const char *s, char **p)
+double SafeStrtod(const char *s, const char **p)
{
+ // 0. Skip white space
+ while (*s == ' ' || *s == '\t')
+ {
+ ++s;
+ }
+
// 1. Check for a sign
const bool negative = (*s == '-');
if (negative || *s == '+')
@@ -121,15 +127,9 @@ extern "C" double strtod(const char *s, char **p)
return (negative) ? -retvalue : retvalue;
}
-extern "C" float strtof(const char *s, char **p)
-{
- return (float)strtod(s, p);
-}
-
-// We need to define this one too because it is called internally, probably by sscanf
-extern "C" double _strtod_r(struct _reent *r, const char *s, char **p)
+float SafeStrtof(const char *s, const char **p)
{
- return strtod(s, p);
+ return (float)SafeStrtod(s, p);
}
// End
diff --git a/src/Libraries/General/SafeStrtod.h b/src/Libraries/General/SafeStrtod.h
new file mode 100644
index 00000000..0d4e222d
--- /dev/null
+++ b/src/Libraries/General/SafeStrtod.h
@@ -0,0 +1,30 @@
+/*
+ * SafeStrtod.h
+ *
+ * Created on: 8 Apr 2018
+ * Author: David
+ */
+
+#ifndef SRC_LIBRARIES_GENERAL_SAFESTRTOD_H_
+#define SRC_LIBRARIES_GENERAL_SAFESTRTOD_H_
+
+double SafeStrtod(const char *s, const char **p = nullptr);
+float SafeStrtof(const char *s, const char **p = nullptr);
+
+inline long SafeStrtol(const char *s, const char **endptr = nullptr, int base = 10)
+{
+ return strtol(s, const_cast<char**>(endptr), base);
+}
+
+inline unsigned long SafeStrtoul(const char *s, const char **endptr = nullptr, int base = 10)
+{
+ return strtoul(s, const_cast<char**>(endptr), base);
+}
+
+#define strtod(s, p) Do_not_use_strtod_use_SafeStrtod_instead
+#define strtof(s, p) Do_not_use_strtof_use_SafeStrtof_instead
+#define strtol(s, ...) Do_not_use_strtol_use_SafeStrtol_instead
+#define strtoul(s, ...) Do_not_use_strtoul_use_SafeStrtoul_instead
+#define atof(s) Do_not_use_atof_use_SafeStrtof_instead
+
+#endif /* SRC_LIBRARIES_GENERAL_SAFESTRTOD_H_ */
diff --git a/src/Libraries/General/SafeVsnprintf.cpp b/src/Libraries/General/SafeVsnprintf.cpp
new file mode 100644
index 00000000..fb153f88
--- /dev/null
+++ b/src/Libraries/General/SafeVsnprintf.cpp
@@ -0,0 +1,636 @@
+/*
+ * vsnprintf.cpp
+ *
+ * Created on: 8 Apr 2018
+
+ Original copyright 2001, 2002 Georges Menie (www.menie.org)
+ stdarg version contributed by Christian Ettinger
+ Converted to C++ and adapted to support floating point formats by D. Crocker
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ Changes for the FreeRTOS ports:
+
+ - The dot in "%-8.8s"
+ - The specifiers 'l' (long) and 'L' (long long)
+ - The specifier 'u' for unsigned
+ - Dot notation for IP addresses:
+ sprintf("IP = %xip\n", 0xC0A80164);
+ will produce "IP = 192.168.1.100\n"
+ sprintf("IP = %pip\n", pxIPv6_Address);
+*/
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <climits>
+#include <cmath>
+
+// The following should be enough for 32-bit int/long and 64-bit long long
+constexpr size_t MaxLongDigits = 10; // to print 4294967296
+constexpr size_t MaxUllDigits = 20; // to print 18446744073709551616
+
+struct xPrintFlags
+{
+ int base;
+ int width;
+ int printLimit;
+ unsigned int
+ letBase : 8,
+ padZero : 1,
+ padRight : 1,
+ isSigned : 1,
+ isNumber : 1,
+ isString : 1,
+ long32 : 1,
+ long64 : 1;
+};
+
+struct SStringBuf
+{
+ char *str;
+ const char *orgStr;
+ const char *nulPos;
+ int curLen;
+ struct xPrintFlags flags;
+
+ SStringBuf(char *s, size_t maxLen);
+ void Init();
+};
+
+SStringBuf::SStringBuf(char *apBuf, size_t maxLen)
+{
+ str = apBuf;
+ orgStr = apBuf;
+ nulPos = apBuf + maxLen - 1;
+ curLen = 0;
+ Init();
+}
+
+void SStringBuf::Init()
+{
+ memset(&flags, 0, sizeof(flags));
+}
+
+/*-----------------------------------------------------------*/
+
+// Store the specified character in the string buffer.
+// If it won't fit leaving room for a null, store a null and return false.
+// If it is null, store it and return false.
+// Else store it and return true.
+static bool strbuf_printchar(SStringBuf& apStr, char c)
+{
+ if (c != 0 && apStr.str < apStr.nulPos)
+ {
+ *apStr.str++ = c;
+ apStr.curLen++;
+ return true;
+ }
+ *apStr.str = '\0';
+ return false;
+}
+
+/*-----------------------------------------------------------*/
+
+// Print the string s to the string buffer adding any necessary padding
+static bool prints(SStringBuf& apBuf, const char *apString )
+{
+ int count;
+ if (apBuf.flags.printLimit > 0 && apBuf.flags.isString)
+ {
+ // It's a string so printLimit is the max number of characters to print from the string.
+ // Don't call strlen on it because it might not be null terminated.
+ count = 0;
+ for (const char *s = apString; count < apBuf.flags.printLimit && *s != 0; ++s)
+ {
+ ++count;
+ }
+ }
+ else
+ {
+ count = (int)strlen(apString);
+ }
+
+ int rightSpacesNeeded = 0;
+ const bool hasMinimumDigits = (apBuf.flags.isNumber && apBuf.flags.printLimit > 0);
+ if (hasMinimumDigits || apBuf.flags.width > 0)
+ {
+ // We may have some padding to do
+ int leftSpacesNeeded = 0, leftZerosNeeded = 0;
+ if (hasMinimumDigits && count < apBuf.flags.printLimit)
+ {
+ leftZerosNeeded = apBuf.flags.printLimit - count;
+ }
+ if (count + leftZerosNeeded < apBuf.flags.width)
+ {
+ const int remainingPaddingNeeded = apBuf.flags.width - (count + leftZerosNeeded);
+ if (apBuf.flags.padRight)
+ {
+ rightSpacesNeeded = remainingPaddingNeeded;
+ }
+ else if (apBuf.flags.padZero)
+ {
+ leftZerosNeeded += remainingPaddingNeeded;
+ }
+ else
+ {
+ leftSpacesNeeded = remainingPaddingNeeded;
+ }
+ }
+
+ // Do the left padding
+ while (leftSpacesNeeded > 0)
+ {
+ if (!strbuf_printchar(apBuf, ' '))
+ {
+ return false;
+ }
+ --leftSpacesNeeded;
+ }
+ while (leftZerosNeeded > 0)
+ {
+ if (!strbuf_printchar(apBuf, '0'))
+ {
+ return false;
+ }
+ --leftZerosNeeded;
+ }
+ }
+
+ // Now print the actual string
+ while (count > 0)
+ {
+ if (!strbuf_printchar(apBuf, *apString++))
+ {
+ return false;
+ }
+ --count;
+ }
+
+ // Now the right padding
+ while (rightSpacesNeeded > 0)
+ {
+ if (!strbuf_printchar(apBuf, ' '))
+ {
+ return false;
+ }
+ --rightSpacesNeeded;
+ }
+
+ return true;
+}
+
+/*-----------------------------------------------------------*/
+
+static bool printll(SStringBuf& apBuf, long long i)
+{
+ apBuf.flags.isNumber = true; /* Parameter for prints */
+ if (i == 0LL)
+ {
+ return prints(apBuf, "0");
+ }
+
+ bool neg = false;
+ unsigned long long u = i;
+ if ((apBuf.flags.isSigned) && (apBuf.flags.base == 10) && (i < 0LL))
+ {
+ neg = true;
+ u = -i;
+ }
+
+ char print_buf[MaxUllDigits + 2];
+ char *s = print_buf + sizeof print_buf - 1;
+ *s = '\0';
+ while (u != 0)
+ {
+ const lldiv_t lldiv_result = lldiv(u, (long long)apBuf.flags.base);
+ unsigned int t = lldiv_result.rem;
+ if (t >= 10)
+ {
+ t += apBuf.flags.letBase - '0' - 10;
+ }
+ *--s = t + '0';
+ u = lldiv_result.quot;
+ }
+
+ if (neg)
+ {
+ if (apBuf.flags.width != 0 && apBuf.flags.padZero)
+ {
+ if (!strbuf_printchar(apBuf, '-'))
+ {
+ return false;
+ }
+ --apBuf.flags.width;
+ }
+ else
+ {
+ *--s = '-';
+ }
+ }
+
+ return prints(apBuf, s);
+}
+
+/*-----------------------------------------------------------*/
+
+static bool printi(SStringBuf& apBuf, int i)
+{
+ apBuf.flags.isNumber = true; /* Parameter for prints */
+
+ if (i == 0)
+ {
+ return prints(apBuf, "0");
+ }
+
+ bool neg = false;
+ unsigned int u = i;
+ unsigned base = apBuf.flags.base;
+ if ((apBuf.flags.isSigned) && (base == 10) && (i < 0))
+ {
+ neg = true;
+ u = -i;
+ }
+
+ char print_buf[MaxLongDigits + 2];
+ char *s = print_buf + sizeof print_buf - 1;
+ *s = '\0';
+
+ switch (base)
+ {
+ case 16:
+ while (u != 0)
+ {
+ unsigned int t = u & 0xF;
+ if (t >= 10)
+ {
+ t += apBuf.flags.letBase - '0' - 10;
+ }
+ *--s = t + '0';
+ u >>= 4;
+ }
+ break;
+
+ case 8:
+ case 10:
+ // GCC compiles very efficient
+ while (u != 0)
+ {
+ const unsigned int t = u % base;
+ *--s = t + '0';
+ u /= base;
+ }
+ break;
+#if 0
+ // The generic case, not yet in use
+ default:
+ while (u != 0)
+ {
+ const unsigned int t = u % base;
+ if (t >= 10)
+ {
+ t += apBuf.flags.letBase - '0' - 10;
+ }
+ *--s = t + '0';
+ u /= base;
+ }
+ break;
+#endif
+ }
+
+ if (neg)
+ {
+ if (apBuf.flags.width && apBuf.flags.padZero)
+ {
+ if (!strbuf_printchar(apBuf, '-'))
+ {
+ return false;
+ }
+ --apBuf.flags.width;
+ }
+ else
+ {
+ *--s = '-';
+ }
+ }
+
+ return prints(apBuf, s);
+}
+
+/*-----------------------------------------------------------*/
+
+// Print a number in scientific format
+// apBuf.flags.printLimit is the number of decimal digits required
+static bool printFloat(SStringBuf& apBuf, double d, char formatLetter)
+{
+ if (std::isnan(d))
+ {
+ return prints(apBuf, "nan");
+ }
+ if (std::isinf(d))
+ {
+ return prints(apBuf, "inf");
+ }
+
+ double ud = fabs(d);
+ if (ud > (double)LONG_LONG_MAX && (formatLetter == 'f' || formatLetter == 'F'))
+ {
+ --formatLetter; // number is too big to print easily in fixed point format, so use exponent format
+ }
+
+ int exponent = 0;
+ if (formatLetter == 'e' || formatLetter == 'E')
+ {
+ // Using exponent format, so calculate the exponent and normalise ud to be >=1.0 but <=10.0
+ // The following loops are inefficient, however we don't expect to print very large or very small numbers
+ while (ud > (double)100000.0)
+ {
+ ud /= (double)100000.0;
+ exponent += 5;
+ }
+ while (ud > (double)10.0)
+ {
+ ud /= (double)10.0;
+ ++exponent;
+ }
+ if (ud != (double)0.0)
+ {
+ while (ud < (double)0.00001)
+ {
+ ud *= (double)100000.0;
+ exponent -= 5;
+ }
+ while (ud < (double)1.0)
+ {
+ ud *= (double)10.0;
+ --exponent;
+ }
+ }
+ // ud is now at least 1.0 but less than 10.0 and exponent is the exponent
+ }
+
+ // Multiply ud by 10 to the power of the number of decimal digits required, or until it becomes too big to print easily
+ if (apBuf.flags.printLimit < 0)
+ {
+ apBuf.flags.printLimit = 6; // set the default number of decimal digits
+ }
+ int digitsAfterPoint = 0;
+ long limit = 10;
+ while (digitsAfterPoint < apBuf.flags.printLimit && ud < LONG_LONG_MAX/10 && limit <= LONG_LONG_MAX/10)
+ {
+ ud *= (double)10.0;
+ limit *= 10;
+ ++digitsAfterPoint;
+ }
+
+ char print_buf[MaxUllDigits + MaxLongDigits + 5];
+ char *s = print_buf + sizeof print_buf - 1;
+ *s = '\0';
+
+ long long u = llrint(ud);
+
+ if (formatLetter == 'e' || formatLetter == 'E')
+ {
+ // Rounding ud may have caused 9.99999... to become 10
+ if (ud >= limit)
+ {
+ ud /= 10;
+ ++exponent;
+ }
+
+ // Store the exponent
+ int iexp = abs(exponent);
+ do
+ {
+ *--s = (iexp % 10) + '0';
+ iexp = iexp/10;
+ } while (iexp != 0);
+ *--s = (exponent < 0) ? '-' : '+';
+ *--s = formatLetter;
+ }
+
+ // Store the non-exponent part
+ do
+ {
+ if (digitsAfterPoint == 0)
+ {
+ *--s = '.';
+ }
+ --digitsAfterPoint;
+
+ const lldiv_t lldiv_result = lldiv(u, 10);
+ *--s = (char)((unsigned int)lldiv_result.rem + '0');
+ u = lldiv_result.quot;
+ }
+ while (u != 0 || digitsAfterPoint >= 0);
+
+ if (d < (double)0.0)
+ {
+ if (apBuf.flags.width != 0 && apBuf.flags.padZero)
+ {
+ if (!strbuf_printchar(apBuf, '-'))
+ {
+ return false;
+ }
+ --apBuf.flags.width;
+ }
+ else
+ {
+ *--s = '-';
+ }
+ }
+
+ return prints(apBuf, s);
+}
+
+/*-----------------------------------------------------------*/
+
+static void tiny_print(SStringBuf& apBuf, const char *format, va_list args)
+{
+ for (;;)
+ {
+ char ch;
+ while ((ch = *format++) != '%')
+ {
+ if (!strbuf_printchar(apBuf, ch)) // note: this returns false if ch == 0
+ {
+ return;
+ }
+ }
+
+ // If we get here then ch == '%'. Get the next character.
+ ch = *format++;
+ if (ch == '\0')
+ {
+ break;
+ }
+ if (ch == '%')
+ {
+ if (strbuf_printchar(apBuf, ch) == 0)
+ {
+ return;
+ }
+ continue;
+ }
+
+ apBuf.Init();
+
+ if (ch == '-')
+ {
+ ch = *format++;
+ apBuf.flags.padRight = true;
+ }
+ while (ch == '0')
+ {
+ ch = *format++;
+ apBuf.flags.padZero = true;
+ }
+ if (ch == '*')
+ {
+ ch = *format++;
+ apBuf.flags.width = va_arg(args, int);
+ }
+ else
+ {
+ while(ch >= '0' && ch <= '9')
+ {
+ apBuf.flags.width *= 10;
+ apBuf.flags.width += ch - '0';
+ ch = *format++;
+ }
+ }
+ if (ch == '.')
+ {
+ ch = *format++;
+ if (ch == '*')
+ {
+ apBuf.flags.printLimit = va_arg(args, int);
+ ch = *format++;
+ }
+ else
+ {
+ while (ch >= '0' && ch <= '9')
+ {
+ apBuf.flags.printLimit *= 10;
+ apBuf.flags.printLimit += ch - '0';
+ ch = *format++;
+ }
+ }
+ }
+ if (apBuf.flags.printLimit == 0)
+ {
+ apBuf.flags.printLimit = -1; // -1: make it unlimited
+ }
+ if (ch == 's')
+ {
+ const char *s = va_arg(args, const char *);
+ apBuf.flags.isString = true;
+ if (!prints(apBuf, (s != nullptr) ? s : "(null)"))
+ {
+ break;
+ }
+ continue;
+ }
+ if (ch == 'c')
+ {
+ // char are converted to int then pushed on the stack
+ if (!strbuf_printchar(apBuf, (char)va_arg(args, int)))
+ {
+ return;
+ }
+
+ continue;
+ }
+ if (ch == 'l')
+ {
+ ch = *format++;
+ apBuf.flags.long32 = 1;
+ // Makes no difference as u32 == long
+ }
+ if (ch == 'L')
+ {
+ ch = *format++;
+ apBuf.flags.long64 = 1;
+ // Does make a difference
+ }
+
+ if (ch == 'f' || ch == 'e' || ch == 'F' || ch == 'E')
+ {
+ if (!printFloat(apBuf, va_arg(args, double), ch))
+ {
+ break;
+ }
+ continue;
+ }
+
+ apBuf.flags.base = 10;
+ apBuf.flags.letBase = 'a';
+
+ if (ch == 'd' || ch == 'u' || ch == 'i')
+ {
+ apBuf.flags.isSigned = (ch != 'u');
+ if (apBuf.flags.long64)
+ {
+ if (!printll(apBuf, va_arg(args, long long)))
+ {
+ break;
+ }
+ }
+ else if (!printi(apBuf, va_arg(args, int)))
+ {
+ break;
+ }
+ continue;
+ }
+
+ apBuf.flags.base = 16; // from here all hexadecimal
+ if (ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o')
+ {
+ if (ch == 'X')
+ {
+ apBuf.flags.letBase = 'A';
+ }
+ else if (ch == 'o')
+ {
+ apBuf.flags.base = 8;
+ }
+ if (apBuf.flags.long64)
+ {
+ if (!printll(apBuf, va_arg(args, long long)))
+ {
+ break;
+ }
+ }
+ else if (!printi(apBuf, va_arg(args, int)))
+ {
+ break;
+ }
+ continue;
+ }
+ }
+ strbuf_printchar(apBuf, '\0');
+}
+
+/*-----------------------------------------------------------*/
+
+int SafeVsnprintf(char *apBuf, size_t aMaxLen, const char *apFmt, va_list args)
+{
+ SStringBuf strBuf(apBuf, aMaxLen);
+ tiny_print(strBuf, apFmt, args);
+ return strBuf.curLen;
+}
+
+int SafeSnprintf(char* buffer, size_t buf_size, const char* format, ...)
+{
+ va_list vargs;
+ va_start(vargs, format);
+ const int ret = SafeVsnprintf(buffer, buf_size, format, vargs);
+ va_end(vargs);
+ return ret;
+}
+
+// End
diff --git a/src/Libraries/General/SafeVsnprintf.h b/src/Libraries/General/SafeVsnprintf.h
new file mode 100644
index 00000000..4a8db786
--- /dev/null
+++ b/src/Libraries/General/SafeVsnprintf.h
@@ -0,0 +1,20 @@
+/*
+ * SafeVsnprintf.h
+ *
+ * Created on: 8 Apr 2018
+ * Author: David
+ */
+
+#ifndef SRC_LIBRARIES_GENERAL_SAFEVSNPRINTF_H_
+#define SRC_LIBRARIES_GENERAL_SAFEVSNPRINTF_H_
+
+#include <cstdarg>
+#include <cstddef>
+
+int SafeVsnprintf(char *buffer, size_t maxLen, const char *format, va_list args);
+int SafeSnprintf(char* buffer, size_t maxLen, const char* format, ...);
+
+#define vsnprintf(b, m, f, a) static_assert(false, "Do not use vsnprintf, use SafeVsnprintf instead")
+#define snprintf(b, m, f, ...) static_assert(false, "Do not use snprintf, use SafeSnprintf instead")
+
+#endif /* SRC_LIBRARIES_GENERAL_SAFEVSNPRINTF_H_ */
diff --git a/src/Libraries/General/StringRef.cpp b/src/Libraries/General/StringRef.cpp
index 5f9c99fe..a65306fb 100644
--- a/src/Libraries/General/StringRef.cpp
+++ b/src/Libraries/General/StringRef.cpp
@@ -9,6 +9,7 @@
#include <cstring>
#include <cstdio>
#include "WMath.h"
+#include "SafeVsnprintf.h"
#ifdef RTOS
# include "RTOSIface.h"
@@ -25,36 +26,6 @@ size_t strnlen(const char *s, size_t n)
return rslt;
}
-// Thread safe version of vsnprintf. The standard one uses a buffer in the _reent structure.
-extern "C" int SafeVsnprintf(char* buffer, size_t buf_size, const char* format, va_list vlist)
-{
-#ifdef RTOS
- TaskCriticalSectionLocker lock;
-#endif
- return vsnprintf(buffer, buf_size, format, vlist);
-}
-
-extern "C" int SafeSnprintf(char* buffer, size_t buf_size, const char* format, ...)
-{
- va_list vargs;
- va_start(vargs, format);
- const int ret = SafeVsnprintf(buffer, buf_size, format, vargs);
- va_end(vargs);
- return ret;
-}
-
-extern "C" int SafeSscanf(const char* s, const char* format, ...)
-{
- va_list vargs;
- va_start(vargs, format);
-#ifdef RTOS
- TaskCriticalSectionLocker lock;
-#endif
- const int ret = vsscanf(s, format, vargs);
- va_end(vargs);
- return ret;
-}
-
//*************************************************************************************************
// StringRef class member implementations
diff --git a/src/Libraries/General/StringRef.h b/src/Libraries/General/StringRef.h
index c8800aaa..6c74fd71 100644
--- a/src/Libraries/General/StringRef.h
+++ b/src/Libraries/General/StringRef.h
@@ -15,11 +15,6 @@
// Need to declare strnlen here because it isn't ISO standard
size_t strnlen(const char *s, size_t n);
-// Thread safe versions of vsnprintf etc.
-extern "C" int SafeVsnprintf(char* buffer, size_t buf_size, const char* format, va_list vlist);
-extern "C" int SafeSnprintf(char* buffer, size_t buf_size, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
-extern "C" int SafeSscanf(const char* s, const char* format, ...) __attribute__ ((format (scanf, 2, 3)));
-
// Class to describe a string buffer, including its length. This saves passing buffer lengths around everywhere.
class StringRef
{
diff --git a/src/Movement/BedProbing/Grid.cpp b/src/Movement/BedProbing/Grid.cpp
index 31e39218..379a4a60 100644
--- a/src/Movement/BedProbing/Grid.cpp
+++ b/src/Movement/BedProbing/Grid.cpp
@@ -88,7 +88,7 @@ void GridDefinition::WriteHeadingAndParameters(const StringRef& s) const
// Check the parameter label line, returning -1 if not recognised, else the version we found
/*static*/ int GridDefinition::CheckHeading(const StringRef& s)
{
- for (size_t i =0; i < ARRAY_SIZE(HeightMapLabelLines); ++i)
+ for (size_t i = 0; i < ARRAY_SIZE(HeightMapLabelLines); ++i)
{
if (StringStartsWith(s.c_str(), HeightMapLabelLines[i]))
{
@@ -101,34 +101,82 @@ void GridDefinition::WriteHeadingAndParameters(const StringRef& s) const
// Read the grid parameters from a string returning true if success
bool GridDefinition::ReadParameters(const StringRef& s, int version)
{
- bool ok;
- switch (version)
+ // 2018-04-08: rewrote this not to use sscanf because that function isn't thread safe
+ isValid = false; // assume failure
+ const char *p = s.c_str();
+ const char *q;
+
+ xMin = SafeStrtof(p, &q);
+ if (p == q || *q != ',')
{
- case 1:
- ok = (SafeSscanf(s.c_str(), "%f,%f,%f,%f,%f,%f,%f,%lu,%lu", &xMin, &xMax, &yMin, &yMax, &radius, &xSpacing, &ySpacing, &numX, &numY) == 9);
- break;
+ return false;
+ }
+ p = q + 1;
- case 0:
- ok = (SafeSscanf(s.c_str(), "%f,%f,%f,%f,%f,%f,%lu,%lu", &xMin, &xMax, &yMin, &yMax, &radius, &xSpacing, &numX, &numY) == 8);
- if (ok)
- {
- ySpacing = xSpacing;
- }
- break;
+ xMax = SafeStrtof(p, &q);
+ if (p == q || *q != ',')
+ {
+ return false;
+ }
+ p = q + 1;
- default:
- ok = false;
+ yMin = SafeStrtof(p, &q);
+ if (p == q || *q != ',')
+ {
+ return false;
}
+ p = q + 1;
- if (ok)
+ yMax = SafeStrtof(p, &q);
+ if (p == q || *q != ',')
{
- CheckValidity();
+ return false;
+ }
+ p = q + 1;
+
+ radius = SafeStrtof(p, &q);
+ if (p == q || *q != ',')
+ {
+ return false;
+ }
+ p = q + 1;
+
+ xSpacing = SafeStrtof(p, &q);
+ if (p == q || *q != ',')
+ {
+ return false;
+ }
+ p = q + 1;
+
+ if (version == 0)
+ {
+ ySpacing = xSpacing;
}
else
{
- isValid = false;
+ ySpacing = SafeStrtof(p, &q);
+ if (p == q || *q != ',')
+ {
+ return false;
+ }
+ p = q + 1;
+ }
+
+ numX = SafeStrtoul(p, &q);
+ if (p == q || *q != ',')
+ {
+ return false;
+ }
+ p = q + 1;
+
+ numY = SafeStrtoul(p, &q);
+ if (p == q)
+ {
+ return false;
}
- return ok;
+
+ CheckValidity();
+ return true;
}
// Print what is wrong with the grid, appending it to the existing string
@@ -209,7 +257,7 @@ unsigned int HeightMap::GetMinimumSegments(float deltaX, float deltaY) const
}
// Save the grid to file returning true if an error occurred
-bool HeightMap::SaveToFile(FileStore *f) const
+bool HeightMap::SaveToFile(FileStore *f, float zOffset) const
{
String<500> bufferSpace;
const StringRef buf = bufferSpace.GetRef();
@@ -225,7 +273,7 @@ bool HeightMap::SaveToFile(FileStore *f) const
}
float mean, deviation;
(void)GetStatistics(mean, deviation);
- buf.catf(", mean error %.3f, deviation %.3f\n", (double)mean, (double)deviation);
+ buf.catf(", mean error %.3f, deviation %.3f\n", (double)(mean + zOffset), (double)deviation);
if (!f->Write(buf.c_str()))
{
return true;
@@ -251,7 +299,7 @@ bool HeightMap::SaveToFile(FileStore *f) const
}
if (IsHeightSet(index))
{
- buf.catf("%7.3f", (double)gridHeights[index]);
+ buf.catf("%7.3f", (double)(gridHeights[index] + zOffset));
}
else
{
@@ -322,6 +370,10 @@ bool HeightMap::LoadFromFile(FileStore *f, const StringRef& r)
const char *p = buffer;
for (uint32_t col = 0; col < def.numX; ++col)
{
+ while (*p == ' ' || *p == '\t')
+ {
+ ++p;
+ }
if (*p == '0' && (p[1] == ',' || p[1] == 0))
{
// Values of 0 with no decimal places in un-probed values, so leave the point set as not valid
@@ -329,8 +381,8 @@ bool HeightMap::LoadFromFile(FileStore *f, const StringRef& r)
}
else
{
- char* np = nullptr;
- const float f = strtof(p, &np);
+ const char* np;
+ const float f = SafeStrtof(p, &np);
if (np == p)
{
r.catf("number expected at line %" PRIu32 " column %d", row + 3, (p - buffer) + 1);
diff --git a/src/Movement/BedProbing/Grid.h b/src/Movement/BedProbing/Grid.h
index 13ce856f..6b1880b6 100644
--- a/src/Movement/BedProbing/Grid.h
+++ b/src/Movement/BedProbing/Grid.h
@@ -8,7 +8,6 @@
#ifndef SRC_MOVEMENT_GRID_H_
#define SRC_MOVEMENT_GRID_H_
-#include <cstdint>
#include "RepRapFirmware.h"
#include "Libraries/General/StringRef.h"
@@ -68,7 +67,7 @@ public:
void ClearGridHeights(); // Clear all grid height corrections
void SetGridHeight(size_t xIndex, size_t yIndex, float height); // Set the height of a grid point
- bool SaveToFile(FileStore *f) const // Save the grid to file returning true if an error occurred
+ bool SaveToFile(FileStore *f, float zOffset) const // Save the grid to file returning true if an error occurred
pre(IsValid());
bool LoadFromFile(FileStore *f, const StringRef& r); // Load the grid from file returning true if an error occurred
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index fedc39b4..8a06e4ac 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -3,10 +3,39 @@
*
* Created on: 7 Dec 2014
* Author: David
+
+ A note on bed levelling:
+
+ As at version 1.21 we support two types of bed compensation:
+ 1. The old 3, 4 and 5-point compensation using a RandomProbePointSet. We will probably discontinue this soon.
+ 2. Mesh bed levelling
+
+ There is an interaction between using G30 to home Z or set a precise Z=0 height just before a print, and bed compensation.
+ Consider the following sequence:
+ 1. Home Z, using either G30 or an endstop.
+ 2. Run G29 to generate a height map. If the Z=0 point has drifted off, the height map may have a Z offset.
+ 3. Use G30 to get an accurate Z=0 point. We want to keep the shape of the height map, but get rid of the offset.
+ 4. Run G29 to generate a height map. This should generate a height map with on offset at the point we just probed.
+ 5. Cancel bed compensation. The height at the point we just probed should be zero.
+
+ So as well as maintaining a height map, we maintain a Z offset from it. The procedure is:
+ 1. Whenever bed compensation is not being used, the Z offset should be zero.
+ 2. Whenever we run G29 to probe the bed, we have a choice:
+ (a) accept that the map may have a height offset; and set the Z offset to zero. This is what we do currently.
+ (b) normalise the height map to zero, adjust the Z=0 origin, and set the Z offset to zero.
+ 3. When we run G30 to reset the Z=0 height, and we have a height map loaded, we adjust the Z offset to be the negative of the
+ height map indication of that point.
+ 4. If we now cancel the height map, we also clear the Z offset, and the height at the point we probed remains correct.
+ 5. If we now run G29 to probe again, the height map should have near zero offset at the point we probed, if there has been no drift.
+
+ Before we introduced the Z offset, at step 4 we would have a potentially large Z error as if the G30 hadn't been run,
+ and at step 5 the new height map would have an offset again.
+
*/
#include "Move.h"
#include "Platform.h"
+#include "Tools/Tool.h"
static constexpr uint32_t UsualMinimumPreparedTime = DDA::stepClockRate/10; // 100ms
static constexpr uint32_t AbsoluteMinimumPreparedTime = DDA::stepClockRate/20; // 50ms
@@ -71,6 +100,7 @@ void Move::Init()
usingMesh = false;
useTaper = false;
+ zShift = 0.0;
idleTimeout = DefaultIdleTimeout;
moveState = MoveState::idle;
@@ -731,6 +761,12 @@ void Move::AxisTransform(float xyzPoint[MaxAxes], AxesBitmap xAxes, AxesBitmap y
}
}
+// Get the height error at an XY position
+float Move::GetInterpolatedHeightError(float xCoord, float yCoord) const
+{
+ return (usingMesh) ? heightMap.GetInterpolatedHeightError(xCoord, yCoord) : probePoints.GetInterpolatedHeightError(xCoord, yCoord);
+}
+
// Invert the Axis transform AFTER the bed transform
void Move::InverseAxisTransform(float xyzPoint[MaxAxes], AxesBitmap xAxes, AxesBitmap yAxes) const
{
@@ -778,14 +814,7 @@ void Move::BedTransform(float xyzPoint[MaxAxes], AxesBitmap xAxes, AxesBitmap yA
if (IsBitSet(yAxes, yAxis))
{
const float yCoord = xyzPoint[yAxis];
- if (usingMesh)
- {
- zCorrection += heightMap.GetInterpolatedHeightError(xCoord, yCoord);
- }
- else
- {
- zCorrection += probePoints.GetInterpolatedHeightError(xCoord, yCoord);
- }
+ zCorrection += GetInterpolatedHeightError(xCoord, yCoord);
++numCorrections;
}
}
@@ -797,6 +826,7 @@ void Move::BedTransform(float xyzPoint[MaxAxes], AxesBitmap xAxes, AxesBitmap yA
zCorrection /= numCorrections; // take an average
}
+ zCorrection += zShift;
xyzPoint[Z_AXIS] += (useTaper) ? (taperHeight - xyzPoint[Z_AXIS]) * recipTaperHeight * zCorrection : zCorrection;
}
}
@@ -820,14 +850,7 @@ void Move::InverseBedTransform(float xyzPoint[MaxAxes], AxesBitmap xAxes, AxesBi
if (IsBitSet(yAxes, yAxis))
{
const float yCoord = xyzPoint[yAxis];
- if (usingMesh)
- {
- zCorrection += heightMap.GetInterpolatedHeightError(xCoord, yCoord);
- }
- else
- {
- zCorrection += probePoints.GetInterpolatedHeightError(xCoord, yCoord);
- }
+ zCorrection += GetInterpolatedHeightError(xCoord, yCoord);
++numCorrections;
}
}
@@ -839,6 +862,8 @@ void Move::InverseBedTransform(float xyzPoint[MaxAxes], AxesBitmap xAxes, AxesBi
zCorrection /= numCorrections; // take an average
}
+ zCorrection += zShift;
+
if (!useTaper || zCorrection >= taperHeight) // need check on zCorrection to avoid possible divide by zero
{
xyzPoint[Z_AXIS] -= zCorrection;
@@ -853,12 +878,43 @@ void Move::InverseBedTransform(float xyzPoint[MaxAxes], AxesBitmap xAxes, AxesBi
}
}
+// Normalise the bed transform to have zero height error at these coordinates
+void Move::SetZeroHeightError(const float coords[MaxAxes])
+{
+ float tempCoords[MaxAxes];
+ memcpy(tempCoords, coords, sizeof(tempCoords));
+ AxisTransform(tempCoords, DefaultXAxisMapping, DefaultYAxisMapping);
+ zShift = -GetInterpolatedHeightError(tempCoords[X_AXIS], tempCoords[Y_AXIS]);
+}
+
void Move::SetIdentityTransform()
{
probePoints.SetIdentity();
heightMap.ClearGridHeights();
heightMap.UseHeightMap(false);
usingMesh = false;
+ zShift = 0.0;
+}
+
+// Load the height map from file, returning true if an error occurred with the error reason appended to the buffer
+bool Move::LoadHeightMapFromFile(FileStore *f, const StringRef& r)
+{
+ const bool ret = heightMap.LoadFromFile(f, r);
+ if (ret)
+ {
+ heightMap.ClearGridHeights(); // make sure we don't end up with a partial height map
+ }
+ else
+ {
+ zShift = 0.0;
+ }
+ return ret;
+}
+
+// Save the height map to a file returning true if an error occurred
+bool Move::SaveHeightMapToFile(FileStore *f) const
+{
+ return heightMap.SaveToFile(f, zShift);
}
void Move::SetTaperHeight(float h)
diff --git a/src/Movement/Move.h b/src/Movement/Move.h
index d033e000..d9a83cb9 100644
--- a/src/Movement/Move.h
+++ b/src/Movement/Move.h
@@ -63,6 +63,7 @@ public:
// Take a position and apply the bed and the axis-angle compensations
void InverseAxisAndBedTransform(float move[], AxesBitmap xAxes, AxesBitmap yAxes) const;
// Go from a transformed point back to user coordinates
+ void SetZeroHeightError(const float coords[MaxAxes]); // Set zero height error at these coordinates
float GetTaperHeight() const { return (useTaper) ? taperHeight : 0.0; }
void SetTaperHeight(float h);
bool UseMesh(bool b); // Try to enable mesh bed compensation and report the final state
@@ -113,6 +114,8 @@ public:
void ResetMoveCounters() { scheduledMoves = completedMoves = 0; }
HeightMap& AccessHeightMap() { return heightMap; } // Access the bed probing grid
+ bool LoadHeightMapFromFile(FileStore *f, const StringRef& r); // Load the height map from a file returning true if an error occurred
+ bool SaveHeightMapToFile(FileStore *f) const; // Save the height map to a file returning true if an error occurred
const DDA *GetCurrentDDA() const { return currentDda; } // Return the DDA of the currently-executing move
@@ -144,6 +147,7 @@ private:
void AxisTransform(float move[MaxAxes], AxesBitmap xAxes, AxesBitmap yAxes) const; // Take a position and apply the axis-angle compensations
void InverseAxisTransform(float move[MaxAxes], AxesBitmap xAxes, AxesBitmap yAxes) const; // Go from an axis transformed point back to user coordinates
void SetPositions(const float move[DRIVES]); // Force the machine coordinates to be these
+ float GetInterpolatedHeightError(float xCoord, float yCoord) const; // Get the height error at an XY position
bool DDARingAdd(); // Add a processed look-ahead entry to the DDA ring
DDA* DDARingGet(); // Get the next DDA ring entry to be run
@@ -177,13 +181,13 @@ private:
float& tanYZ = tangents[1];
float& tanXZ = tangents[2];
- float recipTaperHeight; // Reciprocal of the taper height
- bool useTaper; // True to taper off the compensation
-
HeightMap heightMap; // The grid definition in use and height map for G29 bed probing
RandomProbePointSet probePoints; // G30 bed probe points
- bool usingMesh; // true if we are using the height map, false if we are using the random probe point set
float taperHeight; // Height over which we taper
+ float recipTaperHeight; // Reciprocal of the taper height
+ float zShift; // Height to add to the bed transform
+ bool usingMesh; // true if we are using the height map, false if we are using the random probe point set
+ bool useTaper; // True to taper off the compensation
uint32_t idleTimeout; // How long we wait with no activity before we reduce motor currents to idle, in milliseconds
uint32_t lastStateChangeTime; // The approximate time at which the state last changed, except we don't record timing->idle
diff --git a/src/Networking/NetworkResponder.h b/src/Networking/NetworkResponder.h
index 6bda80e3..b43c02b9 100644
--- a/src/Networking/NetworkResponder.h
+++ b/src/Networking/NetworkResponder.h
@@ -13,7 +13,7 @@
#include "NetworkDefs.h"
#include "Storage/FileData.h"
#include "NetworkBuffer.h"
-#include "Outputmemory.h"
+#include "OutputMemory.h"
// Forward declarations
class NetworkResponder;
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 01431f09..719a6252 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -620,6 +620,7 @@ void Platform::InitZProbe()
case ZProbeType::digital:
case ZProbeType::unfilteredDigital:
case ZProbeType::blTouch:
+ case ZProbeType::zMotorStall:
default:
AnalogInEnableChannel(zProbeAdcChannel, false);
pinMode(zProbePin, INPUT_PULLUP);
@@ -671,6 +672,19 @@ int Platform::GetZProbeReading() const
zProbeVal = GetRawZProbeReading()/4;
break;
+ case ZProbeType::zMotorStall:
+#if HAS_STALL_DETECT
+ {
+ const bool stalled = (reprap.GetMove().GetKinematics().GetKinematicsType() == KinematicsType::coreXZ)
+ ? AnyAxisMotorStalled(X_AXIS) || AnyAxisMotorStalled(Z_AXIS)
+ : AnyAxisMotorStalled(Z_AXIS);
+ zProbeVal = (stalled) ? 1000 : 0;
+ }
+#else
+ zProbeVal = 1000;
+#endif
+ break;
+
default:
return 0;
}
@@ -760,6 +774,7 @@ const ZProbe& Platform::GetZProbeParameters(ZProbeType probeType) const
case ZProbeType::digital:
case ZProbeType::unfilteredDigital:
case ZProbeType::blTouch:
+ case ZProbeType::zMotorStall:
return irZProbeParameters;
case ZProbeType::alternateAnalog:
return alternateZProbeParameters;
@@ -780,6 +795,7 @@ void Platform::SetZProbeParameters(ZProbeType probeType, const ZProbe& params)
case ZProbeType::digital:
case ZProbeType::unfilteredDigital:
case ZProbeType::blTouch:
+ case ZProbeType::zMotorStall:
irZProbeParameters = params;
break;
@@ -1510,13 +1526,9 @@ void Platform::Spin()
reported = true;
}
#elif defined(DUET_NG)
- if (
-# if defined(DUET_WIFI)
- board == BoardType::DuetWiFi_102
-# elif defined(DUET_ETHERNET)
- board == BoardType::DuetEthernet_102
-# endif
- && digitalRead(VssaSensePin))
+ if ( (board == BoardType::DuetWiFi_102 || board == BoardType::DuetEthernet_102)
+ && digitalRead(VssaSensePin)
+ )
{
Message(ErrorMessage, "VSSA fault, check thermistor wiring\n");
reported = true;
@@ -3175,6 +3187,13 @@ void Platform::EnableSharedFan(bool enable)
#endif
+// Check if the given fan can be controlled manually so that DWC can decide whether or not to show the corresponding fan
+// controls. This is the case if no thermostatic control is enabled and if the fan was configured at least once before.
+bool Platform::IsFanControllable(size_t fan) const
+{
+ return (fan < NUM_FANS) ? (!fans[fan].HasMonitoredHeaters() && fans[fan].IsConfigured()) : false;
+}
+
// Get current fan RPM
float Platform::GetFanRPM() const
{
@@ -3963,50 +3982,11 @@ bool Platform::SetExtrusionAncilliaryPwmPin(LogicalPin logicalPin, bool invert)
return extrusionAncilliaryPwmPort.Set(logicalPin, PinAccess::pwm, invert);
}
-// CNC and laser support
-void Platform::SetSpindlePwm(float pwm)
-{
- if (pwm >= 0)
- {
- spindleReversePort.WriteAnalog(0.0);
- spindleForwardPort.WriteAnalog(pwm);
- }
- else
- {
- spindleForwardPort.WriteAnalog(0.0);
- spindleReversePort.WriteAnalog(-pwm);
- }
-}
-
void Platform::SetLaserPwm(float pwm)
{
laserPort.WriteAnalog(pwm);
}
-bool Platform::SetSpindlePins(LogicalPin lpf, LogicalPin lpr, bool invert)
-{
- const bool ok1 = spindleForwardPort.Set(lpf, PinAccess::pwm, invert);
- if (lpr == NoLogicalPin)
- {
- spindleReversePort.Clear();
- return ok1;
- }
- const bool ok2 = spindleReversePort.Set(lpr, PinAccess::pwm, invert);
- return ok1 && ok2;
-}
-
-void Platform::GetSpindlePins(LogicalPin& lpf, LogicalPin& lpr, bool& invert) const
-{
- lpf = spindleForwardPort.GetLogicalPin(invert);
- lpr = spindleReversePort.GetLogicalPin();
-}
-
-void Platform::SetSpindlePwmFrequency(float freq)
-{
- spindleForwardPort.SetFrequency(freq);
- spindleReversePort.SetFrequency(freq);
-}
-
bool Platform::SetLaserPin(LogicalPin lp, bool invert)
{
return laserPort.Set(lp, PinAccess::pwm, invert);
diff --git a/src/Platform.h b/src/Platform.h
index 2cd061e4..9c9477d2 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -38,6 +38,7 @@ Licence: GPL
#include "Storage/FileData.h"
#include "Storage/MassStorage.h" // must be after Pins.h because it needs NumSdCards defined
#include "MessageType.h"
+#include "Spindle.h"
#include "ZProbe.h"
#include "ZProbeProgrammer.h"
@@ -390,35 +391,35 @@ public:
// Movement
void EmergencyStop();
- void SetDirection(size_t drive, bool direction);
+ void SetDirection(size_t axisOrExtruder, bool direction);
void SetDirectionValue(size_t driver, bool dVal);
bool GetDirectionValue(size_t driver) const;
void SetEnableValue(size_t driver, int8_t eVal);
bool GetEnableValue(size_t driver) const;
void EnableDriver(size_t driver);
void DisableDriver(size_t driver);
- void EnableDrive(size_t drive);
- void DisableDrive(size_t drive);
+ void EnableDrive(size_t axisOrExtruder);
+ void DisableDrive(size_t axisOrExtruder);
void DisableAllDrives();
void SetDriversIdle();
- void SetMotorCurrent(size_t drive, float current, int code);
- float GetMotorCurrent(size_t drive, int code) const;
+ void SetMotorCurrent(size_t axisOrExtruder, float current, int code);
+ float GetMotorCurrent(size_t axisOrExtruder, int code) const;
void SetIdleCurrentFactor(float f);
float GetIdleCurrentFactor() const
{ return idleCurrentFactor; }
bool SetDriverMicrostepping(size_t driver, unsigned int microsteps, int mode);
unsigned int GetDriverMicrostepping(size_t drive, int mode, bool& interpolation) const;
- bool SetMicrostepping(size_t drive, int microsteps, int mode);
- unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation) const;
+ bool SetMicrostepping(size_t axisOrExtruder, int microsteps, int mode);
+ unsigned int GetMicrostepping(size_t axisOrExtruder, int mode, bool& interpolation) const;
void SetDriverStepTiming(size_t driver, const float microseconds[4]);
void GetDriverStepTiming(size_t driver, float microseconds[4]) const;
- float DriveStepsPerUnit(size_t drive) const;
+ float DriveStepsPerUnit(size_t axisOrExtruder) const;
const float *GetDriveStepsPerUnit() const
{ return driveStepsPerUnit; }
- void SetDriveStepsPerUnit(size_t drive, float value);
- float Acceleration(size_t drive) const;
+ void SetDriveStepsPerUnit(size_t axisOrExtruder, float value);
+ float Acceleration(size_t axisOrExtruder) const;
const float* Accelerations() const;
- void SetAcceleration(size_t drive, float value);
+ void SetAcceleration(size_t axisOrExtruder, float value);
float GetMaxPrintingAcceleration() const
{ return maxPrintingAcceleration; }
void SetMaxPrintingAcceleration(float acc)
@@ -427,19 +428,19 @@ public:
{ return maxTravelAcceleration; }
void SetMaxTravelAcceleration(float acc)
{ maxTravelAcceleration = acc; }
- float MaxFeedrate(size_t drive) const;
+ float MaxFeedrate(size_t axisOrExtruder) const;
const float* MaxFeedrates() const;
- void SetMaxFeedrate(size_t drive, float value);
- float GetInstantDv(size_t drive) const;
- void SetInstantDv(size_t drive, float value);
- EndStopHit Stopped(size_t drive) const;
- bool EndStopInputState(size_t drive) const;
+ void SetMaxFeedrate(size_t axisOrExtruder, float value);
+ float GetInstantDv(size_t axis) const;
+ void SetInstantDv(size_t axis, float value);
+ EndStopHit Stopped(size_t axisOrExtruder) const;
+ bool EndStopInputState(size_t axis) const;
float AxisMaximum(size_t axis) const;
void SetAxisMaximum(size_t axis, float value, bool byProbing);
float AxisMinimum(size_t axis) const;
void SetAxisMinimum(size_t axis, float value, bool byProbing);
float AxisTotalLength(size_t axis) const;
- float GetPressureAdvance(size_t drive) const;
+ float GetPressureAdvance(size_t extruder) const;
void SetPressureAdvance(size_t extruder, float factor);
void SetEndStopConfiguration(size_t axis, EndStopPosition endstopPos, EndStopInputType inputType)
@@ -450,13 +451,13 @@ public:
uint32_t GetAllEndstopStates() const;
void SetAxisDriversConfig(size_t axis, const AxisDriversConfig& config);
- const AxisDriversConfig& GetAxisDriversConfig(size_t drive) const
- { return axisDrivers[drive]; }
+ const AxisDriversConfig& GetAxisDriversConfig(size_t axis) const
+ { return axisDrivers[axis]; }
void SetExtruderDriver(size_t extruder, uint8_t driver);
uint8_t GetExtruderDriver(size_t extruder) const
{ return extruderDrivers[extruder]; }
- uint32_t GetDriversBitmap(size_t drive) const // get the bitmap of driver step bits for this axis or extruder
- { return driveDriverBits[drive]; }
+ uint32_t GetDriversBitmap(size_t axisOrExtruder) const // get the bitmap of driver step bits for this axis or extruder
+ { return driveDriverBits[axisOrExtruder]; }
static void StepDriversLow(); // set all step pins low
static void StepDriversHigh(uint32_t driverMap); // set the specified step pins high
uint32_t GetSlowDriversBitmap() const { return slowDriversBitmap; }
@@ -515,6 +516,7 @@ public:
#if defined(DUET_06_085)
void EnableSharedFan(bool enable); // enable/disable the fan that shares its PWM pin with the last heater
#endif
+ bool IsFanControllable(size_t fan) const;
bool WriteFanSettings(FileStore *f) const; // Save some resume information
float GetFanRPM() const;
@@ -585,14 +587,9 @@ public:
void ExtrudeOff();
// CNC and laser support
- void SetSpindlePwm(float pwm);
- void SetLaserPwm(float pwm);
-
- bool SetSpindlePins(LogicalPin lpf, LogicalPin lpr, bool invert);
- void GetSpindlePins(LogicalPin& lpf, LogicalPin& lpr, bool& invert) const;
- void SetSpindlePwmFrequency(float freq);
- float GetSpindlePwmFrequency() const { return spindleForwardPort.GetFrequency(); }
+ Spindle& AccessSpindle(size_t slot) { return spindles[slot]; }
+ void SetLaserPwm(float pwm);
bool SetLaserPin(LogicalPin lp, bool invert);
LogicalPin GetLaserPin(bool& invert) const { return laserPort.GetLogicalPin(invert); }
void SetLaserPwmFrequency(float freq);
@@ -906,9 +903,10 @@ private:
uint32_t timeLastUpdatedMillis; // the milliseconds counter when we last incremented the time
// CNC and laser support
+ Spindle spindles[MaxSpindles];
float extrusionAncilliaryPwmValue;
PwmPort extrusionAncilliaryPwmPort;
- PwmPort spindleForwardPort, spindleReversePort, laserPort;
+ PwmPort laserPort;
// Power on/off
bool deferredPowerDown;
@@ -1190,6 +1188,7 @@ inline uint16_t Platform::GetRawZProbeReading() const
return (b) ? 4000 : 0;
}
+ case ZProbeType::zMotorStall:
default:
return 4000;
}
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index 0321ee37..143201f2 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -1028,9 +1028,27 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
}
#endif
- // Spindle
- const double spindleRpm = gCodes->GetSpindleRpm();
- response->catf(",\"spindle\":{\"current\":%1.f,\"active\":%1.f}", spindleRpm, spindleRpm);
+ // Spindles
+ response->cat(",\"spindles\":[");
+ for (size_t i = 0; i < MaxSpindles; i++)
+ {
+ if (i > 0)
+ {
+ response->cat(',');
+ }
+
+ const Spindle& spindle = platform->AccessSpindle(i);
+ response->catf("{\"current\":%1.f,\"active\":%1.f", (double)spindle.GetCurrentRpm(), (double)spindle.GetRpm());
+ if (type == 2)
+ {
+ response->catf(",\"tool\":%d}", spindle.GetToolNumber());
+ }
+ else
+ {
+ response->cat('}');
+ }
+ }
+ response->cat(']');
/* Extended Status Response */
if (type == 2)
@@ -1039,6 +1057,17 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
response->catf(",\"coldExtrudeTemp\":%1.f", (double)(heat->ColdExtrude() ? 0.0 : HOT_ENOUGH_TO_EXTRUDE));
response->catf(",\"coldRetractTemp\":%1.f", (double)(heat->ColdExtrude() ? 0.0 : HOT_ENOUGH_TO_RETRACT));
+ // Controllable Fans
+ FansBitmap controllableFans = 0;
+ for (size_t fan = 0; fan < NUM_FANS; fan++)
+ {
+ if (platform->IsFanControllable(fan))
+ {
+ SetBit(controllableFans, fan);
+ }
+ }
+ response->catf(",\"controllableFans\":%lu", controllableFans);
+
// Maximum hotend temperature - DWC just wants the highest one
response->catf(",\"tempLimit\":%1.f", (double)(heat->GetHighestTemperatureLimit()));
diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h
index 92c3039e..25fe4bf2 100644
--- a/src/RepRapFirmware.h
+++ b/src/RepRapFirmware.h
@@ -35,6 +35,8 @@ typedef uint16_t PwmFrequency; // type used to represent a PWM frequency. 0 som
#include "Configuration.h"
#include "Pins.h"
+#include "Libraries/General/SafeStrtod.h"
+#include "Libraries/General/SafeVsnprintf.h"
#include "Libraries/General/StringRef.h"
// Module numbers and names, used for diagnostics and debug
diff --git a/src/Scanner.cpp b/src/Scanner.cpp
index 919151ab..493090dd 100644
--- a/src/Scanner.cpp
+++ b/src/Scanner.cpp
@@ -258,7 +258,7 @@ void Scanner::ProcessCommand()
// Progress indicator: PROGRESS <PERCENT>
else if (StringStartsWith(buffer, "PROGRESS "))
{
- float parsedProgress = atof(&buffer[9]);
+ const float parsedProgress = SafeStrtof(&buffer[9]);
progress = constrain<float>(parsedProgress, 0.0f, 100.0f);
}
diff --git a/src/Spindle.cpp b/src/Spindle.cpp
new file mode 100644
index 00000000..7c4f531b
--- /dev/null
+++ b/src/Spindle.cpp
@@ -0,0 +1,57 @@
+/*
+ * Spindle.cpp
+ *
+ * Created on: Mar 21, 2018
+ * Author: Christian
+ */
+
+#include "Spindle.h"
+
+bool Spindle::SetPins(LogicalPin lpf, LogicalPin lpr, bool invert)
+{
+ const bool ok1 = spindleForwardPort.Set(lpf, PinAccess::pwm, invert);
+ if (lpr == NoLogicalPin)
+ {
+ spindleReversePort.Clear();
+ return ok1;
+ }
+ const bool ok2 = spindleReversePort.Set(lpr, PinAccess::pwm, invert);
+ return ok1 && ok2;
+}
+
+void Spindle::GetPins(LogicalPin& lpf, LogicalPin& lpr, bool& invert) const
+{
+ lpf = spindleForwardPort.GetLogicalPin(invert);
+ lpr = spindleReversePort.GetLogicalPin();
+}
+
+void Spindle::SetPwmFrequency(float freq)
+{
+ spindleReversePort.SetFrequency(freq);
+ spindleForwardPort.SetFrequency(freq);
+}
+
+void Spindle::SetRpm(float rpm)
+{
+ const float pwm = abs(rpm / maxRpm);
+ if (rpm >= 0.0)
+ {
+ spindleReversePort.WriteAnalog(0.0);
+ spindleForwardPort.WriteAnalog(pwm);
+ }
+ else
+ {
+ spindleReversePort.WriteAnalog(pwm);
+ spindleForwardPort.WriteAnalog(0.0);
+ }
+ currentRpm = configuredRpm = rpm;
+}
+
+void Spindle::TurnOff()
+{
+ spindleReversePort.WriteAnalog(0.0);
+ spindleForwardPort.WriteAnalog(0.0);
+ currentRpm = 0.0;
+}
+
+// End
diff --git a/src/Spindle.h b/src/Spindle.h
new file mode 100644
index 00000000..5e05993c
--- /dev/null
+++ b/src/Spindle.h
@@ -0,0 +1,41 @@
+/*
+ * Spindle.h
+ *
+ * Created on: Mar 21, 2018
+ * Author: Christian
+ */
+
+#ifndef SPINDLE_H
+#define SPINDLE_H
+
+#include "RepRapFirmware.h"
+#include "IoPorts.h"
+
+class Spindle
+{
+private:
+ PwmPort spindleForwardPort, spindleReversePort;
+ bool inverted;
+ float currentRpm, configuredRpm, maxRpm;
+ int toolNumber;
+
+public:
+ Spindle() : inverted(false), currentRpm(0.0), configuredRpm(0.0), maxRpm(DefaultMaxSpindleRpm), toolNumber(-1) { }
+
+ bool SetPins(LogicalPin lpr, LogicalPin lpf, bool invert);
+ void GetPins(LogicalPin& lpf, LogicalPin& lpr, bool& invert) const;
+
+ int GetToolNumber() const { return toolNumber; }
+ void SetToolNumber(int tool) { toolNumber = tool; }
+
+ void SetPwmFrequency(float freq);
+ void SetMaxRpm(float max) { maxRpm = max; }
+
+ float GetCurrentRpm() const { return currentRpm; }
+ float GetRpm() const { return configuredRpm; }
+ void SetRpm(float rpm);
+
+ void TurnOff();
+};
+
+#endif
diff --git a/src/Storage/FileInfoParser.cpp b/src/Storage/FileInfoParser.cpp
index b2f50937..af87f5c1 100644
--- a/src/Storage/FileInfoParser.cpp
+++ b/src/Storage/FileInfoParser.cpp
@@ -382,7 +382,7 @@ bool FileInfoParser::FindFirstLayerHeight(const char* buf, size_t len, float& he
if (buf[i] == 'Z')
{
//debugPrintf("Found at offset %u text: %.100s\n", i, &buf[i + 1]);
- const float flHeight = strtof(&buf[i + 1], nullptr);
+ const float flHeight = SafeStrtof(&buf[i + 1], nullptr);
if ((height == 0.0 || flHeight < height) && (flHeight <= reprap.GetPlatform().GetNozzleDiameter() * 3.0))
{
height = flHeight; // Only report first Z height if it's somewhat reasonable
@@ -475,7 +475,7 @@ bool FileInfoParser::FindHeight(const char* buf, size_t len, float& height) cons
}
else
{
- height = strtof(zpos, nullptr);
+ height = SafeStrtof(zpos, nullptr);
foundHeight = true;
}
break; // carry on looking for a later G1 Z command
@@ -500,7 +500,7 @@ bool FileInfoParser::FindHeight(const char* buf, size_t len, float& height) cons
static const char kisslicerHeightString[] = " END_LAYER_OBJECT z=";
if (len > 31 && StringStartsWith(buf, kisslicerHeightString))
{
- height = strtof(buf + sizeof(kisslicerHeightString)/sizeof(char) - 1, nullptr);
+ height = SafeStrtof(buf + sizeof(kisslicerHeightString)/sizeof(char) - 1, nullptr);
return true;
}
}
@@ -542,8 +542,8 @@ bool FileInfoParser::FindLayerHeight(const char *buf, size_t len, float& layerHe
{
++pos;
}
- char *tailPtr;
- const float val = strtof(pos, &tailPtr);
+ const char *tailPtr;
+ const float val = SafeStrtof(pos, &tailPtr);
if (tailPtr != pos) // if we found and converted a number
{
layerHeight = val;
@@ -627,8 +627,8 @@ unsigned int FileInfoParser::FindFilamentUsed(const char* buf, size_t len, float
}
while (isDigit(*p))
{
- char* q;
- filamentUsed[filamentsFound] = strtof(p, &q);
+ const char* q;
+ filamentUsed[filamentsFound] = SafeStrtof(p, &q);
p = q;
if (*p == 'm')
{
@@ -656,8 +656,8 @@ unsigned int FileInfoParser::FindFilamentUsed(const char* buf, size_t len, float
while (filamentsFound < maxFilaments && (p = strstr(p, filamentUsedStr2)) != nullptr)
{
p += strlen(filamentUsedStr2);
- char *q;
- unsigned int num = strtoul(p, &q, 10);
+ const char *q;
+ unsigned long num = SafeStrtoul(p, &q);
if (q != p && num < maxFilaments)
{
p = q;
@@ -667,7 +667,7 @@ unsigned int FileInfoParser::FindFilamentUsed(const char* buf, size_t len, float
}
if (isDigit(*p))
{
- filamentUsed[filamentsFound] = strtof(p, &q);
+ filamentUsed[filamentsFound] = SafeStrtof(p, nullptr);
++filamentsFound;
}
}
@@ -687,7 +687,7 @@ unsigned int FileInfoParser::FindFilamentUsed(const char* buf, size_t len, float
}
if (isDigit(*p))
{
- filamentUsed[filamentsFound] = strtof(p, nullptr); // S3D reports filament usage in mm, no conversion needed
+ filamentUsed[filamentsFound] = SafeStrtof(p, nullptr); // S3D reports filament usage in mm, no conversion needed
++filamentsFound;
}
}
@@ -712,7 +712,7 @@ unsigned int FileInfoParser::FindFilamentUsed(const char* buf, size_t len, float
if (isDigit(*p))
{
- filamentUsed[filamentsFound] = strtof(p, nullptr);
+ filamentUsed[filamentsFound] = SafeStrtof(p, nullptr);
++filamentsFound;
}
}
@@ -725,7 +725,7 @@ unsigned int FileInfoParser::FindFilamentUsed(const char* buf, size_t len, float
p = strstr(buf, filamentVolumeStr);
if (p != nullptr)
{
- const float filamentCMM = strtof(p + strlen(filamentVolumeStr), nullptr) * 1000.0;
+ const float filamentCMM = SafeStrtof(p + strlen(filamentVolumeStr), nullptr) * 1000.0;
filamentUsed[filamentsFound++] = filamentCMM / (Pi * fsquare(reprap.GetPlatform().GetFilamentWidth() / 2.0));
}
}
diff --git a/src/Version.h b/src/Version.h
index e9fafac7..7a63d15b 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -15,11 +15,11 @@
#endif
#ifndef VERSION
-# define VERSION "2.0" RTOSVER "alpha1"
+# define VERSION "2.0" RTOSVER "beta1"
#endif
#ifndef DATE
-# define DATE "2018-04-05b2"
+# define DATE "2018-04-10b1"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"
diff --git a/src/ZProbe.h b/src/ZProbe.h
index 0ebea544..75c43f80 100644
--- a/src/ZProbe.h
+++ b/src/ZProbe.h
@@ -22,7 +22,8 @@ enum class ZProbeType : uint8_t
zSwitch = 7,
unfilteredDigital = 8,
blTouch = 9,
- numTypes = 10 // must be 1 higher than the last type
+ zMotorStall = 10,
+ numTypes = 11 // must be 1 higher than the last type
};
class ZProbe