diff --git a/CHANGELOG.txt b/CHANGELOG.txt index b5fb4de5..aee73d91 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,7 @@ +v1.0.379: +- Major improvements to USB connection steps, +- set up parser before checking for firmware +- Added more grblHAL errors/settings descriptions v1.0.378: - Test fix for 4X hanging on DTR connect v1.0.377: diff --git a/app/js/grbl-settings-templates.js b/app/js/grbl-settings-templates.js index 8405e8a8..40014356 100644 --- a/app/js/grbl-settings-templates.js +++ b/app/js/grbl-settings-templates.js @@ -885,5 +885,20 @@ var grblSettingsTemplate2 = { description: `Auto mount SD card on startup. 0 - Auto mount SD card (1) / 1 - Hide LittleFS (2)`, template: ``, utils: `` + }, + 328: { + key: `$328`, + title: `FTP port, range: 1 - 65535, reboot required`, + description: `FTP port number listening for incoming connections. NOTE: A hard reset of the controller is required after changing this setting.`, + template: ``, + utils: `` + }, + 372: { + key: `$372`, + title: `Invert I/O Port outputs as bitfield`, + description: ` Invert I/O Port outputs as bitfield`, + template: ``, + utils: `` } + } \ No newline at end of file diff --git a/app/js/websocket.js b/app/js/websocket.js index ebf4d867..02691d3c 100644 --- a/app/js/websocket.js +++ b/app/js/websocket.js @@ -1224,7 +1224,7 @@ function friendlyPort(i) { if (laststatus.comms.interfaces.ports[i].productId == '6015' && laststatus.comms.interfaces.ports[i].vendorId == '1D50') { // found Smoothieboard img = 'smoothieboard.png'; - note = 'Smoothieware USB Port'; + note = 'Smoothieware USB Port (Not Supported)'; } if (laststatus.comms.interfaces.ports[i].productId == '6001' && laststatus.comms.interfaces.ports[i].vendorId == '0403') { // found FTDI FT232 @@ -1259,7 +1259,7 @@ function friendlyPort(i) { if (laststatus.comms.interfaces.ports[i].productId == '7523' && laststatus.comms.interfaces.ports[i].vendorId == '1A86') { // found CH340 img = 'uno.png'; - note = 'CH340 Arduino Fake'; + note = 'WCH.cn CH340 USB to UART'; } if (laststatus.comms.interfaces.ports[i].productId == 'EA60' && laststatus.comms.interfaces.ports[i].vendorId == '10C4') { // found CP2102 @@ -1269,7 +1269,7 @@ function friendlyPort(i) { if (laststatus.comms.interfaces.ports[i].productId == '000A' && laststatus.comms.interfaces.ports[i].vendorId == '2E8A') { // found CP2102 img = 'pipico.png'; - note = 'Raspberry Pi Pico CDC AURT'; + note = 'Raspberry Pi Pico CDC UART (Not Supported)'; } if (laststatus.comms.interfaces.ports[i].productId == '2303' && laststatus.comms.interfaces.ports[i].vendorId == '067B') { // found CP2102 diff --git a/grblStrings.js b/grblStrings.js index e7b57996..4f7882c9 100644 --- a/grblStrings.js +++ b/grblStrings.js @@ -2,44 +2,74 @@ var exports = module.exports = {}; var grblErrorCodes = { - 0: "no error", + 0: "No error", 1: "G-code words consist of a letter and a value. Letter was not found.", - 2: "Numeric value format is not valid or missing an expected value.", - 3: "Grbl '$' system command was not recognized or supported.", + 2: "Missing the expected G-code word value or numeric value format is not valid.", + 3: "'$' system command was not recognized or supported.", 4: "Negative value received for an expected positive value.", - 5: "Homing cycle is not enabled via settings.", - 6: "Minimum step pulse time must be greater than 3usec", - 7: "EEPROM read failed. Reset and restored to default values.", - 8: "Grbl '$' command cannot be used unless Grbl is IDLE. Ensures smooth operation during a job.", - 9: "G-code locked out during alarm or jog state", + 5: "Homing cycle failure. Homing is not configured via settings.", + 6: "Step pulse time must be greater or equal to 2 microseconds.", + 7: "A settings read failed. Auto-restoring affected settings to default values.", + 8: "'$' command cannot be used unless controller state is IDLE. Ensures smooth operation during a job.", + 9: "G-code commands are locked out during alarm or jog state.", 10: "Soft limits cannot be enabled without homing also enabled.", - 11: "Max characters per line exceeded. Line was not processed and executed.", - 12: "(Compile Option) Grbl '$' setting value exceeds the maximum step rate supported.", + 11: "Max characters per line exceeded. Received command line was not executed.", + 12: "'$' setting value causes the step rate to exceed the maximum supported.", 13: "Safety door detected as opened and door state initiated.", - 14: "(Grbl-Mega Only) Build info or startup line exceeded EEPROM line length limit.", - 15: "Jog target exceeds machine travel. Command ignored.", - 16: "Jog command with no '=' or contains prohibited g-code.", - 20: "Unsupported or invalid g-code command found in block.", - 21: "More than one g-code command from same modal group found in block.", + 14: "Build info or startup line exceeded line length limit. Line not stored.", + 15: "Jog target exceeds machine travel. Jog command has been ignored.", + 16: "Jog command has no '=' or contains prohibited G-code.", + 17: "Laser mode requires PWM output.", + 18: "Reset asserted.", + 19: "Non positive value.", + 20: "Unsupported or invalid G-code command found in block.", + 21: "More than one G-code command from same modal group found in block.", 22: "Feed rate has not yet been set or is undefined.", 23: "G-code command in block requires an integer value.", - 24: "Two G-code commands that both require the use of the XYZ axis words were detected in the block.", - 25: "A G-code word was repeated in the block.", - 26: "A G-code command implicitly or explicitly requires XYZ axis words in the block, but none were detected.", - 27: "N line number value is not within the valid range of 1 - 9,999,999.", - 28: "A G-code command was sent, but is missing some required P or L value words in the line.", - 29: "Grbl supports six work coordinate systems G54-G59. G59.1, G59.2, and G59.3 are not supported.", - 30: "The G53 G-code command requires either a G0 seek or G1 feed motion mode to be active. A different motion was active.", - 31: "There are unused axis words in the block and G80 motion mode cancel is active.", - 32: "A G2 or G3 arc was commanded but there are no XYZ axis words in the selected plane to trace the arc.", - 33: "The motion command has an invalid target. G2, G3, and G38.2 generates this error, if the arc is impossible to generate or if the probe target is the current position.", - 34: "A G2 or G3 arc, traced with the radius definition, had a mathematical error when computing the arc geometry. Try either breaking up the arc into semi-circles or quadrants, or redefine them with the arc offset definition.", - 35: "A G2 or G3 arc, traced with the offset definition, is missing the IJK offset word in the selected plane to trace the arc.", - 36: "There are unused, leftover G-code words that aren't used by any command in the block.", - 37: "The G43.1 dynamic tool length offset command cannot apply an offset to an axis other than its configured axis. The Grbl default axis is the Z-axis.", - 46: "Home machine to continue" + 24: "More than one G-code command that requires axis words found in block.", + 25: "Repeated G-code word found in block.", + 26: "No axis words found in block for G-code command or current modal state which requires them.", + 27: "Line number value is invalid.", + 28: "G-code command is missing a required value word.", + 29: "G59.x work coordinate systems are not supported.", + 30: "G53 only allowed with G0 and G1 motion modes.", + 31: "Axis words found in block when no command or current modal state uses them.", + 32: "G2 and G3 arcs require at least one in-plane axis word.", + 33: "Motion command target is invalid.", + 34: "Arc radius value is invalid.", + 35: "G2 and G3 arcs require at least one in-plane offset word.", + 36: "Unused value words found in block.", + 37: "G43.1 dynamic tool length offset is not assigned to configured tool length axis.", + 38: "Tool number greater than max supported value or undefined tool selected.", + 39: "Value out of range.", + 40: "G-code command not allowed when tool change is pending.", + 41: "Spindle not running when motion commanded in CSS or spindle sync mode.", + 42: "Plane must be ZX for threading.", + 43: "Max. feed rate exceeded.", + 44: "RPM out of range.", + 45: "Only homing is allowed when a limit switch is engaged.", + 46: "Home machine to continue.", + 47: "ATC: current tool is not set. Set current tool with M61.", + 48: "Value word conflict.", + 49: "Power on self test failed. A hard reset is required.", + 50: "Emergency stop active.", + 51: "Motor fault.", + 52: "Setting value is out of range.", + 53: "Setting is not available, possibly due to limited driver support.", + 54: "Retract position is less than drill depth.", + 55: "Attempt to home two auto squared axes at the same time.", + 56: "Coordinate system is locked.", + 60: "SD Card mount failed.", + 61: "SD Card file open/read failed.", + 62: "SD Card directory listing failed.", + 63: "SD Card directory not found.", + 64: "SD Card file empty.", + 77: "Authentication required.", + 78: "Access denied.", + 79: "Not allowed while critical event is active." }; + var grblAlarmCodes = { 0: "no alarm", 1: "Hard limit triggered. Machine position is likely lost due to sudden and immediate halt. Re-homing is highly recommended.", @@ -58,7 +88,8 @@ var grblAlarmCodes = { 14: "Spindle at speed timeout. Clear before continuing.", 15: "Homing fail. Could not find second limit switch for auto squared axis within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring.", 16: "Power on selftest (POS) failed.", - 17: "Motor fault." + 17: "Motor fault.", + 18: "Homing fail. Bad configuration." }; var grblSettingCodes = { @@ -157,8 +188,9 @@ var grblSettingCodes = { 484: "Unlock required after E-Stop as boolean", 486: "Lock coordinate systems against accidental changes", 650: "File systems options as bitfield", // Auto mount SD? - 673: "Coolant on delay in s after Feedhold resume" - + 673: "Coolant on delay in s after Feedhold resume", + 328: "FTP port, range: 1 - 65535, reboot required", + 372: "Invert I/O Port outputs as bitfield:" }; exports.errors = function(id) { diff --git a/index.js b/index.js index c3bf5e8c..ae653b01 100644 --- a/index.js +++ b/index.js @@ -60,7 +60,7 @@ config.nextWebPort = function() { config.webPort = process.env.WEB_PORT || config.nextWebPort(); config.posDecimals = process.env.DRO_DECIMALS || 3; config.grblWaitTime = 0.5; -config.firmwareWaitTime = 4; + var express = require("express"); var app = express(); @@ -1205,8 +1205,386 @@ io.on("connection", function(socket) { stopPort() // also clear queues etc }); // end port.onclose + function portOpened(port, data) { + // setup listeners first + + parser.on("data", function(data) { + //console.log(data) + var command = sentBuffer[0]; + + if (command == "$CD" && data != "ok") { + fluidncConfig = fluidncConfig += data + "\n" + } + + if (data.indexOf("<") != 0) { + debug_log('data:', data) + } + + // Grbl $I parser + if (data.indexOf("[VER:") === 0) { + status.machine.name = data.split(':')[2].split(']')[0].toLowerCase() + io.sockets.emit("status", status); + io.sockets.emit("machinename", data.split(':')[2].split(']')[0].toLowerCase()); + status.machine.firmware.date = data.split(':')[1].split(".")[2]; + } + + if (data.indexOf("[OPT:") === 0) { + + var startOpt = data.search(/opt:/i) + 4; + var grblOpt; + if (startOpt > 4) { + var grblOptLen = data.substr(startOpt).search(/]/); + grblOpts = data.substr(startOpt, grblOptLen).split(/,/); + + status.machine.firmware.blockBufferSize = grblOpts[1]; + status.machine.firmware.rxBufferSize = grblOpts[2]; + + var features = [] + + var i = grblOpts[0].length; + while (i--) { + features.push(grblOpts[0].charAt(i)) + switch (grblOpts[0].charAt(i)) { + case 'Q': + debug_log('SPINDLE_IS_SERVO Enabled') + // + break; + case 'V': // Variable spindle enabled + debug_log('Variable spindle enabled') + // + break; + case 'N': // Line numbers enabled + debug_log('Line numbers enabled') + // + break; + case 'M': // Mist coolant enabled + debug_log('Mist coolant enabled') + // + break; + case 'C': // CoreXY enabled + debug_log('CoreXY enabled') + // + break; + case 'P': // Parking motion enabled + debug_log('Parking motion enabled') + // + break; + case 'Z': // Homing force origin enabled + debug_log('Homing force origin enabled') + // + break; + case 'H': // Homing single axis enabled + debug_log('Homing single axis enabled') + // + break; + case 'T': // Two limit switches on axis enabled + debug_log('Two limit switches on axis enabled') + // + break; + case 'A': // Allow feed rate overrides in probe cycles + debug_log('Allow feed rate overrides in probe cycles') + // + break; + case '$': // Restore EEPROM $ settings disabled + debug_log('Restore EEPROM $ settings disabled') + // + break; + case '#': // Restore EEPROM parameter data disabled + debug_log('Restore EEPROM parameter data disabled') + // + break; + case 'I': // Build info write user string disabled + debug_log('Build info write user string disabled') + // + break; + case 'E': // Force sync upon EEPROM write disabled + debug_log('Force sync upon EEPROM write disabled') + // + break; + case 'W': // Force sync upon work coordinate offset change disabled + debug_log('Force sync upon work coordinate offset change disabled') + // + break; + case 'L': // Homing init lock sets Grbl into an alarm state upon power up + debug_log('Homing init lock sets Grbl into an alarm state upon power up') + // + break; + } + } + status.machine.firmware.features = features; + io.sockets.emit("features", features); + } + } + + // [PRB:0.000,0.000,0.000:0] + //if (data.indexOf("[PRB:") === 0 && command != "$#" && command != undefined) { + if (data.indexOf("[PRB:") === 0) { + debug_log(data) + var prbLen = data.substr(5).search(/\]/); + var prbData = data.substr(5, prbLen).split(/,/); + var success = data.split(':')[2].split(']')[0]; + status.machine.probe.x = prbData[0]; + status.machine.probe.y = prbData[1]; + status.machine.probe.z = prbData[2].split(':')[0]; + status.machine.probe.state = success; + if (success > 0) { + var output = { + 'command': '[ PROBE ]', + 'response': "Probe Completed.", + 'type': 'success' + } + io.sockets.emit('data', output); + } else { + var output = { + 'command': '[ PROBE ]', + 'response': "Probe move ERROR - probe did not make contact within specified distance", + 'type': 'error' + } + io.sockets.emit('data', output); + } + io.sockets.emit('prbResult', status.machine.probe); + }; + + if (data.indexOf("[GC:") === 0) { + gotModals(data) + } + + if (data.indexOf("[INTF:") === 0) { + var output = { + 'command': 'connect', + 'response': "Detected an OpenBuilds Interface on port " + port.path, + 'type': 'success' + } + io.sockets.emit('data', output); + status.interface.connected = true; + if (data.split(":")[1].indexOf("ver") == 0) { + var installedVersion = parseFloat(data.split(":")[1].split("]")[0].split("-")[1]) + status.interface.firmware.installedVersion = installedVersion + var output = { + 'command': 'connect', + 'response': "OpenBuilds Interface Firmware Version: v" + installedVersion, + 'type': 'info' + } + io.sockets.emit('data', output); + if (installedVersion < status.interface.firmware.availVersion) { + var output = { + 'command': 'connect', + 'response': "OpenBuilds Interface Firmware OUTDATED: v" + installedVersion + " can be upgraded to v" + status.interface.firmware.availVersion, + 'type': 'error' + } + io.sockets.emit('data', output); + io.sockets.emit('interfaceOutdated', status); + } + } + io.sockets.emit("status", status); + } + + // Machine Identification + if (data.indexOf("Grbl") === 0 || data.indexOf("[FIRMWARE:grblHAL]") === 0) { // Check if it's Grbl + debug_log(data) + status.comms.blocked = false; + if (data.indexOf("GrblHAL") === 0) { + status.machine.firmware.type = "grbl"; + status.machine.firmware.platform = "grblHAL" + status.machine.firmware.version = data.substr(8, 4); // get version + } else if (data.indexOf("[FIRMWARE:grblHAL]") === 0) { + status.machine.firmware.type = "grbl"; + status.machine.firmware.platform = "grblHAL" + // Parse version from seperate [VER:...] line not here for this response + } else if (data.indexOf("FluidNC") != -1) { // Grbl 3.6 [FluidNC v3.6.5 (wifi) '$' for help] + status.machine.firmware.type = "grbl"; + status.machine.firmware.platform = "FluidNC" + status.machine.firmware.version = data.substr(19, 5); // get version + } else { + status.machine.firmware.type = "grbl"; + status.machine.firmware.platform = "gnea" + status.machine.firmware.version = data.substr(5, 4); // get version + } + if (parseFloat(status.machine.firmware.version) < 1.1) { // If version is too old + if (status.machine.firmware.version.length < 3) { + debug_log('invalid version string, stay connected') + } else { + if (status.comms.connectionStatus > 0) { + debug_log('WARN: Closing Port ' + port.path + " / v" + parseFloat(status.machine.firmware.version)); + // stopPort(); + } else { + debug_log('ERROR: Machine connection not open!'); + } + var output = { + 'command': command, + 'response': "Detected an unsupported version: Grbl " + status.machine.firmware.version + ". This is sadly outdated. Please upgrade to Grbl 1.1 or newer to use this software. Go to http://github.com/gnea/grbl", + 'type': 'error' + } + io.sockets.emit('data', output); + } + } + status.machine.firmware.date = ""; + // debug_log("GRBL detected"); + // setTimeout(function() { + // io.sockets.emit('grbl', status.machine.firmware) + // //v1.0.318 - commented out as a test - too many normal alarms clear prematurely + // //io.sockets.emit('errorsCleared', true); + // }, 600) + // // Start interval for status queries + // clearInterval(statusLoop); + // statusLoop = setInterval(function() { + // if (status.comms.connectionStatus > 0) { + // addQRealtime("?"); + // } + // }, 200); + status.machine.modals.homedRecently = false; + } else if (data.indexOf("LPC176") >= 0) { // LPC1768 or LPC1769 should be Smoothieware + status.comms.blocked = false; + debug_log("Smoothieware detected"); + status.machine.firmware.type = "smoothie"; + status.machine.firmware.version = data.substr(data.search(/version:/i) + 9).split(/,/); + status.machine.firmware.date = new Date(data.substr(data.search(/Build date:/i) + 12).split(/,/)).toDateString(); + // Start interval for status queries + // statusLoop = setInterval(function() { + // if (status.comms.connectionStatus > 0) { + // addQRealtime("?"); + // } + // }, 200); + var output = { + 'command': "FIRMWARE ERROR", + 'response': "Detected an unsupported version: Smoothieware " + status.machine.firmware.version + ". This software no longer support Smoothieware. \nLuckilly there is an alternative firmware you can install on your controller to make it work with this software. Check out Grbl-LPC at https://github.com/cprezzi/grbl-LPC - Grbl-LPC is a Grbl port for controllers using the NXP LPC176x chips, for example Smoothieboards", + 'type': 'error' + } + io.sockets.emit('data', output); + stopPort(); + } // end of machine identification + + // Machine Feedback: Position + if (data.indexOf("<") === 0) { + // debug_log(' Got statusReport (Grbl & Smoothieware)') + // statusfeedback func + parseFeedback(data) + if (command == "?") { + var output = { + 'command': command, + 'response': data, + 'type': 'info' + } + // debug_log(output.response) + io.sockets.emit('data', output); + } + // debug_log(data) + } else if (data.indexOf("ok") === 0) { // Got an OK so we are clear to send + io.sockets.emit('ok', command); // added per #325 + // debug_log("OK FOUND") + if (status.machine.firmware.type === "grbl") { + // debug_log('got OK from ' + command) + command = sentBuffer.shift(); + } + if (command == "$CD") { + io.sockets.emit('fluidncConfig', fluidncConfig); + } + status.comms.blocked = false; + send1Q(); + } else if (data.indexOf('ALARM') === 0) { //} || data.indexOf('HALTED') === 0) { + debug_log("ALARM: " + data) + status.comms.connectionStatus = 5; + switch (status.machine.firmware.type) { + case 'grbl': + // sentBuffer.shift(); + var alarmCode = parseInt(data.split(':')[1]); + debug_log('ALARM: ' + alarmCode + ' - ' + grblStrings.alarms(alarmCode)); + status.comms.alarm = alarmCode + ' - ' + grblStrings.alarms(alarmCode) + if (alarmCode != 5) { + io.sockets.emit("toastErrorAlarm", 'ALARM: ' + alarmCode + ' - ' + grblStrings.alarms(alarmCode) + " [ " + command + " ]") + } + var output = { + 'command': '', + 'response': 'ALARM: ' + alarmCode + ' - ' + grblStrings.alarms(alarmCode) + " [ " + command + " ]", + 'type': 'error' + } + io.sockets.emit('data', output); + break; + } + status.comms.connectionStatus = 5; + } else if (data.indexOf('WARNING: After HALT you should HOME as position is currently unknown') != -1) { //} || data.indexOf('HALTED') === 0) { + status.comms.connectionStatus = 2; + } else if (data.indexOf('Emergency Stop Requested') != -1) { //} || data.indexOf('HALTED') === 0) { + debug_log("Emergency Stop Requested") + status.comms.connectionStatus = 5; + } else if (data.indexOf('wait') === 0) { // Got wait from Repetier -> ignore + // do nothing + } else if (data.indexOf('error') === 0) { // Error received -> stay blocked stops queue + switch (status.machine.firmware.type) { + case 'grbl': + // sentBuffer.shift(); + var errorCode = parseInt(data.split(':')[1]); + + var lastAlarm = ""; + if (errorCode == 9 && status.comms.connectionStatus == 5 && status.comms.alarm.length > 0) { + lastAlarm = "
This error may just be a symptom of an earlier event:
ALARM: " + status.comms.alarm + } + debug_log('error: ' + errorCode + ' - ' + grblStrings.errors(errorCode) + " [ " + command + " ]"); + var output = { + 'command': '', + 'response': 'error: ' + errorCode + ' - ' + grblStrings.errors(errorCode) + " [ " + command + " ]" + lastAlarm, + 'type': 'error' + } + io.sockets.emit('data', output); + io.sockets.emit("toastError", 'error: ' + errorCode + ' - ' + grblStrings.errors(errorCode) + " [ " + command + " ]" + lastAlarm) + break; + } + debug_log("error;") + sentBuffer.shift(); + status.comms.connectionStatus = 5; + } else if (data === ' ') { + // nothing + } else { + // do nothing with +data + } + + if (data.indexOf("[MSG:Reset to continue]") === 0) { + switch (status.machine.firmware.type) { + case 'grbl': + debug_log("[MSG:Reset to continue] -> Sending Reset") + addQRealtime(String.fromCharCode(0x18)); // ctrl-x + break; + } + } + + + if (command) { + command = command.replace(/(\r\n|\n|\r)/gm, ""); + // debug_log("CMD: " + command + " / DATA RECV: " + data.replace(/(\r\n|\n|\r)/gm, "")); + + if (command != "?" && command != "M105" && data.length > 0 && data.indexOf('<') == -1) { + var string = ""; + if (status.comms.sduploading) { + string += "SD: " + } + string += data //+ " [ " + command + " ]" + var output = { + 'command': command, + 'response': string, + 'type': 'info' + } + // debug_log(output.response) + io.sockets.emit('data', output); + } + } else { + if (data.indexOf("<") != 0) { + var output = { + 'command': "", + 'response': data, + 'type': 'info' + } + io.sockets.emit('data', output); + } + } + }); // end of parser.on(data) + + // Then try to connect + // set status + status.comms.connectionStatus = 1; + + // Log attempt 1 debug_log("PORT INFO: Connected to " + port.path + " at " + port.baudRate); var output = { 'command': 'connect', @@ -1214,12 +1592,10 @@ io.on("connection", function(socket) { 'type': 'info' } io.sockets.emit('data', output); - - status.comms.connectionStatus = 1; - + // do attempt 1 addQRealtime("\n"); // this causes smoothie and grblHAL to send the welcome string - + // log attempt 2 var output = { 'command': 'connect', 'response': "Attempting to detect Controller (1): (Autoreset)", @@ -1227,7 +1603,7 @@ io.on("connection", function(socket) { } io.sockets.emit('data', output); - + // do attempt 2 after 1 second setTimeout(function() { //wait for controller to be ready if (status.machine.firmware.type.length < 1) { debug_log("Didnt detect firmware after AutoReset. Lets see if we have Grbl instance with a board that doesnt have AutoReset"); @@ -1242,12 +1618,29 @@ io.on("connection", function(socket) { } }, config.grblWaitTime * 1000); + //do attempt 3 after 2 seconds Smoothie and soft-usb + setTimeout(function() { //wait for controller to be ready + if (status.machine.firmware.type.length < 1) { + debug_log("No firmware yet, probably not Grbl then. lets see if we have Smoothie?"); + var output = { + 'command': 'connect', + 'response': "Attempting to detect Controller (3): (others)", + 'type': 'info' + } + io.sockets.emit('data', output); + addQRealtime("version\n"); // Check if it's Smoothieware? + debug_log("Sent: version"); + } + }, config.grblWaitTime * 2000); + + + // Not smoothie, maybe DTR setTimeout(function() { //wait for controller to be ready if (status.machine.firmware.type.length < 1) { debug_log("Didnt detect firmware after AutoReset or Ctrl+X. Lets try toggling DTR"); var output = { 'command': 'connect', - 'response': "Attempting to detect Controller (3): (DTR Enable)", + 'response': "Attempting to detect Controller (4): (DTR Enable)", 'type': 'info' } io.sockets.emit('data', output); @@ -1256,21 +1649,46 @@ io.on("connection", function(socket) { port.set({ "dtr": true }, console.log("Set DTR")); + // then try Ctrl+X again setTimeout(function() { + addQRealtime(String.fromCharCode(0x18)); // ctrl-x (needed for rx/tx connection) debug_log("Sent: Ctrl+x after DTR toggle"); - }, 200); + + // port.set({ + // "dtr": false + // }, console.log("Set DTR")); + }, 100); } - port.set({ // toggle Off again else grbl on Uno gets stuck - "dtr": false - }, console.log("Set DTR")); - }, config.grblWaitTime * 2000); + // port.set({ // toggle Off again else grbl on Uno gets stuck + // "dtr": false + // }, console.log("Set DTR")); + }, config.grblWaitTime * 3000); setTimeout(function() { - if (status.machine.firmware.type.length > 1) { + // Close port if we don't detect supported firmware after 2s. + if (status.machine.firmware.type.length < 1) { + debug_log("No supported firmware detected. Closing port " + port.path); + if (status.interface.connected) { + var output = { + 'command': 'connect', + 'response': `ERROR!: Connection established to INTERFACE, but no response from Grbl on the upstream controller. See https://docs.openbuilds.com/interface for more details. Closing port ` + port.path, + 'type': 'error' + } + } else { + var output = { + 'command': 'connect', + 'response': `ERROR!: No Response from Controller - See https://docs.openbuilds.com/doku.php?id=docs:blackbox:faq-usb-connection-failed for troubleshooting information. Closing port ` + port.path, + 'type': 'error' + } + } + io.sockets.emit('data', output); + stopPort(); + } else { + if (status.machine.firmware.type === "grbl") { debug_log("GRBL detected"); var output = { @@ -1283,7 +1701,7 @@ io.on("connection", function(socket) { io.sockets.emit('grbl', status.machine.firmware) //v1.0.318 - commented out as a test - too many normal alarms clear prematurely //io.sockets.emit('errorsCleared', true); - }, 600) + }, 100) // Start interval for status queries clearInterval(statusLoop); statusLoop = setInterval(function() { @@ -1293,49 +1711,24 @@ io.on("connection", function(socket) { }, 200); status.machine.modals.homedRecently = false; } - } - - - }, config.grblWaitTime * 3000) - if (config.firmwareWaitTime > 0) { - setTimeout(function() { - // Close port if we don't detect supported firmware after 2s. - if (status.machine.firmware.type.length < 1) { - debug_log("No supported firmware detected. Closing port " + port.path); - if (status.interface.connected) { - var output = { - 'command': 'connect', - 'response': `ERROR!: Connection established to INTERFACE, but no response from Grbl on the upstream controller. See https://docs.openbuilds.com/interface for more details. Closing port ` + port.path, - 'type': 'error' - } - } else { - var output = { - 'command': 'connect', - 'response': `ERROR!: No Response from Controller - See https://docs.openbuilds.com/doku.php?id=docs:blackbox:faq-usb-connection-failed for troubleshooting information. Closing port ` + port.path, - 'type': 'error' - } + if (data.type == "usb") { + var output = { + 'command': 'connect', + 'response': "Firmware Detected: " + status.machine.firmware.platform + " version " + status.machine.firmware.version + " dated " + status.machine.firmware.date + " on " + port.path, + 'type': 'success' } - io.sockets.emit('data', output); - stopPort(); - } else { - if (data.type == "usb") { - var output = { - 'command': 'connect', - 'response': "Firmware Detected: " + status.machine.firmware.platform + " version " + status.machine.firmware.version + " dated " + status.machine.firmware.date + " on " + port.path, - 'type': 'success' - } - } else if (data.type = "telnet") { - var output = { - 'command': 'connect', - 'response': "Firmware Detected: " + status.machine.firmware.platform + " version " + status.machine.firmware.version + " dated " + status.machine.firmware.date + " on " + data.ip, - 'type': 'success' - } + } else if (data.type = "telnet") { + var output = { + 'command': 'connect', + 'response': "Firmware Detected: " + status.machine.firmware.platform + " version " + status.machine.firmware.version + " dated " + status.machine.firmware.date + " on " + data.ip, + 'type': 'success' } - io.sockets.emit('data', output); } - }, config.firmwareWaitTime * 1000); - } + io.sockets.emit('data', output); + } + }, config.grblWaitTime * 4000); + status.comms.connectionStatus = 2; @@ -1350,376 +1743,7 @@ io.on("connection", function(socket) { } } - parser.on("data", function(data) { - //console.log(data) - var command = sentBuffer[0]; - - if (command == "$CD" && data != "ok") { - fluidncConfig = fluidncConfig += data + "\n" - } - - if (data.indexOf("<") != 0) { - debug_log('data:', data) - } - - // Grbl $I parser - if (data.indexOf("[VER:") === 0) { - status.machine.name = data.split(':')[2].split(']')[0].toLowerCase() - io.sockets.emit("status", status); - io.sockets.emit("machinename", data.split(':')[2].split(']')[0].toLowerCase()); - status.machine.firmware.date = data.split(':')[1].split(".")[2]; - } - - if (data.indexOf("[OPT:") === 0) { - - var startOpt = data.search(/opt:/i) + 4; - var grblOpt; - if (startOpt > 4) { - var grblOptLen = data.substr(startOpt).search(/]/); - grblOpts = data.substr(startOpt, grblOptLen).split(/,/); - - status.machine.firmware.blockBufferSize = grblOpts[1]; - status.machine.firmware.rxBufferSize = grblOpts[2]; - - var features = [] - - var i = grblOpts[0].length; - while (i--) { - features.push(grblOpts[0].charAt(i)) - switch (grblOpts[0].charAt(i)) { - case 'Q': - debug_log('SPINDLE_IS_SERVO Enabled') - // - break; - case 'V': // Variable spindle enabled - debug_log('Variable spindle enabled') - // - break; - case 'N': // Line numbers enabled - debug_log('Line numbers enabled') - // - break; - case 'M': // Mist coolant enabled - debug_log('Mist coolant enabled') - // - break; - case 'C': // CoreXY enabled - debug_log('CoreXY enabled') - // - break; - case 'P': // Parking motion enabled - debug_log('Parking motion enabled') - // - break; - case 'Z': // Homing force origin enabled - debug_log('Homing force origin enabled') - // - break; - case 'H': // Homing single axis enabled - debug_log('Homing single axis enabled') - // - break; - case 'T': // Two limit switches on axis enabled - debug_log('Two limit switches on axis enabled') - // - break; - case 'A': // Allow feed rate overrides in probe cycles - debug_log('Allow feed rate overrides in probe cycles') - // - break; - case '$': // Restore EEPROM $ settings disabled - debug_log('Restore EEPROM $ settings disabled') - // - break; - case '#': // Restore EEPROM parameter data disabled - debug_log('Restore EEPROM parameter data disabled') - // - break; - case 'I': // Build info write user string disabled - debug_log('Build info write user string disabled') - // - break; - case 'E': // Force sync upon EEPROM write disabled - debug_log('Force sync upon EEPROM write disabled') - // - break; - case 'W': // Force sync upon work coordinate offset change disabled - debug_log('Force sync upon work coordinate offset change disabled') - // - break; - case 'L': // Homing init lock sets Grbl into an alarm state upon power up - debug_log('Homing init lock sets Grbl into an alarm state upon power up') - // - break; - } - } - status.machine.firmware.features = features; - io.sockets.emit("features", features); - } - } - - // [PRB:0.000,0.000,0.000:0] - //if (data.indexOf("[PRB:") === 0 && command != "$#" && command != undefined) { - if (data.indexOf("[PRB:") === 0) { - debug_log(data) - var prbLen = data.substr(5).search(/\]/); - var prbData = data.substr(5, prbLen).split(/,/); - var success = data.split(':')[2].split(']')[0]; - status.machine.probe.x = prbData[0]; - status.machine.probe.y = prbData[1]; - status.machine.probe.z = prbData[2].split(':')[0]; - status.machine.probe.state = success; - if (success > 0) { - var output = { - 'command': '[ PROBE ]', - 'response': "Probe Completed.", - 'type': 'success' - } - io.sockets.emit('data', output); - } else { - var output = { - 'command': '[ PROBE ]', - 'response': "Probe move ERROR - probe did not make contact within specified distance", - 'type': 'error' - } - io.sockets.emit('data', output); - } - io.sockets.emit('prbResult', status.machine.probe); - }; - - if (data.indexOf("[GC:") === 0) { - gotModals(data) - } - if (data.indexOf("[INTF:") === 0) { - var output = { - 'command': 'connect', - 'response': "Detected an OpenBuilds Interface on port " + port.path, - 'type': 'success' - } - io.sockets.emit('data', output); - status.interface.connected = true; - if (data.split(":")[1].indexOf("ver") == 0) { - var installedVersion = parseFloat(data.split(":")[1].split("]")[0].split("-")[1]) - status.interface.firmware.installedVersion = installedVersion - var output = { - 'command': 'connect', - 'response': "OpenBuilds Interface Firmware Version: v" + installedVersion, - 'type': 'info' - } - io.sockets.emit('data', output); - if (installedVersion < status.interface.firmware.availVersion) { - var output = { - 'command': 'connect', - 'response': "OpenBuilds Interface Firmware OUTDATED: v" + installedVersion + " can be upgraded to v" + status.interface.firmware.availVersion, - 'type': 'error' - } - io.sockets.emit('data', output); - io.sockets.emit('interfaceOutdated', status); - } - } - io.sockets.emit("status", status); - } - - // Machine Identification - if (data.indexOf("Grbl") === 0 || data.indexOf("[FIRMWARE:grblHAL]") === 0) { // Check if it's Grbl - debug_log(data) - status.comms.blocked = false; - if (data.indexOf("GrblHAL") === 0) { - status.machine.firmware.type = "grbl"; - status.machine.firmware.platform = "grblHAL" - status.machine.firmware.version = data.substr(8, 4); // get version - } else if (data.indexOf("[FIRMWARE:grblHAL]") === 0) { - status.machine.firmware.type = "grbl"; - status.machine.firmware.platform = "grblHAL" - // Parse version from seperate [VER:...] line not here for this response - } else if (data.indexOf("FluidNC") != -1) { // Grbl 3.6 [FluidNC v3.6.5 (wifi) '$' for help] - status.machine.firmware.type = "grbl"; - status.machine.firmware.platform = "FluidNC" - status.machine.firmware.version = data.substr(19, 5); // get version - } else { - status.machine.firmware.type = "grbl"; - status.machine.firmware.platform = "gnea" - status.machine.firmware.version = data.substr(5, 4); // get version - } - if (parseFloat(status.machine.firmware.version) < 1.1) { // If version is too old - if (status.machine.firmware.version.length < 3) { - debug_log('invalid version string, stay connected') - } else { - if (status.comms.connectionStatus > 0) { - debug_log('WARN: Closing Port ' + port.path + " / v" + parseFloat(status.machine.firmware.version)); - // stopPort(); - } else { - debug_log('ERROR: Machine connection not open!'); - } - var output = { - 'command': command, - 'response': "Detected an unsupported version: Grbl " + status.machine.firmware.version + ". This is sadly outdated. Please upgrade to Grbl 1.1 or newer to use this software. Go to http://github.com/gnea/grbl", - 'type': 'error' - } - io.sockets.emit('data', output); - } - } - status.machine.firmware.date = ""; - // debug_log("GRBL detected"); - // setTimeout(function() { - // io.sockets.emit('grbl', status.machine.firmware) - // //v1.0.318 - commented out as a test - too many normal alarms clear prematurely - // //io.sockets.emit('errorsCleared', true); - // }, 600) - // // Start interval for status queries - // clearInterval(statusLoop); - // statusLoop = setInterval(function() { - // if (status.comms.connectionStatus > 0) { - // addQRealtime("?"); - // } - // }, 200); - status.machine.modals.homedRecently = false; - } else if (data.indexOf("LPC176") >= 0) { // LPC1768 or LPC1769 should be Smoothieware - status.comms.blocked = false; - debug_log("Smoothieware detected"); - status.machine.firmware.type = "smoothie"; - status.machine.firmware.version = data.substr(data.search(/version:/i) + 9).split(/,/); - status.machine.firmware.date = new Date(data.substr(data.search(/Build date:/i) + 12).split(/,/)).toDateString(); - // Start interval for status queries - // statusLoop = setInterval(function() { - // if (status.comms.connectionStatus > 0) { - // addQRealtime("?"); - // } - // }, 200); - var output = { - 'command': "FIRMWARE ERROR", - 'response': "Detected an unsupported version: Smoothieware " + status.machine.firmware.version + ". This software no longer support Smoothieware. \nLuckilly there is an alternative firmware you can install on your controller to make it work with this software. Check out Grbl-LPC at https://github.com/cprezzi/grbl-LPC - Grbl-LPC is a Grbl port for controllers using the NXP LPC176x chips, for example Smoothieboards", - 'type': 'error' - } - io.sockets.emit('data', output); - stopPort(); - } // end of machine identification - - // Machine Feedback: Position - if (data.indexOf("<") === 0) { - // debug_log(' Got statusReport (Grbl & Smoothieware)') - // statusfeedback func - parseFeedback(data) - if (command == "?") { - var output = { - 'command': command, - 'response': data, - 'type': 'info' - } - // debug_log(output.response) - io.sockets.emit('data', output); - } - - // debug_log(data) - } else if (data.indexOf("ok") === 0) { // Got an OK so we are clear to send - io.sockets.emit('ok', command); // added per #325 - // debug_log("OK FOUND") - if (status.machine.firmware.type === "grbl") { - // debug_log('got OK from ' + command) - command = sentBuffer.shift(); - } - if (command == "$CD") { - io.sockets.emit('fluidncConfig', fluidncConfig); - } - status.comms.blocked = false; - send1Q(); - } else if (data.indexOf('ALARM') === 0) { //} || data.indexOf('HALTED') === 0) { - debug_log("ALARM: " + data) - status.comms.connectionStatus = 5; - switch (status.machine.firmware.type) { - case 'grbl': - // sentBuffer.shift(); - var alarmCode = parseInt(data.split(':')[1]); - debug_log('ALARM: ' + alarmCode + ' - ' + grblStrings.alarms(alarmCode)); - status.comms.alarm = alarmCode + ' - ' + grblStrings.alarms(alarmCode) - if (alarmCode != 5) { - io.sockets.emit("toastErrorAlarm", 'ALARM: ' + alarmCode + ' - ' + grblStrings.alarms(alarmCode) + " [ " + command + " ]") - } - var output = { - 'command': '', - 'response': 'ALARM: ' + alarmCode + ' - ' + grblStrings.alarms(alarmCode) + " [ " + command + " ]", - 'type': 'error' - } - io.sockets.emit('data', output); - break; - } - status.comms.connectionStatus = 5; - } else if (data.indexOf('WARNING: After HALT you should HOME as position is currently unknown') != -1) { //} || data.indexOf('HALTED') === 0) { - status.comms.connectionStatus = 2; - } else if (data.indexOf('Emergency Stop Requested') != -1) { //} || data.indexOf('HALTED') === 0) { - debug_log("Emergency Stop Requested") - status.comms.connectionStatus = 5; - } else if (data.indexOf('wait') === 0) { // Got wait from Repetier -> ignore - // do nothing - } else if (data.indexOf('error') === 0) { // Error received -> stay blocked stops queue - switch (status.machine.firmware.type) { - case 'grbl': - // sentBuffer.shift(); - var errorCode = parseInt(data.split(':')[1]); - - var lastAlarm = ""; - if (errorCode == 9 && status.comms.connectionStatus == 5 && status.comms.alarm.length > 0) { - lastAlarm = "
This error may just be a symptom of an earlier event:
ALARM: " + status.comms.alarm - } - debug_log('error: ' + errorCode + ' - ' + grblStrings.errors(errorCode) + " [ " + command + " ]"); - var output = { - 'command': '', - 'response': 'error: ' + errorCode + ' - ' + grblStrings.errors(errorCode) + " [ " + command + " ]" + lastAlarm, - 'type': 'error' - } - io.sockets.emit('data', output); - io.sockets.emit("toastError", 'error: ' + errorCode + ' - ' + grblStrings.errors(errorCode) + " [ " + command + " ]" + lastAlarm) - break; - } - debug_log("error;") - sentBuffer.shift(); - status.comms.connectionStatus = 5; - } else if (data === ' ') { - // nothing - } else { - // do nothing with +data - } - - if (data.indexOf("[MSG:Reset to continue]") === 0) { - switch (status.machine.firmware.type) { - case 'grbl': - debug_log("[MSG:Reset to continue] -> Sending Reset") - addQRealtime(String.fromCharCode(0x18)); // ctrl-x - break; - } - } - - - if (command) { - command = command.replace(/(\r\n|\n|\r)/gm, ""); - // debug_log("CMD: " + command + " / DATA RECV: " + data.replace(/(\r\n|\n|\r)/gm, "")); - - if (command != "?" && command != "M105" && data.length > 0 && data.indexOf('<') == -1) { - var string = ""; - if (status.comms.sduploading) { - string += "SD: " - } - string += data //+ " [ " + command + " ]" - var output = { - 'command': command, - 'response': string, - 'type': 'info' - } - // debug_log(output.response) - io.sockets.emit('data', output); - } - } else { - if (data.indexOf("<") != 0) { - var output = { - 'command': "", - 'response': data, - 'type': 'info' - } - io.sockets.emit('data', output); - } - } - }); // end of parser.on(data) } }); diff --git a/package.json b/package.json index 1aa7e0a5..5dee94e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "OpenBuildsCONTROL", - "version": "1.0.378", + "version": "1.0.379", "license": "AGPL-3.0", "description": "OpenBuildsCONTROL CNC Machine Host Software", "author": "github.com/openbuilds ",