Giter Club home page Giter Club logo

duetsoftwareframework's Introduction

Duet Software Framework

Version License Issues

Duet Software Framework resembles a collection of programs to control an attached Duet3D board from a Linux-based mini computer (SBC). Since it is using .NET, it requires an ARM processor that supports ARMv7 instructions processor is required (Raspberry Pi 2 or newer). In addition, Linux >= 4.8 is required because the relatively new gpiochip character device interface is used.

DuetControlServer

This application is the heart component of Duet Software Framework. It takes takes care of G/M/T-code processing, inter-process communication, file path mapping, and communication with RepRapFirmware as well as firmware updates. If you want to write your own plugins, this is the component that you need to connect to.

Command-Line Options

The following command-line arguments are available:

  • -u, --update: Update RepRapFirmware and exit. This works even if another instance is already started
  • -l, --log-level: Set the minimum log level. Valid options are: trace, debug , info , warn, error, fatal, off Default is info
  • -c, --config: Override the path to the JSON configuration file. Defaults to /opt/dsf/conf/config.json
  • -r, --no-reset-stop: Do not terminate this application when M999 has been processed
  • -S, --socket-directory: Override the path where DCS creates UNIX sockets. Defaults to /var/run/dsf
  • -s, --socket-file: Override the filename of DCS's UNIX socket. Defaults to dcs.sock
  • -b, --base-directory: Set the base directory of the virtual SD card directoy. This is used for RepRapFirmware compatibility. Defaults to /opt/dsf/sd
  • -D, --no-spi: Do NOT connect over SPI. Not recommended, use at your own risk!
  • -h, --help: Display all available command-line parameters

Note that all the command-line options are case-sensitive.

Return Codes

This application may return the following codes (derived from sysexits.h):

  • 0: Successful termination
  • 64: Failed to initialize settings (usage error)
  • 69: Could not connect to Duet (service unavailable)
  • 70: Internal software error
  • 71: Failed to initialize environment (OS error)
  • 73: Failed to initialize IPC socket (Cannot create file)
  • 74: Could not open SPI or GPIO device (IO error)
  • 75: Auto-update disabled or other instance already running (temporary failure)
  • 78: Bad settings file (configuration error)

SPI Link

In order to connect to the firmware, a binary data protocol is used. DuetControlServer attaches to the Duet using an SPI connection (typically /dev/spidev0.0) in master mode. In addition, a GPIO pin (typically pin 22 on the Raspberry Pi header via /dev/gpiochip0) is required which is toggled by RepRapFirmware whenever the firmware is ready to exchange data.

More technical documentation about this can be found here.

Inter-Process Communication

DuetControlServer provides a UNIX socket for inter-process commmunication. This socket usually resides in /var/run/dsf/dcs.sock . For .NET, DSF provides the DuetAPIClient class library which is also used internally by the DSF core applications.

Technical information about the way the communication over the UNIX socket works can be found in the API description.

Object Model

Like RepRapFirmware, DSF provides a central object model that replicates the entire machine state. This model data is synchronized with Duet Web Control as well and stored in its backend. For further information about the object model structure, check out the DSF code documentation.

Virtual SD Card

Since RepRapFirmware relies on files from a SD card, DSF provides an emulation layer. These files are stored inside a "virtual SD card" for RepRapFirmware in /opt/dsf/sd. However, this path may be adjusted in the config.json file (in /opt/dsf/conf).

Configuration

The configuration behind DCS is kept quite flexible in order to allow for simple changes. By default those values are stored in /opt/dsf/conf/config.json but the config path may be overridden using a command-line parameter.

Check out the code documentation for an overview of the available settings.

DuetWebServer

This application provides Duet Web Control along with a RESTful API and possibly custom HTTP endpoints. It is implemented using ASP.NET and uses Kestrel internally. The coniguration file defaults to /opt/dsf/conf/http.json.

Configuration

The configuration file of DuetWebServer can be found in /opt/dsf/conf/http.json. In this file various settings can be tuned.

In the Logging section, the default minimum LogLevel can be changed to one of Trace, Debug, Information, Warning, Error, orCritical. It defaults to Information.

The Kestrel section specifies the default configuration of the underlying webserver. Further details about the available options can be found at Microsoft Docs.

Apart from these two sections, you can also customize the following settings:

  • SocketPath: Path to the UNIX socket provided by DCS
  • StartErrorFile: Optional file containing the last start error from DCS
  • KeepAliveInterval: Default keep-alive interval for WebSocket connections. This is useful if DWS is operating as a reverse proxy
  • SessionTimeout: Default timeout for inactive HTTP sessions
  • ModelRetryDelay: If DuetControlServer is not running, this specifies the delay between reconnect attempts in milliseconds
  • ObjectModelUpdateTimeout: When a WebSocket is connected and waiting for object model changes, this specifies the timeout after which DWS stops waiting and polls the WebSocket again
  • UseStaticFiles: Whether to provide web files from the virtual www directory. This is required for DWC if DWS is not running as a reverse proxy
  • DefaultWebDirectory: Default web directory to fall back to if DCS could not be contacted (requires UseStaticFiles to be set)
  • MaxAge: Maximum cache time for static files (requires UseStaticFiles to be true)
  • WebSocketBufferSize: This defines the maximum buffer size per third-party WebSocket connection

It is possible to override these settings using command-line arguments, too.

Operation as a reverse proxy

If you wish to use another HTTP server than DuetWebServer, it is possible to set up DuetWebServer as a reverse proxy. Check out this page for Apache and this one for nginx.

Tools

DSF comes with a bunch of command-line tools. They may be invoked from a local terminal or from a remote connection via SSH. All these tools are installed to /opt/dsf/bin so e.g. the CodeConsole utility can be invoked using /opt/dsf/bin/CodeConsole.

CodeConsole

This tool can be used to run G/M/T-codes and to wait for a result.

Command-Line Options

The following command-line arguments are available:

  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock
  • -c, --code: Execute the given code(s), wait for the result and exit
  • -q, --quiet: Do not display when a connection has been established (only applicable if -c is not set)
  • -h, --help: Display all available command-line parameters

CodeLogger

This tool lets you track the lifecycle of a G/M/T-code that is processed by DSF. Once launched, these types of code interception can be observed:

  • pre: Code is being started but it has not been processed internally yet
  • post: Code has been executed internally but it has not been resolved. It is about to be sent to RepRapFirmware for further processing
  • executed: Code has been executed and a result is about to be returned

Command-Line Options

The following command-line arguments are available:

  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock
  • -q, --quiet: Do not display when a connection has been established (only applicable if -c is not set)
  • -h, --help: Display all available command-line parameters

CodeStream

This tool can be used to stream codes in order to execute multiple G/M/T-codes without waiting for a response first. When a code has finished, the corresponding result is written to the console.

Command-Line Options

The following command-line arguments are available:

  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock
  • -b, --buffer-size <size>: Maximum number of codes to execute simultaneously
  • -q, --quiet: Do not display when a connection has been established (only applicable if -c is not set)
  • -h, --help: Display all available command-line parameters

CustomHttpEndpoint

This tool lets you create a custom RESTful HTTP or WebSocket endpoint via /machine/{namespace}/{path}. If started without any command-line arguments, it will try to register a new HTTP GET endpoint at /machine/custom-http-endpoint/demo that is accessible from a web browser. It is possible to register different HTTP methods at the same endpoint path.

By default, this tool echoes the session ID, HTTP method, received HTTP headers, queries, and body (if set). If WebSocket mode is selected, the tool will wait for the a single connection, print text data received from the WebSocket to stdout and send input lines from stdin back to the WebSocket.

Binary data transfers are not supported in any mode. If you need to transfer binary data, upload to a file instead and call your custom endpoint when the transfer has finished.

Command-Line Options

  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock
  • -m, --method: Set designated method for the HTTP endpoint. May be one of GET, POST, PUT, PATCH, TRACE, DELETE, OPTIONS, WebSocket
  • -n, --namespace: Set namespace to use (defaults to custom-http-endpoint)
  • -p, --path: Set HTTP query path (defaults to demo)
  • -e, --exec: Set binary file to execute when an HTTP query is received. Stdout and stderr are returned as the response body once the program terminates
  • -u, --uri <uri>: Tell the web server to relay the incoming request to another server specified by the URI
  • -a, --args: Set arguments for the executable file. Query values in % characters are replaced with query options (e.g. %myvalue%). Not applicable for WebSockets
  • -q, --quiet: Do not display info text
  • -h, --help: Display all available command-line parameters

DuetPiManagementPlugin

This DSF plugin provides various M-code extensions to mimic standalone compatibility using various M-codes. It is intended to be used with DuetPi because it requires various services to be installed first.

See its dedicate README.md for further details.

Command-Line Options

  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock

DuetPluginService

Two instances of this service run as

  1. DSF user
  2. Root user

It is in charge of plugin installations, security profiles, and plugin lifecycles. Hence this service starts and stops whenever DuetControlServer does (using the PartOf systemd binding).

Unlike DuetControlServer, which starts early in the boot process (sysinit target), this service is started as soon as the system reaches the multi-user target. This is intended to reduce load on the system during start-up and to make sure potentially required resources are available when third-party plugins are started.

As soon as both plugin services (and the previously started plugins) have been started, dsf-config.g is executed by DuetControlServer. Note that dsf-config.g does not run if not both services have been started unless plugin support has been disabled in /opt/dsf/conf/config.json.

Command-Line Options

  • -l, --log-level: Set the minimum log level. Valid options are: trace, debug , info , warn, error, fatal, off Default is info
  • -c, --config: Override the path to the JSON configuration file. Defaults to /opt/dsf/conf/config.json
  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock
  • -h, --help: Display all available command-line parameters

ModelObserver

This tool lets you keep track of object model changes. Since it relies on a model subscription, it gives an idea how model updates are pushed from DuetWebServer to Duet Web Control.

Command-Line Options

  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock
  • -f, --filter <filter>: UNIX socket to connect to
  • -c, --confirm: Confirm every JSON receipt manually
  • -q, --quiet: Do not display when a connection has been established
  • -h, --help: Display all available command-line parameters

PluginManager

This tool is intended to manage third-party plugins directly on the SBC without a GUI.

Command-Line Options

  • -s, --socket: Specify the UNIX socket to connect to. Defaults to /var/run/dsf/dcs.sock
  • list: List installed plugins
  • list-data: List plugin data of all installed plugins
  • install <pluginZIP>: Install a plugin ZIP file
  • start <plugin>: Start a plugin
  • set-data <plugin>:<key>=<value>: Set plugin data
  • stop <plugin>: Stop a plugin
  • uninstall <plugin>: Uninstall a plugin
  • -h, --help: Display all available command-line parameters

Unit Tests

To ensure flawless operation of the most critical components, Duet Software Framework relies on unit tests via the NUnit framework. These unit tests can be found in the src/UnitTests directory.

Known incompatibilities

  • G-Code checksums and M998 are not supported

Reporting issues

Before reporting any new issues, please check if it is already a known issue or if it has been already reported on the GitHub issues page. For general support questions, please check out the forums.

If the issue you encountered is easy to reproduce, please file a new issue in the GitHub issues page along with instructions on how to reproduce.

If the issue only happens sporadically, please launch DuetControlServer with the log level debug and provide the log including a short note when the error occurred. To launch DuetControlServer with this log level on DuetPi, you may run the following commands from an SSH terminal:

sudo systemctl stop duetcontrolserver
sudo /opt/dsf/bin/DuetControlServer -l debug -r

duetsoftwareframework's People

Contributors

chrishamm avatar gloomyandy avatar gtjoseph avatar kriechi avatar loicgrenon avatar natewalck avatar sindarius avatar t3p3 avatar wilriker avatar x0rtrunks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

duetsoftwareframework's Issues

wiringpi - missing dependancy

Fresh install on debian strech (lite):

Duet Control Server v1.0.0.14
Written by Christian Hammacher for Duet3D
Licensed under the terms of the GNU Public License Version 3

Loading settings... Done!
Initialising object model... Done!
Connecting to RepRapFirmware... wiringPiISR: Can't find gpio program

solved by sudo apt-get install wiringpi

Tool 0 is broken

duetcontrolserver=1.0.3.0-1
duetruntime=1.0.3.0-1
duetsd=1.0.1-3
duetsoftwareframework-meta=1.0.3.0-1
duettools=1.0.3.0-1
duetwebcontrol=2.0.0.RC8.b1-2
duetwebserver=1.0.1.1-2
duet3firmware=3.0b7@2019-08-05b1

After updating to the latest versions of DCS and RRF there is no more Tool 0 in DWC. Or at least it is quite broken.
2019-08-05-155824_1920x1200_scrot

Here is the content of the first (and only) message on the WebSocket:

{
    "channels": {
        "http": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "telnet": {
            "compatibility": 2,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "file": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "usb": {
            "compatibility": 2,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "aux": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "daemon": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": false,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "codeQueue": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "lcd": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "spi": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        },
        "autoPause": {
            "compatibility": 1,
            "feedrate": 50.0000038,
            "relativeExtrusion": true,
            "volumetricExtrusion": false,
            "relativePositioning": false,
            "usingInches": false,
            "stackDepth": 1,
            "lineNumber": 0
        }
    },
    "electronics": {
        "type": "duet3",
        "name": "Duet 3",
        "revision": "0.5",
        "firmware": {
            "name": "RepRapFirmware for Duet 3 v0.5",
            "version": null,
            "date": null
        },
        "processorID": null,
        "vIn": {
            "current": 0.3,
            "min": 0.1,
            "max": 0.3
        },
        "mcuTemp": {
            "current": 33.8,
            "min": 33.2,
            "max": 34.1
        },
        "expansionBoards": []
    },
    "fans": [
        {
            "value": 0.0,
            "name": "Part Cooling Fan",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        },
        {
            "value": 0.0,
            "name": "",
            "rpm": null,
            "inverted": false,
            "frequency": null,
            "min": 0.0,
            "max": 1.0,
            "blip": 0.1,
            "thermostatic": {
                "control": true,
                "heaters": [],
                "temperature": null
            },
            "pin": null
        }
    ],
    "heat": {
        "beds": [
            {
                "active": [
                    0.0
                ],
                "standby": [
                    0.0
                ],
                "name": null,
                "heaters": [
                    0
                ]
            }
        ],
        "chambers": [],
        "coldExtrudeTemperature": 160.0,
        "coldRetractTemperature": 90.0,
        "extra": [
            {
                "current": 33.8,
                "name": "*MCU",
                "state": null,
                "sensor": null
            },
            {
                "current": 0.0,
                "name": "*TMC",
                "state": null,
                "sensor": null
            }
        ],
        "heaters": [
            {
                "current": 20.3,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 0
            },
            {
                "current": 19.8,
                "name": "",
                "state": 2,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 1
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 2
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 3
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 4
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 5
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 6
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 7
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 8
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 9
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 10
            },
            {
                "current": -273.1,
                "name": "",
                "state": 0,
                "model": {
                    "gain": null,
                    "timeConstant": null,
                    "deadTime": null,
                    "maxPwm": null,
                    "standardVoltage": null,
                    "usePID": true,
                    "customPID": false,
                    "p": 0.0,
                    "i": 0.0,
                    "d": 0.0
                },
                "max": 290.0,
                "sensor": 11
            }
        ]
    },
    "job": {
        "file": {
            "fileName": null,
            "size": 0,
            "lastModified": null,
            "height": 0.0,
            "firstLayerHeight": 0.0,
            "layerHeight": 0.0,
            "numLayers": null,
            "filament": [],
            "generatedBy": "",
            "printTime": 0,
            "simulatedTime": 0
        },
        "filePosition": null,
        "lastFileName": null,
        "lastFileSimulated": false,
        "extrudedRaw": [],
        "duration": null,
        "layer": null,
        "layerTime": null,
        "layers": [],
        "warmUpDuration": null,
        "timesLeft": {
            "file": null,
            "filament": null,
            "layer": null
        }
    },
    "messageBox": {
        "mode": null,
        "title": null,
        "message": null,
        "axisControls": [],
        "seq": 0
    },
    "messages": [
        {
            "time": "2019-08-05T15:25:30.3877852+02:00",
            "type": 0,
            "content": "Connection to Duet established"
        },
        {
            "time": "2019-08-05T15:54:20.5167298+02:00",
            "type": 0,
            "content": "Connection to Duet established"
        },
        {
            "time": "2019-08-05T15:54:31.1776684+02:00",
            "type": 0,
            "content": "Connection to Duet established"
        }
    ],
    "move": {
        "axes": [
            {
                "letter": "X",
                "drives": [],
                "homed": false,
                "machinePosition": 0.0,
                "min": null,
                "minProbed": false,
                "max": null,
                "maxProbed": false,
                "visible": true
            },
            {
                "letter": "Y",
                "drives": [],
                "homed": false,
                "machinePosition": 0.0,
                "min": null,
                "minProbed": false,
                "max": null,
                "maxProbed": false,
                "visible": true
            },
            {
                "letter": "Z",
                "drives": [],
                "homed": false,
                "machinePosition": 0.0,
                "min": null,
                "minProbed": false,
                "max": null,
                "maxProbed": false,
                "visible": true
            }
        ],
        "babystepZ": 0.0,
        "currentMove": {
            "requestedSpeed": 0.0,
            "topSpeed": 0.0
        },
        "compensation": "None",
        "drives": [
            {
                "position": 0.0,
                "microstepping": {
                    "value": 16,
                    "interpolated": true
                },
                "current": null,
                "acceleration": null,
                "minSpeed": null,
                "maxSpeed": null
            },
            {
                "position": 0.0,
                "microstepping": {
                    "value": 16,
                    "interpolated": true
                },
                "current": null,
                "acceleration": null,
                "minSpeed": null,
                "maxSpeed": null
            },
            {
                "position": 0.0,
                "microstepping": {
                    "value": 16,
                    "interpolated": true
                },
                "current": null,
                "acceleration": null,
                "minSpeed": null,
                "maxSpeed": null
            },
            {
                "position": 0.0,
                "microstepping": {
                    "value": 16,
                    "interpolated": true
                },
                "current": null,
                "acceleration": null,
                "minSpeed": null,
                "maxSpeed": null
            }
        ],
        "extruders": [
            {
                "drives": [
                    3
                ],
                "factor": 1.0,
                "nonlinear": {
                    "a": 0.0,
                    "b": 0.0,
                    "upperLimit": 0.2,
                    "temperature": 0.0
                }
            }
        ],
        "geometry": {
            "type": "unknown",
            "anchors": [
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0,
                0.0
            ],
            "printRadius": 0.0,
            "diagonals": [
                0.0,
                0.0,
                0.0
            ],
            "radius": 0.0,
            "homedHeight": 0.0,
            "angleCorrections": [
                0.0,
                0.0,
                0.0
            ],
            "endstopAdjustments": [
                0.0,
                0.0,
                0.0
            ],
            "tilt": [
                0.0,
                0.0
            ]
        },
        "idle": {
            "timeout": 30.0,
            "factor": 0.3
        },
        "speedFactor": 1.0,
        "currentWorkplace": 0,
        "workplaceCoordinates": []
    },
    "network": {
        "name": "Duet3",
        "hostname": "Duet3",
        "password": "reprap",
        "interfaces": [
            {
               [REDACTED]
            }
        ]
    },
    "scanner": {
        "progress": 0.0,
        "status": "D"
    },
    "sensors": {
        "endstops": [],
        "probes": [
            {
                "type": 0,
                "value": 1000,
                "secondaryValues": [],
                "threshold": 500,
                "speed": 2.0,
                "diveHeight": 0.0,
                "offsets": [
                    0.0,
                    0.0
                ],
                "triggerHeight": 0.7,
                "filtered": true,
                "inverted": false,
                "recoveryTime": 0.0,
                "travelSpeed": 100.0,
                "maxProbeCount": 1,
                "tolerance": 0.03,
                "disablesBed": false,
                "persistent": false
            }
        ]
    },
    "spindles": [],
    "state": {
        "atxPower": false,
        "beep": {
            "frequency": 0,
            "duration": 0.0
        },
        "currentTool": 0,
        "displayMessage": "",
        "logFile": null,
        "mode": "FFF",
        "status": "off"
    },
    "storages": [
        [REDACTED]
    ],
    "tools": [
        {
            "number": 0,
            "active": [],
            "standby": [],
            "name": null,
            "filamentExtruder": 0,
            "filament": null,
            "fans": [],
            "heaters": [],
            "mix": [],
            "spindle": -1,
            "axes": [],
            "offsets": [],
            "offsetsProbed": 0
        }
    ],
    "userVariables": []
}

GCode commands and parameters should be case-insensitive

GCode should be case-insensitive, except in particular contexts e.g. quoted strings. However, a macro file using lower case command letters and parameter letters does not execute. Example of a file that does nothing:

m106 p3 s1
g1 x100 f1200
m106 p3 s0
g1 x0 f1200

M905 at the end of config.g is executed as timedatectl command

duetcontrolserver=1.0.3.0-1
duetruntime=1.0.3.0-1
duetsd=1.0.1-3
duetsoftwareframework-meta=1.0.3.0-1
duettools=1.0.3.0-1
duetwebcontrol=2.0.0.RC8.b1-2
duetwebserver=1.0.1.1-2
duet3firmware=3.0b7@2019-08-05b3

With DCS 1.0.3.0 M905 being sent at the end of config.g has been implemented. See #38.
I also found hints in the source code that this is supposed to then not try to set the SBC's date and time in this case but still it tries to. In the log of DCS and see

Aug 07 14:19:27 duet3-v05 DuetControlServer[14682]: Failed to set time: Automatic time synchronization is enabled
Aug 07 14:19:28 duet3-v05 DuetControlServer[14682]: Failed to set time: Automatic time synchronization is enabled
Aug 07 14:19:28 duet3-v05 DuetControlServer[14682]: [info] Sent M905 P"2019-08-07" S"14:19:27", remaining space 712 (1992 total), needed 56

where the first two lines of error messages are the output of timedatectl set-time [...] if time sync is enabled (as on my setup). This means the flag to execute this internally does not work as intended.

Also as a side-note: M905 is automatically appended whenever any macro called config.g is executed, i.e. also when M703 is executing a filament-specific config.g. It is not a problem but I want to still mention it.

Uncaught exception when parsing invalid gcode

Accidentally inserted a l instead of ; and DuetControlServer crashed when running the homing macro.

homex.g

G91
;G1 Z2.5 F600 S2
G1 S1 X-400 F180
G1 X5 F600
G1 S1 X-5 F300
lG1 Z-2.5 F180
G90
[info] Sent G28 X"", remaining space 1024, need 28
[info] Executing nested macro file '/opt/dsf/sd/sys/homex.g' on channel HTTP
[crit] Abnormal program termination:
SPI task terminated
[crit] DuetAPI.Commands.CodeParserException: Failed to parse minor GCode number (Z-25)
   at DuetAPI.Commands.Code..ctor(String codeString) in /home/christian/duet/DuetSoftwareFramework/src/DuetAPI/Commands/Code/Parser.cs:line 142
   at DuetControlServer.Commands.Code..ctor(String code) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Commands/Code.cs:line 26
   at DuetControlServer.FileExecution.BaseFile.ReadCode() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/FileExecution/BaseFile.cs:line 100
   at DuetControlServer.FileExecution.MacroFile.ReadCode() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/FileExecution/MacroFile.cs:line 156
   at DuetControlServer.SPI.ChannelInformation.ProcessRequests() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Channel.cs:line 182
   at DuetControlServer.SPI.Interface.Run() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Interface.cs:line 337
[warn] Connection error: System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at DuetControlServer.IPC.Processors.Subscription.Process() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/IPC/Processors/Subscription.cs:line 100
   at DuetControlServer.IPC.Server.ConnectionEstablished(Socket socket, Int32 id) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/IPC/Server.cs:line 86
[warn] Connection error: System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at DuetControlServer.IPC.Processors.Subscription.Process() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/IPC/Processors/Subscription.cs:line 100
   at DuetControlServer.IPC.Server.ConnectionEstablished(Socket socket, Int32 id) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/IPC/Server.cs:line 86

Job start/end messages missing

RRF on Duet 2 writes messages to the GCode console (and the log file if logging is enabled) when a SD card job is started and when it finishes or is cancelled. These messages are not generated on Duet 3. DSF will need to generate them because it has control of the start/stop process.

Trouble homing

Firstly this is likely to be several issues, but I'm getting nowhere with isolating any one of the problems.

When homing, X axis will randomly terminate the G1 H1 move, as if it hit the endstop. But it will also reliably work if it reaches the inductive endstop. Initially I thought it coincided with one of the other axes hitting their endstop causing X to also stop, but the behavior persist when homing one axis at the time in homeall.g

After homing X, it will most often get the M208 value, but occasionally a higher number, seemingly only if it did not home properly.

DuetWebControl will hang after 5-10 cycles of homing, jogging and homing again. I.e the home button has a spinning indicator that nevers goes away. Restarting DuetControlServer and reloading the page seems to get it going again.

info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action method DuetWebServer.Controllers.MachineController.DoCode (DuetWebServer) - Validation state: Valid
info: DuetWebServer.Controllers.MachineController[0]
      [DoCode] Executing code 'G28 X'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://10.10.0.193/js/app.492b2e82.js.map
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
      Sending file. Request path: '/js/app.492b2e82.js.map'. Physical path: '/opt/dsf/sd/www/js/app.492b2e82.js.map'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 6568.5538ms 200 text/plain
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action method DuetWebServer.Controllers.MachineController.Get (DuetWebServer), returned result Microsoft.AspNetCore.Mvc.EmptyResult in 356428.1503ms.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action method DuetWebServer.Controllers.MachineController.Get (DuetWebServer), returned result Microsoft.AspNetCore.Mvc.EmptyResult in 2968344.1988ms.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action DuetWebServer.Controllers.MachineController.Get (DuetWebServer) in 2968345.7494ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'DuetWebServer.Controllers.MachineController.Get (DuetWebServer)'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 2968360.1028ms 101
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action DuetWebServer.Controllers.MachineController.Get (DuetWebServer) in 356430.4367ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'DuetWebServer.Controllers.MachineController.Get (DuetWebServer)'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 356440.4761ms 101
[info] Sent G28 X"", remaining space 484 (996 total), needed 28
[info] Executing nested macro file '/opt/dsf/sd/sys/homex.g' on channel HTTP
[info] Sent G91 ; relative positioning, remaining space 492 (1004 total), needed 20
[info] Sent G1 H1 X3000 F1000 ;fast home x, remaining space 448 (960 total), needed 44
[info] Sent G1 X-1 F1000 ;move off endstops, remaining space 412 (924 total), needed 36
[info] Sent G1 H1 X10 F100, remaining space 368 (880 total), needed 44
[info] Sent G90 ; absolute positioning, remaining space 348 (860 total), needed 20
[info] Completed G91 ; relative positioning
[info] Completed G1 H1 X3000 F1000 ;fast home x
[info] Completed G1 X-1 F1000 ;move off endstops
; config.g
M584 X5 Y1 Z2           ;driver 0 is toast, move X to 5(test whole chain)
;M569 P0 D3 V4000       ;toast
M569 P1 S1 D3 V4000     ;Y
M569 P2 S0 D3 V4000     ;Z
M569 P5 S1 D3 V4000     ;X

M208 X200 Y200 Z90      ;work area
M350 X16 Y16 Z16 I1     ;microsteps w/interpolation
M92 X640 Y640 Z1280     ;steps/mm
M906 X1000 Y1000 Z1000  ;current limits
M201 X200 Y200 Z100     ;acceleration mm/sec^2 (or M204?)
M203 X2000 Y2000 Z1000  ;max feed rate mm/min
M205 X50 Y50 Z25        ;jerk mm/sec

M574 X2 S1 P"io0.in"    ; pnp no x max
M574 Y1 S1 P"io1.in"    ; pnp no y min
M574 Z2 S1 P"io2.in"    ; pnp no z max
; homeall.g
G91
;G1 H1 X3000 Y-4000 Z900 F1500;doesn't work?!
G1 H1 Z900 F1000              ;fast home z
G1 H1 X3000 F1000             ;fast home x
G1 H1 Y-4000 F1000            ;fast home y
G1 H2 X-1 Y1 Z-1 F1000        ;move off endstops
;G1 H1 X10 Y-10 Z10 F100       ;accurately home x/y/z
G1 H1 X10 F100
G1 H1 Y-10 F100
G1 H1 Z10 F100       ;accurately home x/y/z
G90

Resume button doesn't work

Pausing a print works, and the pause.g file is executed if it is present. But the print can't be resumed. When the resume button is pressed, resume.g is executed if it is present, but then the print hangs. It can be paused again.

DSF GCode command parser requires additional spaces

On Duet 3 if I send "M302P1" from the GCode console it returns "Error: Bad command". Command "M302 P1" works properly. Both versions work on Duet 2. [Note: parameter letter E is a special case, an E parameter must always be preceded by a space.]

Failed to add /run/systemd/ask-password to directory watch: No space left on device

pi@duet3:~ $ sudo /bin/systemctl stop duetwebserver
Failed to add /run/systemd/ask-password to directory watch: No space left on device

Webserver seems to be stopped, but this message is output (occasionally?). Have been an issue with all versions tested so far.

Plain Debian Stretch (lite) with screen and rng-tools as only non standard software.

G32 with manual probing does not stop

duetcontrolserver=1.0.3.1-1
duetruntime=1.0.3.1-1
duetsd=1.0.1-4
duettools=1.0.3.1-1
duetwebcontrol=2.0.0.RC8.b3-1
duetwebserver=1.1.0.0-1
duet3firmware=3.0b7-ch@2019-08-07b2

Running G32 with manual probing will result in the head moving to all configured points but only stopping at the last point in bed.g and then displaying the manual jog dialog.

Contents of bed.g:

M561 ; clear any bed transform, otherwise homing may be at the wrong height
G28 ; home

G30 P2 X5.5   Y214.5 Z-99999    ; probe near adjusting screw back left
G30 P1 X214.5 Y214.5 Z-99999    ; probe near adjusting screw back right
G30 P2 X121   Y3.2   Z-99999 S3 ; probe near adjusting screw front center and report adjustments needed

sudo systemctl enable fails on stretch

Followed https://duet3d.dozuki.com/Wiki/Duet_3_prototype_guide_for_OEMs

sudo systemctl start duetcontrolserver works without errors but enable fails as shown below.
same problem with duetwebserver

pi@octopi:~ $ sudo ln -s /opt/dsf/services/duetcontrolserver.service /etc/systemd/system/duetcontrolserver.service
pi@octopi:~ $ sudo ln -s /opt/dsf/services/duetwebserver.service /etc/systemd/system/duetwebserver.service
pi@octopi:~ $ sudo systemctl daemon-reload
pi@octopi:~ $ sudo systemctl start duetcontrolserver
pi@octopi:~ $ sudo systemctl |grep  duetcontrolserver
duetcontrolserver.service                                                                            loaded active running   Duet Control Server                                      
pi@octopi:~ $ sudo systemctl enable duetcontrolserver
Failed to enable unit: File duetcontrolserver.service: No such file or directory

and stack trace if that helps
strace.log

edit; versions and stuffs

pi@octopi:~ $ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
NAME="Raspbian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
pi@octopi:~ $ uname -a
Linux octopi 4.14.79-v7+ #1159 SMP Sun Nov 4 17:50:20 GMT 2018 armv7l GNU/Linux
pi@octopi:~ $

DWC/DCS now extremely slow to respond

Related to #23

Since the versions that included buffering i have noticed a very significant slowdown in DWC response, which shows as a very slow rate of gcodes being sent by DCS. Response times are now so laggy that its usual for me to have multiple different commands sent by DWC "queued up" (i.e. i have pressed a button i am used to completing instantly, like set temperature) and because it has taken so long to complete i have sent more commands before it completes. This has caused crashes:

info] Completed G10 P0 S200
[warn] Handled exception: System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetResult(TResult result)
   at DuetControlServer.SPI.QueuedCode.SetFinished() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/QueuedCode.cs:line 132
   at DuetControlServer.SPI.QueuedCode.HandleReply(MessageTypeFlags messageType, String reply) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/QueuedCode.cs:line 99
   at DuetControlServer.SPI.ChannelInformation.Invalidate(String codeErrorMessage) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Channel.cs:line 533
   at DuetControlServer.SPI.Interface.InvalidateData(String codeErrorMessage) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Interface.cs:line 755
   at DuetControlServer.SPI.Interface.RequestEmergencyStop() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Interface.cs:line 173
   at DuetControlServer.Codes.MCodes.Process(Code code) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Codes/MCodes.cs:line 227
   at DuetControlServer.Commands.Code.ExecuteInternally() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Commands/Code.cs:line 147
[info] Completed M140 P0 S60
[info] Completed T0
[info] Completed M122
System.AggregateException: One or more errors occurred. (An attempt was made to transition a task to a final state when it had already completed.) ---> System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetResult(TResult result)
   at DuetControlServer.SPI.QueuedCode.SetFinished() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/QueuedCode.cs:line 132
   at DuetControlServer.SPI.QueuedCode.HandleReply(MessageTypeFlags messageType, String reply) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/QueuedCode.cs:line 99
   at DuetControlServer.SPI.ChannelInformation.Invalidate(String codeErrorMessage) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Channel.cs:line 533
   at DuetControlServer.SPI.Interface.InvalidateData(String codeErrorMessage) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Interface.cs:line 755
   at DuetControlServer.SPI.Interface.RequestEmergencyStop() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Interface.cs:line 173
   at DuetControlServer.Codes.MCodes.Process(Code code) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Codes/MCodes.cs:line 227
   at DuetControlServer.Commands.Code.ExecuteInternally() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Commands/Code.cs:line 147
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at DuetControlServer.Commands.Code.Enqueue() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Commands/Code.cs:line 109
   at DuetControlServer.Commands.SimpleCode.Execute() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Commands/SimpleCode.cs:line 31
   at DuetAPI.Commands.Command`1.Invoke() in /home/christian/duet/DuetSoftwareFramework/src/DuetAPI/Commands/BaseCommand.cs:line 86
   at DuetControlServer.IPC.Processors.Command.Process() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/IPC/Processors/Command.cs:line 61
---> (Inner Exception #0) System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
   at System.Threading.Tasks.TaskCompletionSource`1.SetResult(TResult result)
   at DuetControlServer.SPI.QueuedCode.SetFinished() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/QueuedCode.cs:line 132
   at DuetControlServer.SPI.QueuedCode.HandleReply(MessageTypeFlags messageType, String reply) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/QueuedCode.cs:line 99
   at DuetControlServer.SPI.ChannelInformation.Invalidate(String codeErrorMessage) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Channel.cs:line 533
   at DuetControlServer.SPI.Interface.InvalidateData(String codeErrorMessage) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Interface.cs:line 755
   at DuetControlServer.SPI.Interface.RequestEmergencyStop() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/SPI/Interface.cs:line 173
   at DuetControlServer.Codes.MCodes.Process(Code code) in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Codes/MCodes.cs:line 227
   at DuetControlServer.Commands.Code.ExecuteInternally() in /home/christian/duet/DuetSoftwareFramework/src/DuetControlServer/Commands/Code.cs:line 147<---

and out of sync errors

"[warn] Received out-of-sync code reply (HttpMessage, BinaryCodeReplyFlag: )"

it is also makes the UI highly frustrating to use.

I only noticed this on the most recent versions of DCS (1.0.1.0 and later) so it don't think its an issue with the underlying SPI speed (i have this set to 5Mhz). is DCS/RRF waiting for a buffer to be full before sending it?

Edit
It also applies to gcode sent when printing a file.. Looking at M122:

Code buffer space: 1144
SPI speed: 5000000 Hz
Full transfers per second: 0.95

Filenames are case-sensitive

Filenames in RRF have always been case-insensitive in the past, however in DSF they are case-sensitive. For example, if a M98 command is used to run a macro and the filename is not in exactly the correct case, then the file is not found.

DWC not honoring jog button speed

DCS: 1.0.2.1
DWS: 1.0.1.1
DWC: 2.0.0-RC8-b1

Not sure if this belongs here or to DWC.
The jog buttons will run GCode with F18000 (a value I set at some time in the past on Duet 2 and I copied the DWC settings file over). Channing the value in DWC Machine-specific settings tab does not affect which value is used. The changed value is persisted to dwc2settings.json, though.

G91 G0 Y10 = G91

Not sure if this is a firmware, DSF issue or a non issue

But running G91 G0 Y10 seems to result in G0 Y10 being ignored, but relative mode does get set.

Similar with G90.

(I'm open to changing the title to something more descriptive:)

[info] Sent G91 G0 X1, remaining space 1024, need 36
[info] Completed G91 G0 X1

Only found this in the DuetControlServer output, but the same things happens regardless of x,y and z.

M550 is ignored

duetcontrolserver=1.0.2.1-1
duetruntime=1.0.2.1-1
duetsd=1.0.1-2
duetsoftwareframework-meta=1.0.2.1-1
duettools=1.0.2.1-1
duetwebcontrol=2.0.0.RC8.b1-1
duetwebserver=1.0.1.1-1
duet3firmware=3.0b6-ch@2019-07-21b1

Instead of using the name of the device set via M550 DWC will display the hostname of the RPi that is serving DWC.

Shown Fan RPM increases as speed decrease

Possibly a RRF 3 issue and not a DFS issue?

In any case after configuring fan with tach output the shown RPM increases as the fan is slowed down.

3 pin fan
positive --> V_OUTLC1
negative --> OUT_4
tach --> OUT4.tach

M950 F2 C"out4+out4.tach" ;Fan RPM not shown 
M106 P2 S0    ;Fan RPM not shown 
M106 P2 S1    ;Fan RPM show ~5500 RPM
M106 P2 S0.5  ;Fan RPM show ~9000 RPM

edit: possibly a fan issue - physically slowing down the fan has the correct effect on the RPM sensor. will get new batteries for tachometer and get the scope out to do some measurements next week

DCS blocks while executing start.g

duetcontrolserver=1.0.2.2-1
RRF=3.0b7-ch@2019-07-26b1

When trying to print something DCS will send the very first line of start.g and then block completely. It will no longer send status updates to DWS and will not react to Emergency Stop button clicks in DWC. DCS has to be restarted in order to interact with it again.

Log excerpt


Aug 02 13:12:13 duet3 DuetControlServer[2723]: Duet Control Server v1.0.2.2
Aug 02 13:12:13 duet3 DuetControlServer[2723]: Written by Christian Hammacher for Duet3D
Aug 02 13:12:13 duet3 DuetControlServer[2723]: Licensed under the terms of the GNU Public License Version 3
Aug 02 13:12:15 duet3 DuetControlServer[2723]: Loading settings... Done!
Aug 02 13:12:15 duet3 DuetControlServer[2723]: Initialising object model... Done!
Aug 02 13:12:15 duet3 DuetControlServer[2723]: Connecting to RepRapFirmware... Done!
Aug 02 13:12:15 duet3 DuetControlServer[2723]: Creating IPC socket... Done!
Aug 02 13:12:47 duet3 DuetControlServer[2723]: [info] Printing file '/opt/dsf/sd/gcodes/topsurface.gcode'
Aug 02 13:12:47 duet3 DuetControlServer[2723]: [info] Executing system macro file '/opt/dsf/sd/sys/start.g' on channel File
Aug 02 13:12:47 duet3 DuetControlServer[2723]: [info] Sent M80 ; Turn the VIN PSU on, remaining space 748 (2028 total), needed 20

Nothing happens then anymore until restart of DCS.

Also after having restarted DCS if the heaters were turned on before they will all be off then. This is not the case if DCS is restarted while it is still working.

M291 does not work

DCS: 1.0.1.0
RRF: 70b8084b0d713001e5594d570107d854269562bc

M291 does not show a message/jog dialog in DWC.

This also breaks G29 and G32 if Z probe is set to manual via M558 P0. In these cases the head will just continue moving in the defined sequence and does not stop to let the user jog to the correct position.

Fast-clicked multi-line commands from DWC are executed out-of-order

DCS: 1.0.1.0
RRF: 70b8084b0d713001e5594d570107d854269562bc
DWC: 2.0.0RC7
DWS: 1.0.0.3

If you click e.g. a jog button in DWC faster than it takes for each click to execute fully it will happen that the associated codes are executed out of order. Since jog buttons switch temporarily to relative positions, move the head and switch back to absolute positions this can lead to the axis moving to absolute 10mm instead of increasing the current position by 10mm because one of the later move commands is executed before its corresponding relative-movements command.

Connection issues behind reverse proxy

duetcontrolserver=1.0.2.1-1
duetruntime=1.0.2.1-1
duetsd=1.0.1-2
duetsoftwareframework-meta=1.0.2.1-1
duettools=1.0.2.1-1
duetwebcontrol=2.0.0.RC8.b1-1
duetwebserver=1.0.1.1-1
duet3firmware=3.0b6-ch@2019-07-21b1

This is new with the latest release. I get lots of connection

Connection interrupted, attempting to reconnect...
Network error

when connecting through a reverse proxy (nginx) to load DWC. This was working without any issues before.

Spurious Motor(#) temp high

Server control terminal will spuriously report "high temperature reported by driver(s) X" These often occur after an estop or some sort of restart. Those motors are often not even involved in the movement and sometimes not even connect, just configured.

Running an M122 immediately after warning does not show any stepper driver issue.

When in Subscription Patch Connection, model is not updated

In release 1.0.2.1, we are connecting to the DCS using a subscription patch connection. We have observed that the DCS sends the first full update of the Model, but it doesn't send any further patch updates unless any other client connects to the DCS with a patch connection (for example opening the DWS web page). In previous releases we didn't have this problem.

DWC requires reload after board reset

duetcontrolserver 1.0.2.2
duetruntime 1.0.2.1
duetsoftwareframework 1.0.2.1
duetwebcontrol 2.0.0-2
duetwebserver 1.0.1.1

Issue: The Extrude/Retract buttons do not work in DWC after an emergency stop until DWC is reloaded (normally by refreshing the page using F5)

How to recreate: Use emergency stop to reset the Duet. Once the reset has completed ensure the hotend is up to temperature, then prese Extruder/Retract. No commands will be sent to DCS (and DWS does not report the button presses). Refresh the page (F5) try Extrude/Retract again. The commands are now sent to DWS->DCS.

Commands from DWC while printing lead to stop

DCS: 1.0.1.0
RRF: 70b8084b0d713001e5594d570107d854269562bc
DWC: 2.0.0RC7
DWS: 1.0.0.3

If a print is started any command sent from DWC while the print is running will lead to the print stopping at whatever command it is a few seconds after the DWC-issued command was executed. The printer does no longer react to any commands from DWC after that.

Restarting DCS is the only solution to gain back control.

Memory leak in DCS

DCS: 1.0.1.0

DuetControlServer has a memory leak. It will request additional ~80MiB/hour. This is linear and does not depend on any process being connected as a client to DCS.

Assigned filaments are not restored

DCS: 1.0.1.0
RRF: 70b8084b0d713001e5594d570107d854269562bc

After a reset the filaments assigned to an extruder are not restored from /sys/filaments.csv. Since many people (me included) do put filament-specific configuration into the associated /filaments/*/config.g this can lead to prints failing.

M569 works only for driver 0.0

duetcontrolserver=1.0.2.2-1
RRF=3.0b7-ch@2019-07-26b1

In the latest version of DuetAPI Pnnn parameters of M569 are converted into DriverId type. In RRF though this is still read with gb.GetIValue() and it will always only parse driver 0 out of this. This way all drivers except driver 0 are set to defaults and driver 0 receives the settings of the last seen M569 command.

M111 results in 19 separate messages

DCS: 1.0.1.0
RRF: 70b8084b0d713001e5594d570107d854269562bc
DWC: 2.0.0RC7
DWS: 1.0.0.3

Issuing M111 to see the status of debugging will return 19 separate messages popping up in DWC. One for each module plus one for the header lines (enabled/disabled modules).

Inconsistent file ownership in virtual SD folder

After trying to edit some of the config files from the ssh shell I notice ownership is inconsistent.

config.g is owned by root, the other by pi. I change all ownership to pi.

pi@duet3:~ $ ls -lh  /opt/dsf/sd/sys/
total 64K
-rw-r--r-- 1 root root  614 Jul 29 12:14 config.g
-rw-r--r-- 1 root root  613 Jul 29 11:36 config.g.bak
-rw-r--r-- 1 pi   pi   3.1K Jul 22 16:05 dwc2settings.json
-rw-r--r-- 1 pi   pi    521 Jul 29 12:07 homeall.g
-rw-r--r-- 1 pi   pi    486 Jul 29 12:17 homex.g
-rw-r--r-- 1 pi   pi    625 Jul 28 11:48 homey.g
-rw-r--r-- 1 pi   pi    383 Jul 28 11:46 homez.g
-rwxr-xr-x 1 pi   pi    34K Jul 21 09:15 iapduet3.bin
pi@duet3:~ $ sudo chown -R pi:pi  /opt/dsf/sd/sys/
pi@duet3:~ $ ls -lh  /opt/dsf/sd/sys/
total 64K
-rw-r--r-- 1 pi pi  614 Jul 29 12:14 config.g
-rw-r--r-- 1 pi pi  613 Jul 29 11:36 config.g.bak
-rw-r--r-- 1 pi pi 3.1K Jul 22 16:05 dwc2settings.json
-rw-r--r-- 1 pi pi  521 Jul 29 12:07 homeall.g
-rw-r--r-- 1 pi pi  486 Jul 29 12:17 homex.g
-rw-r--r-- 1 pi pi  625 Jul 28 11:48 homey.g
-rw-r--r-- 1 pi pi  383 Jul 28 11:46 homez.g
-rwxr-xr-x 1 pi pi  34K Jul 21 09:15 iapduet3.bin

Now I edit config.g and homeall.g in DWS and check again:

pi@duet3:~ $ ls -lh  /opt/dsf/sd/sys/
total 64K
-rw-r--r-- 1 root root  613 Jul 29 12:34 config.g
-rw-r--r-- 1 pi   pi    614 Jul 29 12:14 config.g.bak
-rw-r--r-- 1 pi   pi   3.1K Jul 22 16:05 dwc2settings.json
-rw-r--r-- 1 pi   pi    521 Jul 29 12:35 homeall.g
-rw-r--r-- 1 pi   pi    486 Jul 29 12:17 homex.g
-rw-r--r-- 1 pi   pi    625 Jul 28 11:48 homey.g
-rw-r--r-- 1 pi   pi    383 Jul 28 11:46 homez.g
-rwxr-xr-x 1 pi   pi    34K Jul 21 09:15 iapduet3.bin

Only config.g has changed owner to root again, not homeall.g

Macro calling another macro and having blocking M291 stalls

duetcontrolserver=1.0.3.1-1
duetruntime=1.0.3.1-1
duetsd=1.0.1-4
duettools=1.0.3.1-1
duetwebcontrol=2.0.0.RC8.b3-1
duetwebserver=1.1.0.0-1
duet3firmware=3.0b7-ch@2019-08-07b2

Having a macro that calls another macro (directly or via e.g. G28) and also having M291 in there which has S2 or S3 will stall and requires a reset of the Duet.

Minimal example

G28
M291 S2 P"message"

DCS not connecting to RRF on RPi 4B

duetcontrolserver=1.0.2.1-1
duetruntime=1.0.2.1-1
duetsd=1.0.1-2
duetsoftwareframework-meta=1.0.2.1-1
duettools=1.0.2.1-1
duetwebcontrol=2.0.0.RC8.b1-1
duetwebserver=1.0.1.1-1
duet3firmware=3.0b6-ch@2019-07-21b1

I received my RPi 4B today and right now I cannot use it to connect DCS to RRF. It just states "Duet is not available" and exits.

Is there any config flag to make it more verbose about this or do I need to add more logging to DCS to find out what is going wrong?

I know that instructions ask for a RPi 3B+ but since it was also working with my RPi 3B (without the plus) and 4B has the same GPIO layout I assumed it would also work out of the box.

M98 parsing error

Command M98 P"config.g" sent from DWC works. Command M98 Pconfig.g doesn't work and reports "File Pconfig.g not found". Interestingly, command M98 P"a.g" where file a.g doesn't exist reports "Fila Pa.g not found" instead of "File a.g not found".

Interruptible gcode commands

M280 command seems to be able to interrupt/ occur in parallel with G1 move commands.

For example:
Current X location is at 0
G1 X300 F5000
M280 P0 S175

While moving to the 300 in the X, the servo will actuate instead of actuating after arriving at X300.

Currently must use M400 after the G1 command to gate the M280 command.

M115 does not work on serial/USB

Wanted to grab the FW version from M115 off the serial, but when sending M115 the response is Emulation of unknown is not yet supported. M115 works as expected in Web UI.

Unable to start DWS via systemd

DWS: 1.0.0.3+

I cannot start DWS as systemd unit. The binary will start and has a PID but the webserver itself will not initialize. There is no output to the journal or a manually added output file for logging. It runs fine when started manually via command line. Then it also can be backgrounded with output redirect.

This is running Arch Linux ARM. Does it work on Raspbian?

estop interrupt stack issue

  1. Execute any macro, system or user created (ie. homex, home all)
  2. WHILE macro is in progress click emergency stop.
  3. When duet reboots and is idle, macros no longer work, they will hang.
  4. Another emergency stop cycle is required for everything to work again.

Date and time on Duet not initialized

Previously DWC would send the current date and time when connecting via rr_connect?password=xxx&time=... but this does not happen anymore. So now the Duet won't get any more information about current date and time.

This could be implemented to happen upon successful connection of DCS to RRF via M905.

DCS does max out one CPU core

duetcontrolserver=1.0.2.2

As the title says, DCS does max out one of the CPU cores (96%) of my RPi 4B just with status updates. If no client is connected, i.e. DWS stopped (or simply no client connected to running DWS) it still uses 50-60% of one CPU core. This is a lot of resources for basically "doing nothing".

Heaters shut off while printing

DCS: 1.0.1.0
RRF: 70b8084b0d713001e5594d570107d854269562bc
DWC: 2.0.0RC7
DWS: 1.0.0.3

While printing all heaters will be shut-off without any further notice after a couple of minutes. Trying to re-enable them via DWC leads to the print failing because of #24.

DWC not continuously updating anymore

DCS: 1.0.2.1
DWS: 1.0.1.1
DWC: 2.0.0-RC8-b1
RRF: 1c85904a

Since updating to the latest DuetSoftwareFramework and RRF DWC no longer continuously updates values like temperatures, current VIN value, DHT sensor values. Sometimes it also does not populate the tools section of DWC. This is with the printer being idle. I did not yet test while printing.

EDIT: This also leads to ATX Power Control Panel being hidden until M80 (or I assume also M81) is sent manually.

DCS blocks after executing a macro

DCS: 1.0.2.1
DWS: 1.0.1.1
DWC: 2.0.0-RC8-b1
RRF: 1c85904a

When clicking a macro in DWC this will be executed but then DCS is blocked (on this channel?). In logging it also states it finished the macro but no more commands are accepted. Restarting DCS fixes the problem.

EDIT: DCS never returns the information that the macro has been executed to DWC. DWC continues showing a spinner and once DCS is being restarted it will show an error pop-up that executing the macro failed (though it actually executed).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.