diff --git a/README.md b/README.md index 89b5bb5..d777c3a 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ The full cncjs UI can still be used, perhaps on a different computer or in a dif It works well with TinyG/g2core and GRBL. It has been tested a little with Marlin but not extensively. It has not been tested with Smoothieware - but Smoothie and GRBL are quite similar from a protocol standpoint so it is likely to work. -Rotary axes A/B/C are not supported from the GUI, but you can issue GCode commands for those axes manually via the MDI boxes. +Rotary axis A is supported from the GUI, but not B and C. You can issue GCode commands for those axes manually via the MDI boxes. The A axis GUI support includes a DRO, Set and GoTo functions, but not jog buttons. There is a Home A menu entry in the dropdown menu. + ### Setup @@ -64,19 +65,29 @@ You can still use the full cncjs UI by browsing 'http://*host*:8000'. You can us ### Usage -![cncjs-tablet 2](https://user-images.githubusercontent.com/4861133/33970662-4a8244b2-e018-11e7-92ab-5a379e3de461.PNG) - -* **Start/Pause/Resume/Stop** are highlighted and colored according to the program state - * **Start** is green when it is possible to start running a program - * **Pause** is red when the program is running - * **Stop** is red when the program is running or paused - * **Resume** is green when the program is paused -* The **Inch** or **mm** button shows the currently-active units, and toggles them if clicked. +![cncjs-shopfloor-tablet](https://user-images.githubusercontent.com/4861133/100148429-d9b16b80-2e40-11eb-8bc0-7c80a1b27a9f.png) + +From left to right, top to bottom, the screen elements are: +* The legend in the upper left hand corner shows the current controller state and sometimes error messages. +* There are two program control buttons that change according to the program state + * The left button is generalized "Go", while the right is generalized "Stop" + * The idea is that the left one is always the "accelerator" and the right the "brake" + * If no program is loaded, neither button is active (both are greyed out) + * If a program is loaded but not running, the left button is green/Start + * When a program is running, the right button is red, labeled Pause + * Then a program is paused, the left one is green/Resume and the right is red/Stop + * When a program is running, hitting the "brake" (right button) pauses exection. From there you can decide whether to Resume or Stop (go back to idle state). +* The number to the right of the control buttons is the number of program lines that have been executed. +* The number to the right of that is the program run time. +* The button in the upper right corner is a drop-down menu with miscellaneous functions that are used infrequently. +* "G54" shows the current work coordinate system - G54, G55, .. G59. To change the coordinate system manually you can enter e.g. G55 in an MDI box. +* The gray "DRO" boxes labeled X, Y, Z, A show the current work coordinate for that axis. Touching a DRO box brings up an RPN calculator in which you can enter or calculate a new value. Having entered the value, you can exit from the calculator with Cancel (does nothing), GoTo (rapid move to the new location) or Set (change the work coordinate to the new value). +* You can use the calculator to quickly perform custom jogs, as follows: When the calculator starts, the current location is pre-entered. If you type a number followed by + or -, the new number will be added to or subtracted from the current location. You can then hit GoTo. +* The **Inch** or **mm** button shows the currently-active units, and toggles them if clicked. Switching units also changes the jog increment selections. * **X=** **Y=** **Z=** set the axis work coordinate to the value in the number box above -* **GoX** **GoY** **GoZ** rapid to the axis work coordinate to the value in the number box above -* **X=0** **Y=0** **Z=0** set the axis work coordinate to 0 -* **GoX0** **GoY0** **GoZ0** rapid to work 0 for that axis -* **0.001** .. **5** set the jog increment. +* **X=0** **Y=0** **Z=0** **A=0** set the axis work coordinate to 0 +* **->X0** **->Y0** **->Z0** **->A0" rapid to work 0 for that axis +* **0.001** .. **5** set the jog increment. The selection of increments changes according to the units (Inch or mm). * The selector box between **Z+** and **Z-** shows the current jog increment, and, when clicked, permits the choice of some additional jog increments. * **X-** **X+** **Y-** **Y+** **Z-** **Z+** jog by the current increment. You can jog continuously by selecting a large increment, starting the jog, then hitting **Stop** when it has gone far enough. * **MDI** sends the GCode command entered in the box to its left. To resend that command, click **MDI** again. There are MDI blocks so you can have two different GCode commands "queued up" for easy execution. @@ -84,3 +95,6 @@ You can still use the full cncjs UI by browsing 'http://*host*:8000'. You can us * **Rfrsh** refreshes the file selector list. That is useful if additional files are added to the watch directory. Another way to refresh the file list is to reload the page. * **Load** reloads the GCode program from the currently selected file. That is useful if you edit the file from another computer and want to pick up the new version. To reload it directly from the file selector, you would have to first select a different file and then re-select the edited one (because of the way selector ".change" events work). * If the file selector is blank and there is GCode text in the GCode display text area, the GCode is probably a macro loaded by a different cncjs session. +* The text box to the right of MDI shows the currently loaded GCode program. You can scroll it by swiping in the box. When a program is running, the currently executing line is highlighted. The highlighted line is sometimes wrong due to the fact that the CNCjs server filters out blank lines, so the line that the controller reports is sometimes a little off compared to the raw text in the file. +* The graphic window in the lower right shows the toolpath looking down from the top. Feedrate (cutting) moves are shown in blue, with rapid moves in green.There is a crosshair reticle at the origin, and the current tool position is shown as a pink circle. The numbers are the motion limits in X and Y. +* The scrollable Serial Messages box shows selected serial messages from the controller, filtering out very common protocol and flow control messages that are generally uninteresting. The messages that are shown include error and alarm messages, and responses to inquiries that you enter in MDI boxes. diff --git a/package.json b/package.json index 1f6de20..3f4f502 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cncjs-shopfloor-tablet", - "version": "1.0.4", + "version": "2.0.0", "description": "A simplified UI for cncjs optimized for tablet computers in a production (shop floor) environment.", "homepage": "https://github.com/cncjs/cncjs-shopfloor-tablet", "author": "Mitch Bradley", diff --git a/src/app.js b/src/app.js index 59872f2..2c96e98 100644 --- a/src/app.js +++ b/src/app.js @@ -100,7 +100,8 @@ controller.on('serialport:open', function(options) { // settings report, so interpreting the numbers from the first status // report is ambiguous. Subsequent status reports are interpreted correctly. // We work around that by deferring status reports until the settings report. - controller.writeln('$$'); + // I commented this out because of https://github.com/cncjs/cncjs-shopfloor-tablet/issues/20 + // controller.writeln('$$'); } root.location = '#/workspace'; @@ -148,24 +149,44 @@ cnc.goAxis = function(axis, coordinate) { } cnc.moveAxis = function(axis, field) { - coordinate = document.getElementById(field).value; - cnc.goAxis(axis, coordinate) + cnc.goAxis(axis, document.getElementById(field).value) } +cnc.currentAxisPNum = function() { + return 'P' + String(Number(modal.wcs.substring(1)) - 53); +} + +cnc.setAxisByValue = function(axis, coordinate) { + cnc.click(); + controller.command('gcode', 'G10 L20 ' + cnc.currentAxisPNum() + ' ' + axis + coordinate); +} cnc.setAxis = function(axis, field) { + cnc.setAxisByValue(axis, document.getElementById(field).value); +} +cnc.MDIcmd = function(value) { cnc.click(); - coordinate = document.getElementById(field).value; - controller.command('gcode', 'G10 L20 P1 ' + axis + coordinate); + controller.command('gcode', value); } + cnc.MDI = function(field) { - cnc.click(); - mdicmd = document.getElementById(field).value; - controller.command('gcode', mdicmd); + cnc.MDIcmd(document.getElementById(field).value); } cnc.zeroAxis = function(axis) { - cnc.click(); - controller.command('gcode', 'G10 L20 P1 ' + axis + '0'); + cnc.setAxisByValue(axis, 0); +} + +cnc.toggleFullscreen = function() { + var messages = document.getElementById('messages'); + + if (document.fullscreenElement) { + document.exitFullscreen(); + messages.rows = 2; + } else { + document.documentElement.requestFullscreen(); + messages.rows = 4; + } + messages.scrollTop = messages.scrollHeight; } cnc.toggleUnits = function() { @@ -178,6 +199,12 @@ cnc.toggleUnits = function() { // No need to fix the button label, as that will be done by the status watcher } +cnc.btnSetDistance = function() { + cnc.click(); + var distance = event.target.innerText; + $('[data-route="workspace"] select[data-name="select-distance"]').val(distance); +} + cnc.setDistance = function(distance) { cnc.click(); $('[data-route="workspace"] select[data-name="select-distance"]').val(distance); @@ -269,13 +296,20 @@ cnc.sendMove = function(cmd) { fn && fn(); }; -controller.on('serialport:read', function(data) { + echoData = function(data) { + var messages = $('[data-route="workspace"] [id="messages"]'); + messages.text(messages.text() + "\n" + data); + messages[0].scrollTop = messages[0].scrollHeight; + } + + controller.on('serialport:read', function(data) { if (data.r) { cnc.line++; } switch (cnc.controllerType) { case 'Marlin': if (data.startsWith('echo:')) { + echoData(data); stateName = data.substring(5); if (machineWorkflow == MACHINE_IDLE) { machineWorkflow = MACHINE_STALL; // Disables Start button @@ -284,17 +318,27 @@ controller.on('serialport:read', function(data) { stateName = 'Idle'; machineWorkflow = MACHINE_IDLE; } else if (data.startsWith('Error:')) { + echoData(data); stateName = data; } cnc.updateView(); break; case 'Smoothie': case 'Grbl': + if (!data.startsWith('ok')) { + echoData(data); + } if (data.startsWith('error:')) { stateName = data; } cnc.updateView(); break; + case 'TinyG': + if (!data.startsWith('{"qr"')) { + echoData(data); + } + + break; } }); @@ -303,7 +347,7 @@ controller.on('serialport:read', function(data) { // We track the $13 value by watching for the Grbl:settings event and by // watching for manual changes via serialport:write. Upon initial connection, // we issue a settings request in serialport:open. -var grblReportingUnits; // initially undefined +var grblReportingUnits = 0; // initially undefined controller.on('serialport:write', function(data) { // var style = 'font-weight: bold; line-height: 20px; padding: 2px 4px; border: 1px solid; color: #00529B; background: #BDE5F8'; @@ -552,6 +596,9 @@ controller.on('TinyG:state', function(data) { return; } + if (sr.modal) { + Object.assign(modal, sr.modal); + } mpos = sr.mpos; wpos = sr.wpos; var INIT = 0, READY = 1, ALARM = 2, STOP = 3, END = 4, RUN = 5, @@ -569,14 +616,8 @@ controller.on('TinyG:state', function(data) { } else { machineWorkflow = MACHINE_STOP; } - if (sr.modal) { - Object.assign(modal, sr.modal); - } } else if ([READY, STOP].indexOf(machineState) >= 0) { machineWorkflow = (machineState == STOP && workflowState == 'paused') ? MACHINE_HOLD : MACHINE_IDLE; - if (sr.modal) { - Object.assign(modal, sr.modal); - } } else if ([RUN, CYCLE, HOMING, PROBE, JOG].indexOf(machineState) >= 0) { machineWorkflow = MACHINE_RUN; running = true; @@ -681,6 +722,72 @@ cnc.doRightButton = function() { } + cnc.setJogSelector = function(units) { + var selector = $('[data-route="workspace"] select[data-name="select-distance"]'); + selector.empty(); + if (units == "Inch") { + $('[data-route="workspace"] [id="jog00"]').text('0.001'); + $('[data-route="workspace"] [id="jog01"]').text('0.01'); + $('[data-route="workspace"] [id="jog02"]').text('0.1'); + $('[data-route="workspace"] [id="jog03"]').text('1'); + $('[data-route="workspace"] [id="jog10"]').text('0.003'); + $('[data-route="workspace"] [id="jog11"]').text('0.03'); + $('[data-route="workspace"] [id="jog12"]').text('0.3'); + $('[data-route="workspace"] [id="jog13"]').text('3'); + $('[data-route="workspace"] [id="jog20"]').text('0.005'); + $('[data-route="workspace"] [id="jog21"]').text('0.05'); + $('[data-route="workspace"] [id="jog22"]').text('0.5'); + $('[data-route="workspace"] [id="jog23"]').text('5'); + selector.append($("