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:
authorDavid Crocker <dcrocker@eschertech.com>2018-04-10 18:43:04 +0300
committerDavid Crocker <dcrocker@eschertech.com>2018-04-10 18:43:21 +0300
commit3d28ae850b69dbb101c14b496a8b57276f1f6c3e (patch)
treeace858262c8623425afa91b16b342fa6f1371079
parent81766be3d9a462cc420b2e1f35c23d189c7fb6f9 (diff)
Again more RTOS work
Use our own version of vsnprintf to save stack and avoid needing to stop scheduler during calls to it G0 now moves at maximum travel speed and ignores F parameters Fixed problem with doing G20 after loading or probing a height map with a significant Z offset Added chrishamm's spindle and fan map changes Added type 10 Z probe which uses Z motor stall detection Don't need to home any more before simulating a file Update user coordinates after G10 is used to change tool offsets Don't require both X and Y or both I and J parameters to be specified in G2/G3 commands
-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