Ajout FishPeper
This commit is contained in:
56
cncjs/test/ensure-type.js
Normal file
56
cncjs/test/ensure-type.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { test } from 'tap';
|
||||
import { ensureBoolean, ensureNumber, ensureString } from '../src/server/lib/ensure-type';
|
||||
|
||||
test('ensureBoolean', (t) => {
|
||||
t.equal(ensureBoolean({}), true);
|
||||
t.equal(ensureBoolean(true), true);
|
||||
t.equal(ensureBoolean(false), false);
|
||||
t.equal(ensureBoolean(0), false);
|
||||
t.equal(ensureBoolean(1), true);
|
||||
t.equal(ensureBoolean(Infinity), true);
|
||||
t.equal(ensureBoolean(-Infinity), true);
|
||||
t.equal(ensureBoolean(NaN), false);
|
||||
t.equal(ensureBoolean(undefined), false);
|
||||
t.equal(ensureBoolean(null), false);
|
||||
t.equal(ensureBoolean(''), false);
|
||||
t.equal(ensureBoolean(' '), true);
|
||||
t.equal(ensureBoolean('foo'), true);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('ensureNumber', (t) => {
|
||||
t.ok(Number.isNaN(ensureNumber({})));
|
||||
t.equal(ensureNumber(true), 1);
|
||||
t.equal(ensureNumber(false), 0);
|
||||
t.equal(ensureNumber(0), 0);
|
||||
t.equal(ensureNumber(1), 1);
|
||||
t.equal(ensureNumber(Infinity), Infinity);
|
||||
t.equal(ensureNumber(-Infinity), -Infinity);
|
||||
t.ok(Number.isNaN(ensureNumber(NaN)));
|
||||
t.equal(ensureNumber(undefined), 0);
|
||||
t.equal(ensureNumber(null), 0);
|
||||
t.equal(ensureNumber(''), 0);
|
||||
t.equal(ensureNumber(' '), 0);
|
||||
t.ok(Number.isNaN(ensureNumber('foo')));
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('ensureString', (t) => {
|
||||
t.equal(ensureString({}), ({}).toString());
|
||||
t.equal(ensureString(true), 'true');
|
||||
t.equal(ensureString(false), 'false');
|
||||
t.equal(ensureString(0), '0');
|
||||
t.equal(ensureString(1), '1');
|
||||
t.equal(ensureString(Infinity), 'Infinity');
|
||||
t.equal(ensureString(-Infinity), '-Infinity');
|
||||
t.equal(ensureString(NaN), 'NaN');
|
||||
t.equal(ensureString(undefined), '');
|
||||
t.equal(ensureString(null), '');
|
||||
t.equal(ensureString(''), '');
|
||||
t.equal(ensureString(' '), ' ');
|
||||
t.equal(ensureString('foo'), 'foo');
|
||||
|
||||
t.end();
|
||||
});
|
||||
135
cncjs/test/evaluate-assignment-expression.js
Normal file
135
cncjs/test/evaluate-assignment-expression.js
Normal file
@@ -0,0 +1,135 @@
|
||||
import { test } from 'tap';
|
||||
import evaluateAssignmentExpression from '../src/server/lib/evaluate-assignment-expression';
|
||||
|
||||
test('exceptions', (t) => {
|
||||
// Unexpected identifier
|
||||
evaluateAssignmentExpression('Not a valid expression');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('expressions', (t) => {
|
||||
{ // Evaluates expressions with variables
|
||||
const vars = {
|
||||
wposx: 10,
|
||||
wposy: 20,
|
||||
wposz: 30,
|
||||
};
|
||||
|
||||
// Evaluate assignment expression
|
||||
evaluateAssignmentExpression('value = 0.1', vars);
|
||||
t.same(vars, {
|
||||
wposx: 10,
|
||||
wposy: 20,
|
||||
wposz: 30,
|
||||
value: 0.1,
|
||||
});
|
||||
|
||||
// Evaluate sequence expression
|
||||
evaluateAssignmentExpression(' _x=(wposx+5), _y = wposy + 5, _z = (wposz+1*5) ', vars);
|
||||
t.same(vars, {
|
||||
wposx: 10,
|
||||
wposy: 20,
|
||||
wposz: 30,
|
||||
value: 0.1,
|
||||
_x: 15,
|
||||
_y: 25,
|
||||
_z: 35,
|
||||
});
|
||||
}
|
||||
|
||||
{ // Evaluates expressions containing template literals
|
||||
const bar = '0';
|
||||
const baz = 1;
|
||||
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('bar = "0", baz = 1, foo[bar][baz] = `${bar}${baz}`', { bar, baz }); // eslint-disable-line no-template-curly-in-string
|
||||
t.equal(vars.bar, bar);
|
||||
t.equal(vars.baz, baz);
|
||||
t.equal(vars.foo[bar][baz], '01');
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('bar = "0", baz = 1, foo[1][`baz`] = baz', { bar, baz });
|
||||
t.equal(vars.foo[1].baz, baz);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('bar = "0", baz = 1, foo[bar][baz] = `${bar}${baz}`', { bar, baz }); // eslint-disable-line no-template-curly-in-string
|
||||
t.equal(vars.foo[bar][baz], `${bar}${baz}`);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('bar = "0", baz = 1, foo.bar.baz = `${bar}${baz}`', { bar, baz }); // eslint-disable-line no-template-curly-in-string
|
||||
t.equal(vars.foo.bar.baz, `${bar}${baz}`);
|
||||
t.end();
|
||||
});
|
||||
}
|
||||
|
||||
// Set object values with a path string
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('x.y.z.a.b.c = 1');
|
||||
t.equal(vars.x.y.z.a.b.c, 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Boolean
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('ok = Boolean(1), notOk = Boolean(0)', { Boolean });
|
||||
t.equal(vars.ok, true);
|
||||
t.equal(vars.notOk, false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Number
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('dx = 4000, dy = 3000, dz = 1000, object.volume = Number(dx * dy * dz) || 0', { Number });
|
||||
t.equal(vars.dx, 4000);
|
||||
t.equal(vars.dy, 3000);
|
||||
t.equal(vars.dz, 1000);
|
||||
t.equal(vars.object.volume, 4000 * 3000 * 1000);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// String
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('value = String(100)', { String });
|
||||
t.equal(vars.value, '100');
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Date
|
||||
t.test(t => {
|
||||
const now = Date.now();
|
||||
const vars = evaluateAssignmentExpression('now = Date.now()', { Date });
|
||||
t.ok(vars.now >= now);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// JSON
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('global.state.pos = JSON.stringify({ x: 0, y: 0, z: 0 })', { JSON });
|
||||
t.equal(vars.global.state.pos, '{"x":0,"y":0,"z":0}');
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Math
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('global.value = Math.floor(4.003)', { Math });
|
||||
t.equal(vars.global.value, 4);
|
||||
t.end();
|
||||
});
|
||||
|
||||
// parseInt
|
||||
t.test(t => {
|
||||
const vars = evaluateAssignmentExpression('binaryValue = parseInt("10000", 2), decimalValue = parseInt("325mm", 10)', { parseInt });
|
||||
t.equal(vars.binaryValue, 16);
|
||||
t.equal(vars.decimalValue, 325);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
124
cncjs/test/evaluate-expression.js
Normal file
124
cncjs/test/evaluate-expression.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import { test } from 'tap';
|
||||
import evaluateExpression from '../src/server/lib/evaluate-expression';
|
||||
|
||||
test('resolved', (t) => {
|
||||
const src = '[1,2,3+4*10+(n||6),foo(3+5),obj[""+"x"].y]';
|
||||
const res = evaluateExpression(src, {
|
||||
n: false,
|
||||
foo: function (x) {
|
||||
return x * 100;
|
||||
},
|
||||
obj: {
|
||||
x: {
|
||||
y: 555
|
||||
}
|
||||
}
|
||||
});
|
||||
t.deepEqual(res, [1, 2, 49, 800, 555]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('unresolved', (t) => {
|
||||
const src = '[1,2,3+4*10*z+n,foo(3+5),obj[""+"x"].y]';
|
||||
const res = evaluateExpression(src, {
|
||||
n: 6,
|
||||
foo: function (x) {
|
||||
return x * 100;
|
||||
},
|
||||
obj: {
|
||||
x: {
|
||||
y: 555
|
||||
}
|
||||
}
|
||||
});
|
||||
t.equal(res, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('boolean', (t) => {
|
||||
const src = '[ 1===2+3-16/4, [2]==2, [2]!==2, [2]!==[2] ]';
|
||||
t.deepEqual(evaluateExpression(src), [true, true, true, true]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('array methods', (t) => {
|
||||
const src = '[1, 2, 3].map(function(n) { return n * 2 })';
|
||||
t.deepEqual(evaluateExpression(src), [2, 4, 6]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('array methods with vars', (t) => {
|
||||
const src = '[1, 2, 3].map(function(n) { return n * x })';
|
||||
t.deepEqual(evaluateExpression(src, { x: 2 }), [2, 4, 6]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('evaluate this', (t) => {
|
||||
const src = 'this.x + this.y.z';
|
||||
const res = evaluateExpression(src, {
|
||||
'this': {
|
||||
x: 1,
|
||||
y: {
|
||||
z: 100
|
||||
}
|
||||
}
|
||||
});
|
||||
t.equal(res, 101);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('unresolved function expression', (t) => {
|
||||
const src = '(function(){console.log("Not Good")})';
|
||||
const res = evaluateExpression(src);
|
||||
t.equal(res, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('immediate-invoked function expression with a return value', (t) => {
|
||||
const src = '(function(){ return !!x; }(x))';
|
||||
const res = evaluateExpression(src, { x: 1 });
|
||||
t.equal(res, true);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('function property', (t) => {
|
||||
const src = '[1,2,3+4*10+n,beep.boop(3+5),obj[""+"x"].y]';
|
||||
const res = evaluateExpression(src, {
|
||||
n: 6,
|
||||
beep: {
|
||||
boop: function (x) {
|
||||
return x * 100;
|
||||
}
|
||||
},
|
||||
obj: {
|
||||
x: {
|
||||
y: 555
|
||||
}
|
||||
}
|
||||
});
|
||||
t.deepEqual(res, [1, 2, 49, 800, 555]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('untagged template strings', (t) => {
|
||||
const src = '`${1},${2 + n},${"4,5"}`'; // eslint-disable-line no-template-curly-in-string
|
||||
const res = evaluateExpression(src, {
|
||||
n: 6
|
||||
});
|
||||
t.deepEqual(res, '1,8,4,5');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('tagged template strings', (t) => {
|
||||
const src = 'taggedTemplate`${1},${2 + n},${"4,5"}`'; // eslint-disable-line no-template-curly-in-string
|
||||
const res = evaluateExpression(src, {
|
||||
taggedTemplate: function (strings, ...values) {
|
||||
t.deepEqual(strings, ['', ',', ',', '']);
|
||||
t.deepEqual(values, [1, 8, '4,5']);
|
||||
return 'foo';
|
||||
},
|
||||
n: 6
|
||||
});
|
||||
t.deepEqual(res, 'foo');
|
||||
t.end();
|
||||
});
|
||||
2428
cncjs/test/fixtures/jsdc.gcode
vendored
Normal file
2428
cncjs/test/fixtures/jsdc.gcode
vendored
Normal file
File diff suppressed because it is too large
Load Diff
481
cncjs/test/grbl.js
Normal file
481
cncjs/test/grbl.js
Normal file
@@ -0,0 +1,481 @@
|
||||
import { test } from 'tap';
|
||||
import trim from 'lodash/trim';
|
||||
import GrblRunner from '../src/server/controllers/Grbl/GrblRunner';
|
||||
|
||||
// $10 - Status report mask:binary
|
||||
// Report Type | Value
|
||||
// Machine Position | 1
|
||||
// Work Position | 2
|
||||
// Planner Buffer | 4
|
||||
// RX Buffer | 8
|
||||
// Limit Pins | 16
|
||||
test('GrblLineParserResultStatus: all zeroes in the mask ($10=0)', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
subState: 0
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('GrblLineParserResultStatus: default ($10=3)', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
subState: 0,
|
||||
mpos: {
|
||||
x: '5.529',
|
||||
y: '0.560',
|
||||
z: '7.000'
|
||||
},
|
||||
wpos: {
|
||||
x: '1.529',
|
||||
y: '-5.440',
|
||||
z: '-0.000'
|
||||
}
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('GrblLineParserResultStatus: 6-axis', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle,MPos:5.529,0.560,7.000,0.100,0.250,0.500,WPos:1.529,-5.440,-0.000,0.100,0.250,0.500>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
subState: 0,
|
||||
mpos: {
|
||||
x: '5.529',
|
||||
y: '0.560',
|
||||
z: '7.000',
|
||||
a: '0.100',
|
||||
b: '0.250',
|
||||
c: '0.500'
|
||||
},
|
||||
wpos: {
|
||||
x: '1.529',
|
||||
y: '-5.440',
|
||||
z: '-0.000',
|
||||
a: '0.100',
|
||||
b: '0.250',
|
||||
c: '0.500'
|
||||
}
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle,MPos:5.529,0.560,7.000,0.100,0.250,0.500,WPos:1.529,-5.440,-0.000,0.100,0.250,0.500>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('GrblLineParserResultStatus: set all bits to 1 ($10=31)', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000,Buf:0,RX:0,Lim:000>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
subState: 0,
|
||||
mpos: {
|
||||
x: '5.529',
|
||||
y: '0.560',
|
||||
z: '7.000'
|
||||
},
|
||||
wpos: {
|
||||
x: '1.529',
|
||||
y: '-5.440',
|
||||
z: '-0.000'
|
||||
},
|
||||
buf: {
|
||||
planner: 0,
|
||||
rx: 0
|
||||
},
|
||||
pinState: ''
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle,MPos:5.529,0.560,7.000,WPos:1.529,-5.440,-0.000,Buf:0,RX:0,Lim:000>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('GrblLineParserResultOk', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('ok', ({ raw }) => {
|
||||
t.equal(raw, 'ok');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('GrblLineParserResultError', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('error', ({ raw, message }) => {
|
||||
t.equal(raw, 'error: Expected command letter');
|
||||
t.equal(message, 'Expected command letter');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'error: Expected command letter';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('GrblLineParserResultAlarm', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('alarm', ({ raw, message }) => {
|
||||
t.equal(raw, 'ALARM: Probe fail');
|
||||
t.equal(message, 'Probe fail');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ALARM: Probe fail';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('GrblLineParserResultParserState', (t) => {
|
||||
t.test('#1', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('parserstate', ({ raw, ...parserstate }) => {
|
||||
t.equal(raw, '[G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 F2540. S0.]');
|
||||
t.same(parserstate, {
|
||||
modal: {
|
||||
motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
|
||||
wcs: 'G54', // G54, G55, G56, G57, G58, G59
|
||||
plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
|
||||
units: 'G21', // G20: Inches, G21: Millimeters
|
||||
distance: 'G90', // G90: Absolute, G91: Relative
|
||||
feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
|
||||
program: 'M0',
|
||||
spindle: 'M5',
|
||||
coolant: 'M9'
|
||||
},
|
||||
tool: '0',
|
||||
feedrate: '2540.',
|
||||
spindle: '0.'
|
||||
});
|
||||
t.equal(runner.getTool(), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '[G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 F2540. S0.]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('#2', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('parserstate', ({ raw, ...parserstate }) => {
|
||||
t.equal(raw, '[G0 G54 G17 G21 G90 G94 M0 M5 M7 M8 T2 F2540. S0.]');
|
||||
t.same(parserstate, {
|
||||
modal: {
|
||||
motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
|
||||
wcs: 'G54', // G54, G55, G56, G57, G58, G59
|
||||
plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
|
||||
units: 'G21', // G20: Inches, G21: Millimeters
|
||||
distance: 'G90', // G90: Absolute, G91: Relative
|
||||
feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
|
||||
program: 'M0',
|
||||
spindle: 'M5',
|
||||
coolant: ['M7', 'M8']
|
||||
},
|
||||
tool: '2',
|
||||
feedrate: '2540.',
|
||||
spindle: '0.'
|
||||
});
|
||||
t.equal(runner.getTool(), 2);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '[G0 G54 G17 G21 G90 G94 M0 M5 M7 M8 T2 F2540. S0.]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('GrblLineParserResultParameters:G54,G55,G56,G57,G58,G59,G28,G30,G92', (t) => {
|
||||
const lines = [
|
||||
'[G54:0.000,0.000,0.000]',
|
||||
'[G55:0.000,0.000,0.000]',
|
||||
'[G56:0.000,0.000,0.000]',
|
||||
'[G57:0.000,0.000,0.000]',
|
||||
'[G58:0.000,0.000,0.000]',
|
||||
'[G59:0.000,0.000,0.000]',
|
||||
'[G28:0.000,0.000,0.000]',
|
||||
'[G30:0.000,0.000,0.000]',
|
||||
'[G92:0.000,0.000,0.000]'
|
||||
];
|
||||
const runner = new GrblRunner();
|
||||
let i = 0;
|
||||
runner.on('parameters', ({ name, value, raw }) => {
|
||||
if (i < lines.length) {
|
||||
t.equal(raw, lines[i]);
|
||||
}
|
||||
if (name === 'G54') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G55') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G56') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G57') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G58') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G59') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G28') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G30') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G92') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
|
||||
++i;
|
||||
if (i >= lines.length) {
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
lines.forEach(line => {
|
||||
runner.parse(line);
|
||||
});
|
||||
});
|
||||
|
||||
test('GrblLineParserResultParameters:TLO', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('parameters', ({ name, value, raw }) => {
|
||||
t.equal(raw, '[TLO:0.000]');
|
||||
t.equal(name, 'TLO');
|
||||
t.equal(value, '0.000');
|
||||
t.end();
|
||||
});
|
||||
|
||||
runner.parse('[TLO:0.000]');
|
||||
});
|
||||
|
||||
test('GrblLineParserResultParameters:PRB', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('parameters', ({ name, value, raw }) => {
|
||||
t.equal(raw, '[PRB:0.000,0.000,1.492:1]');
|
||||
t.equal(name, 'PRB');
|
||||
t.same(value, {
|
||||
result: 1,
|
||||
x: '0.000',
|
||||
y: '0.000',
|
||||
z: '1.492'
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
runner.parse('[PRB:0.000,0.000,1.492:1]');
|
||||
});
|
||||
|
||||
test('GrblLineParserResultFeedback', (t) => {
|
||||
const lines = [
|
||||
// $I - View build info
|
||||
'[0.9j.20160303:]',
|
||||
// Sent after an alarm message to tell the user to reset Grbl as an acknowledgement that an alarm has happened.
|
||||
'[Reset to continue]',
|
||||
// After an alarm and the user has sent a reset,
|
||||
'[\'$H\'|\'$X\' to unlock]',
|
||||
// This feedback message is sent when the user overrides the alarm.
|
||||
'[Caution: Unlocked]',
|
||||
// $C - Check gcode mode
|
||||
'[Enabled]',
|
||||
'[Disabled]'
|
||||
];
|
||||
const runner = new GrblRunner();
|
||||
let i = 0;
|
||||
runner.on('feedback', ({ raw, ...full }) => {
|
||||
const message = trim(lines[i], '[]');
|
||||
|
||||
if (i < lines.length) {
|
||||
t.equal(raw, lines[i]);
|
||||
t.equal(full.message, message);
|
||||
}
|
||||
|
||||
++i;
|
||||
if (i >= lines.length) {
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
lines.forEach(line => {
|
||||
runner.parse(line);
|
||||
});
|
||||
});
|
||||
|
||||
test('GrblLineParserResultSettings', (t) => {
|
||||
const lines = [
|
||||
'$1=25 (step idle delay, msec)',
|
||||
'$2=0 (step port invert mask:00000000)',
|
||||
'$3=0 (dir port invert mask:00000000)',
|
||||
'$4=0 (step enable invert, bool)',
|
||||
'$5=0 (limit pins invert, bool)',
|
||||
'$6=0 (probe pin invert, bool)',
|
||||
'$10=3 (status report mask:00000011)',
|
||||
'$11=0.020 (junction deviation, mm)',
|
||||
'$12=0.002 (arc tolerance, mm)',
|
||||
'$13=0 (report inches, bool)',
|
||||
'$20=0 (soft limits, bool)',
|
||||
'$21=0 (hard limits, bool)',
|
||||
'$22=0 (homing cycle, bool)',
|
||||
'$23=0 (homing dir invert mask:00000000)',
|
||||
'$24=25.000 (homing feed, mm/min)',
|
||||
'$25=500.000 (homing seek, mm/min)',
|
||||
'$26=250 (homing debounce, msec)',
|
||||
'$27=1.000 (homing pull-off, mm)',
|
||||
'$100=320.000 (x, step/mm)',
|
||||
'$101=320.000 (y, step/mm)',
|
||||
'$102=250.000 (z, step/mm)',
|
||||
'$110=2500.000 (x max rate, mm/min)',
|
||||
'$111=2500.000 (y max rate, mm/min)',
|
||||
'$112=500.000 (z max rate, mm/min)',
|
||||
'$120=250.000 (x accel, mm/sec^2)',
|
||||
'$121=250.000 (y accel, mm/sec^2)',
|
||||
'$122=50.000 (z accel, mm/sec^2)',
|
||||
'$130=200.000 (x max travel, mm)',
|
||||
'$131=200.000 (y max travel, mm)',
|
||||
'$132=200.000 (z max travel, mm)'
|
||||
];
|
||||
const runner = new GrblRunner();
|
||||
let i = 0;
|
||||
runner.on('settings', ({ raw, name, value, message }) => {
|
||||
if (i < lines.length) {
|
||||
const r = raw.match(/^(\$[^=]+)=([^ ]*)\s*(.*)/);
|
||||
t.equal(raw, lines[i]);
|
||||
t.equal(name, r[1]);
|
||||
t.equal(value, r[2]);
|
||||
t.equal(message, trim(r[3], '()'));
|
||||
}
|
||||
|
||||
++i;
|
||||
if (i >= lines.length) {
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
lines.forEach(line => {
|
||||
runner.parse(line);
|
||||
});
|
||||
});
|
||||
|
||||
test('GrblLineParserResultStartup', (t) => {
|
||||
t.test('Grbl 0.9j', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('startup', ({ raw, firmware, version, message }) => {
|
||||
t.equal(raw, 'Grbl 0.9j [\'$\' for help]');
|
||||
t.equal(firmware, 'Grbl');
|
||||
t.equal(version, '0.9j');
|
||||
t.equal(message, '[\'$\' for help]');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Grbl 0.9j [\'$\' for help]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Grbl 1.1f', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('startup', ({ raw, firmware, version, message }) => {
|
||||
t.equal(raw, 'Grbl 1.1f [\'$\' for help]');
|
||||
t.equal(firmware, 'Grbl');
|
||||
t.equal(version, '1.1f');
|
||||
t.equal(message, '[\'$\' for help]');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Grbl 1.1f [\'$\' for help]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Custom firmware build', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('startup', ({ raw, firmware, version, message }) => {
|
||||
t.equal(raw, 'Grbl 1.2.3');
|
||||
t.equal(firmware, 'Grbl');
|
||||
t.equal(version, '1.2.3');
|
||||
t.equal(message, '');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Grbl 1.2.3';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Custom firmware build: LongMill build #1', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('startup', ({ raw, firmware, version, message }) => {
|
||||
t.equal(raw, 'Grbl 1.1h: LongMill build [\'$\' for help]');
|
||||
t.equal(firmware, 'Grbl');
|
||||
t.equal(version, '1.1h');
|
||||
t.equal(message, ': LongMill build [\'$\' for help]');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Grbl 1.1h: LongMill build [\'$\' for help]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Custom firmware build: LongMill build #2', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('startup', ({ raw, firmware, version, message }) => {
|
||||
t.equal(raw, 'Grbl 1.1h [\'$\' for help] LongMill build Feb 25, 2020');
|
||||
t.equal(firmware, 'Grbl');
|
||||
t.equal(version, '1.1h');
|
||||
t.equal(message, '[\'$\' for help] LongMill build Feb 25, 2020');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Grbl 1.1h [\'$\' for help] LongMill build Feb 25, 2020';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Custom firmware build: vCarvin', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('startup', ({ raw, firmware, version, message }) => {
|
||||
t.equal(raw, 'vCarvin 2.0.0 [\'$\' for help]');
|
||||
t.equal(firmware, 'vCarvin');
|
||||
t.equal(version, '2.0.0');
|
||||
t.equal(message, '[\'$\' for help]');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'vCarvin 2.0.0 [\'$\' for help]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('Not supported output format', (t) => {
|
||||
const runner = new GrblRunner();
|
||||
runner.on('others', ({ raw }) => {
|
||||
t.equal(raw, 'Not supported output format');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Not supported output format';
|
||||
runner.parse(line);
|
||||
});
|
||||
286
cncjs/test/marlin.js
Normal file
286
cncjs/test/marlin.js
Normal file
@@ -0,0 +1,286 @@
|
||||
import { test } from 'tap';
|
||||
import MarlinRunner from '../src/server/controllers/Marlin/MarlinRunner';
|
||||
|
||||
test('MarlinLineParserResultEcho', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('echo', ({ raw, message }) => {
|
||||
t.equal(raw, 'echo:message');
|
||||
t.equal(message, 'message');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'echo:message';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('MarlinLineParserResultError', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('error', ({ raw, message }) => {
|
||||
t.equal(raw, 'Error:Printer halted. kill() called!');
|
||||
t.equal(message, 'Printer halted. kill() called!');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Error:Printer halted. kill() called!';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('MarlinLineParserResultFirmware', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('firmware', (payload) => {
|
||||
const { raw, firmwareName, protocolVersion, machineType, extruderCount, uuid } = payload;
|
||||
|
||||
t.equal(raw, 'FIRMWARE_NAME:Marlin 1.1.0 (Github) SOURCE_CODE_URL:https://github.com/MarlinFirmware/Marlin PROTOCOL_VERSION:1.0 MACHINE_TYPE:RepRap EXTRUDER_COUNT:1 UUID:cede2a2f-41a2-4748-9b12-c55c62f367ff');
|
||||
t.equal(firmwareName, 'Marlin 1.1.0');
|
||||
t.equal(protocolVersion, '1.0');
|
||||
t.equal(machineType, 'RepRap');
|
||||
t.equal(extruderCount, 1);
|
||||
t.equal(uuid, 'cede2a2f-41a2-4748-9b12-c55c62f367ff');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'FIRMWARE_NAME:Marlin 1.1.0 (Github) SOURCE_CODE_URL:https://github.com/MarlinFirmware/Marlin PROTOCOL_VERSION:1.0 MACHINE_TYPE:RepRap EXTRUDER_COUNT:1 UUID:cede2a2f-41a2-4748-9b12-c55c62f367ff';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('MarlinLineParserResultOk', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('ok', ({ raw }) => {
|
||||
t.equal(raw, 'ok');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('MarlinLineParserResultPosition', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('pos', ({ raw, pos }) => {
|
||||
t.equal(raw, 'X:1.529 Y:-5.440 Z:0.00 E:0.00 Count X:0 Y:0 Z:0');
|
||||
t.same(pos, {
|
||||
x: '1.529',
|
||||
y: '-5.440',
|
||||
z: '0.00',
|
||||
e: '0.00'
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'X:1.529 Y:-5.440 Z:0.00 E:0.00 Count X:0 Y:0 Z:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('MarlinLineParserResultStart', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('start', ({ raw }) => {
|
||||
t.equal(raw, 'start');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'start';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('MarlinLineParserResultTemperature', (t) => {
|
||||
t.test('ok T:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, 'ok T:0');
|
||||
t.equal(ok, true);
|
||||
t.same(extruder, {});
|
||||
t.same(heatedBed, {});
|
||||
t.equal(wait, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok T:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('ok T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, 'ok T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0');
|
||||
t.equal(ok, true);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('ok T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, 'ok T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0');
|
||||
t.equal(ok, true);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, 'ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0');
|
||||
t.equal(ok, true);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0 W:?', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, 'ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0 W:?');
|
||||
t.equal(ok, true);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, '?');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0 W:?';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0 W:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, 'ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0 W:0');
|
||||
t.equal(ok, true);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, '0');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0 W:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test(' T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, ' T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0');
|
||||
t.equal(ok, false);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = ' T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test(' T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, ' T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0');
|
||||
t.equal(ok, false);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = ' T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test(' T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0', (t) => {
|
||||
const runner = new MarlinRunner();
|
||||
runner.on('temperature', ({ raw, ok, extruder, heatedBed, wait }) => {
|
||||
t.equal(raw, ' T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0');
|
||||
t.equal(ok, false);
|
||||
t.same(extruder, {
|
||||
deg: '293.0',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.same(heatedBed, {
|
||||
deg: '25.9',
|
||||
degTarget: '0.0',
|
||||
power: 0,
|
||||
});
|
||||
t.equal(wait, undefined);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = ' T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
253
cncjs/test/sender.js
Normal file
253
cncjs/test/sender.js
Normal file
@@ -0,0 +1,253 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { test } from 'tap';
|
||||
import ProgressBar from 'progress';
|
||||
import Sender, {
|
||||
SP_TYPE_SEND_RESPONSE,
|
||||
SP_TYPE_CHAR_COUNTING
|
||||
} from '../src/server/lib/Sender';
|
||||
|
||||
test('null streaming protocol', (t) => {
|
||||
const sender = new Sender(null);
|
||||
t.equal(sender.sp, null);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('send-response streaming protocol', (t) => {
|
||||
const sender = new Sender(SP_TYPE_SEND_RESPONSE);
|
||||
t.equal(sender.sp.type, SP_TYPE_SEND_RESPONSE, 'send-response streaming protocol');
|
||||
|
||||
const file = path.resolve(__dirname, 'fixtures/jsdc.gcode');
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
const context = {
|
||||
xmin: 0,
|
||||
xmax: 100,
|
||||
ymin: 0,
|
||||
ymax: 100,
|
||||
zmin: -2,
|
||||
zmax: 50
|
||||
};
|
||||
const ok = sender.load(path.basename(file), content, context);
|
||||
t.equal(ok, true, `Failed to load "${file}".`);
|
||||
|
||||
t.same(sender.toJSON(), {
|
||||
sp: SP_TYPE_SEND_RESPONSE,
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
name: path.basename(file),
|
||||
context: context,
|
||||
size: sender.state.gcode.length,
|
||||
total: sender.state.total,
|
||||
sent: 0,
|
||||
received: 0,
|
||||
startTime: sender.state.startTime,
|
||||
finishTime: sender.state.finishTime,
|
||||
elapsedTime: sender.state.elapsedTime,
|
||||
remainingTime: sender.state.remainingTime
|
||||
});
|
||||
|
||||
sender.on('data', () => {
|
||||
sender.ack();
|
||||
});
|
||||
sender.on('start', () => {
|
||||
});
|
||||
sender.on('end', () => {
|
||||
t.same(sender.toJSON(), {
|
||||
sp: SP_TYPE_SEND_RESPONSE,
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
name: path.basename(file),
|
||||
context: context,
|
||||
size: sender.state.gcode.length,
|
||||
total: sender.state.total,
|
||||
sent: sender.state.sent,
|
||||
received: sender.state.received,
|
||||
startTime: sender.state.startTime,
|
||||
finishTime: sender.state.finishTime,
|
||||
elapsedTime: sender.state.elapsedTime,
|
||||
remainingTime: sender.state.remainingTime
|
||||
});
|
||||
|
||||
sender.unload();
|
||||
|
||||
t.equal(sender.sp.type, SP_TYPE_SEND_RESPONSE);
|
||||
t.same(sender.state, {
|
||||
name: '',
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
context: {},
|
||||
gcode: '',
|
||||
lines: [],
|
||||
total: 0,
|
||||
sent: 0,
|
||||
received: 0,
|
||||
startTime: 0,
|
||||
finishTime: 0,
|
||||
elapsedTime: 0,
|
||||
remainingTime: 0
|
||||
});
|
||||
t.same(sender.toJSON(), {
|
||||
sp: SP_TYPE_SEND_RESPONSE,
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
name: '',
|
||||
context: {},
|
||||
size: 0,
|
||||
total: 0,
|
||||
sent: 0,
|
||||
received: 0,
|
||||
startTime: 0,
|
||||
finishTime: 0,
|
||||
elapsedTime: 0,
|
||||
remainingTime: 0
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
const bar = new ProgressBar('processing [:bar] :percent :etas', {
|
||||
total: sender.state.total
|
||||
});
|
||||
const timer = setInterval(() => {
|
||||
bar.tick();
|
||||
|
||||
sender.next();
|
||||
|
||||
if (bar.complete) {
|
||||
clearInterval(timer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender.peek()) {
|
||||
// Nothing
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
test('character-counting streaming protocol', (t) => {
|
||||
const sender = new Sender(SP_TYPE_CHAR_COUNTING, {
|
||||
bufferSize: 256
|
||||
});
|
||||
t.equal(sender.sp.type, SP_TYPE_CHAR_COUNTING, 'character-counting streaming protocol');
|
||||
|
||||
// Validation
|
||||
sender.sp.bufferSize = 0;
|
||||
t.equal(sender.sp.bufferSize, 256);
|
||||
sender.sp.bufferSize = 128;
|
||||
t.equal(sender.sp.bufferSize, 128);
|
||||
sender.sp.dataLength = 120;
|
||||
sender.sp.bufferSize = 100;
|
||||
t.equal(sender.sp.bufferSize, 120, 'The buffer size cannot be reduced below the size of the data within the buffer.');
|
||||
sender.sp.clear();
|
||||
sender.sp.bufferSize = 256;
|
||||
t.equal(sender.sp.bufferSize, 256);
|
||||
t.equal(sender.sp.dataLength, 0);
|
||||
t.equal(sender.sp.queue.length, 0);
|
||||
t.equal(sender.sp.line, '');
|
||||
|
||||
const file = path.resolve(__dirname, 'fixtures/jsdc.gcode');
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
const context = {
|
||||
xmin: 0,
|
||||
xmax: 100,
|
||||
ymin: 0,
|
||||
ymax: 100,
|
||||
zmin: -2,
|
||||
zmax: 50
|
||||
};
|
||||
const ok = sender.load(path.basename(file), content, context);
|
||||
t.equal(ok, true, `Failed to load "${file}".`);
|
||||
|
||||
t.same(sender.toJSON(), {
|
||||
sp: SP_TYPE_CHAR_COUNTING,
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
name: path.basename(file),
|
||||
context: context,
|
||||
size: sender.state.gcode.length,
|
||||
total: sender.state.total,
|
||||
sent: 0,
|
||||
received: 0,
|
||||
startTime: sender.state.startTime,
|
||||
finishTime: sender.state.finishTime,
|
||||
elapsedTime: sender.state.elapsedTime,
|
||||
remainingTime: sender.state.remainingTime
|
||||
});
|
||||
|
||||
sender.on('data', () => {
|
||||
sender.ack();
|
||||
});
|
||||
sender.on('start', () => {
|
||||
});
|
||||
sender.on('end', () => {
|
||||
t.same(sender.toJSON(), {
|
||||
sp: SP_TYPE_CHAR_COUNTING,
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
name: path.basename(file),
|
||||
context: context,
|
||||
size: sender.state.gcode.length,
|
||||
total: sender.state.total,
|
||||
sent: sender.state.sent,
|
||||
received: sender.state.received,
|
||||
startTime: sender.state.startTime,
|
||||
finishTime: sender.state.finishTime,
|
||||
elapsedTime: sender.state.elapsedTime,
|
||||
remainingTime: sender.state.remainingTime
|
||||
});
|
||||
|
||||
sender.unload();
|
||||
|
||||
t.equal(sender.sp.type, SP_TYPE_CHAR_COUNTING);
|
||||
t.same(sender.state, {
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
name: '',
|
||||
gcode: '',
|
||||
context: {},
|
||||
lines: [],
|
||||
total: 0,
|
||||
sent: 0,
|
||||
received: 0,
|
||||
startTime: 0,
|
||||
finishTime: 0,
|
||||
elapsedTime: 0,
|
||||
remainingTime: 0
|
||||
});
|
||||
t.same(sender.toJSON(), {
|
||||
sp: SP_TYPE_CHAR_COUNTING,
|
||||
hold: false,
|
||||
holdReason: null,
|
||||
name: '',
|
||||
context: {},
|
||||
size: 0,
|
||||
total: 0,
|
||||
sent: 0,
|
||||
received: 0,
|
||||
startTime: 0,
|
||||
finishTime: 0,
|
||||
elapsedTime: 0,
|
||||
remainingTime: 0
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
const bar = new ProgressBar('processing [:bar] :percent :etas', {
|
||||
total: sender.state.total
|
||||
});
|
||||
const timer = setInterval(() => {
|
||||
bar.tick();
|
||||
|
||||
sender.next();
|
||||
|
||||
if (bar.complete) {
|
||||
clearInterval(timer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender.peek()) {
|
||||
// Nothing
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
466
cncjs/test/smoothie.js
Normal file
466
cncjs/test/smoothie.js
Normal file
@@ -0,0 +1,466 @@
|
||||
import { test } from 'tap';
|
||||
import SmoothieRunner from '../src/server/controllers/Smoothie/SmoothieRunner';
|
||||
|
||||
// $10 - Status report mask:binary
|
||||
// Report Type | Value
|
||||
// Machine Position | 1
|
||||
// Work Position | 2
|
||||
// Planner Buffer | 4
|
||||
// RX Buffer | 8
|
||||
// Limit Pins | 16
|
||||
test('SmoothieRunnerLineParserResultStatus: all zeroes in the mask ($10=0)', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultStatus: old status format', (t) => {
|
||||
t.test('6-axis', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle,MPos:200.0000,200.0000,0.0000,0.0000,0.0000,0.0000,WPos:200.0000,200.0000,0.0000>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
mpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
a: '0.0000',
|
||||
b: '0.0000',
|
||||
c: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
}
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle,MPos:200.0000,200.0000,0.0000,0.0000,0.0000,0.0000,WPos:200.0000,200.0000,0.0000>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultStatus: new status format', (t) => {
|
||||
t.test('6-axis', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle|MPos:200.0000,200.0000,0.0000,0.0000,0.0000,0.0000|WPos:200.0000,200.0000,0.0000|F:4000.0,100.0>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
mpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
a: '0.0000',
|
||||
b: '0.0000',
|
||||
c: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
},
|
||||
feedrate: '4000.0',
|
||||
feedrateOverride: '100.0',
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle|MPos:200.0000,200.0000,0.0000,0.0000,0.0000,0.0000|WPos:200.0000,200.0000,0.0000|F:4000.0,100.0>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Laser', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle|MPos:200.0000,200.0000,0.0000,0.0000,0.0000,0.0000|WPos:200.0000,200.0000,0.0000|F:4000.0,100.0|L:0.0000|S:0.8000>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
mpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
a: '0.0000',
|
||||
b: '0.0000',
|
||||
c: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
},
|
||||
feedrate: '4000.0',
|
||||
feedrateOverride: '100.0',
|
||||
laserPower: '0.0000',
|
||||
laserIntensity: '0.8000',
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle|MPos:200.0000,200.0000,0.0000,0.0000,0.0000,0.0000|WPos:200.0000,200.0000,0.0000|F:4000.0,100.0|L:0.0000|S:0.8000>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Home', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Home|MPos:15.8250,15.8250,0.0000|WPos:15.8250,15.8250,0.0000|F:4000.0,4000.0,100.0>');
|
||||
t.same(status, {
|
||||
activeState: 'Home',
|
||||
mpos: {
|
||||
x: '15.8250',
|
||||
y: '15.8250',
|
||||
z: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '15.8250',
|
||||
y: '15.8250',
|
||||
z: '0.0000',
|
||||
},
|
||||
currentFeedrate: '4000.0',
|
||||
feedrate: '4000.0',
|
||||
feedrateOverride: '100.0',
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Home|MPos:15.8250,15.8250,0.0000|WPos:15.8250,15.8250,0.0000|F:4000.0,4000.0,100.0>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Run', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Run|MPos:15.8250,15.8250,0.0000|WPos:15.8250,15.8250,0.0000|F:4000.0,4000.0,100.0>');
|
||||
t.same(status, {
|
||||
activeState: 'Run',
|
||||
mpos: {
|
||||
x: '15.8250',
|
||||
y: '15.8250',
|
||||
z: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '15.8250',
|
||||
y: '15.8250',
|
||||
z: '0.0000',
|
||||
},
|
||||
currentFeedrate: '4000.0',
|
||||
feedrate: '4000.0',
|
||||
feedrateOverride: '100.0',
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Run|MPos:15.8250,15.8250,0.0000|WPos:15.8250,15.8250,0.0000|F:4000.0,4000.0,100.0>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('Idle', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
t.equal(raw, '<Idle|MPos:200.0000,200.0000,0.0000|WPos:200.0000,200.0000,0.0000|F:4000.0,100.0>');
|
||||
t.same(status, {
|
||||
activeState: 'Idle',
|
||||
mpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
},
|
||||
feedrate: '4000.0',
|
||||
feedrateOverride: '100.0',
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '<Idle|MPos:200.0000,200.0000,0.0000|WPos:200.0000,200.0000,0.0000|F:4000.0,100.0>';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('state transition', (t) => {
|
||||
let lineNumber = 0;
|
||||
const lines = [
|
||||
'<Run|MPos:15.8250,15.8250,0.0000|WPos:15.8250,15.8250,0.0000|F:4000.0,4000.0,100.0>',
|
||||
'<Idle|MPos:200.0000,200.0000,0.0000|WPos:200.0000,200.0000,0.0000|F:4000.0,100.0>',
|
||||
];
|
||||
const expectedResults = [
|
||||
{ // Run
|
||||
activeState: 'Run',
|
||||
mpos: {
|
||||
x: '15.8250',
|
||||
y: '15.8250',
|
||||
z: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '15.8250',
|
||||
y: '15.8250',
|
||||
z: '0.0000',
|
||||
},
|
||||
currentFeedrate: '4000.0',
|
||||
feedrate: '4000.0',
|
||||
feedrateOverride: '100.0',
|
||||
},
|
||||
{ // Idle
|
||||
activeState: 'Idle',
|
||||
mpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
},
|
||||
wpos: {
|
||||
x: '200.0000',
|
||||
y: '200.0000',
|
||||
z: '0.0000',
|
||||
},
|
||||
feedrate: '4000.0',
|
||||
feedrateOverride: '100.0',
|
||||
}
|
||||
];
|
||||
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('status', ({ raw, ...status }) => {
|
||||
const index = lineNumber - 1;
|
||||
t.equal(raw, lines[index]);
|
||||
t.same(status, expectedResults[index]);
|
||||
|
||||
if (lineNumber === lines.length) {
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
lineNumber = index + 1;
|
||||
runner.parse(line);
|
||||
});
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultOk', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('ok', ({ raw }) => {
|
||||
t.equal(raw, 'ok');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ok';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultError', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('error', ({ raw, message }) => {
|
||||
t.equal(raw, 'error: Expected command letter');
|
||||
t.equal(message, 'Expected command letter');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'error: Expected command letter';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultAlarm', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('alarm', ({ raw, message }) => {
|
||||
t.equal(raw, 'ALARM: Probe fail');
|
||||
t.equal(message, 'Probe fail');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'ALARM: Probe fail';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultParserState', (t) => {
|
||||
test('#1', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('parserstate', ({ raw, ...parserstate }) => {
|
||||
t.equal(raw, '[G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 F2540. S0.]');
|
||||
t.same(parserstate, {
|
||||
modal: {
|
||||
motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
|
||||
wcs: 'G54', // G54, G55, G56, G57, G58, G59
|
||||
plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
|
||||
units: 'G21', // G20: Inches, G21: Millimeters
|
||||
distance: 'G90', // G90: Absolute, G91: Relative
|
||||
feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
|
||||
program: 'M0',
|
||||
spindle: 'M5',
|
||||
coolant: 'M9'
|
||||
},
|
||||
tool: '0',
|
||||
feedrate: '2540.',
|
||||
spindle: '0.'
|
||||
});
|
||||
t.equal(runner.getTool(), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '[G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 F2540. S0.]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('#2', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('parserstate', ({ raw, ...parserstate }) => {
|
||||
t.equal(raw, '[G0 G54 G17 G21 G90 G94 M0 M5 M7 M8 T2 F2540. S0.]');
|
||||
t.same(parserstate, {
|
||||
modal: {
|
||||
motion: 'G0', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
|
||||
wcs: 'G54', // G54, G55, G56, G57, G58, G59
|
||||
plane: 'G17', // G17: xy-plane, G18: xz-plane, G19: yz-plane
|
||||
units: 'G21', // G20: Inches, G21: Millimeters
|
||||
distance: 'G90', // G90: Absolute, G91: Relative
|
||||
feedrate: 'G94', // G93: Inverse Time Mode, G94: Units Per Minutes
|
||||
program: 'M0',
|
||||
spindle: 'M5',
|
||||
coolant: ['M7', 'M8']
|
||||
},
|
||||
tool: '2',
|
||||
feedrate: '2540.',
|
||||
spindle: '0.'
|
||||
});
|
||||
t.equal(runner.getTool(), 2);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '[G0 G54 G17 G21 G90 G94 M0 M5 M7 M8 T2 F2540. S0.]';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultParameters:G54,G55,G56,G57,G58,G59,G28,G30,G92', (t) => {
|
||||
const lines = [
|
||||
'[G54:0.000,0.000,0.000]',
|
||||
'[G55:0.000,0.000,0.000]',
|
||||
'[G56:0.000,0.000,0.000]',
|
||||
'[G57:0.000,0.000,0.000]',
|
||||
'[G58:0.000,0.000,0.000]',
|
||||
'[G59:0.000,0.000,0.000]',
|
||||
'[G28:0.000,0.000,0.000]',
|
||||
'[G30:0.000,0.000,0.000]',
|
||||
'[G92:0.000,0.000,0.000]'
|
||||
];
|
||||
const runner = new SmoothieRunner();
|
||||
let i = 0;
|
||||
runner.on('parameters', ({ name, value, raw }) => {
|
||||
if (i < lines.length) {
|
||||
t.equal(raw, lines[i]);
|
||||
}
|
||||
if (name === 'G54') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G55') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G56') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G57') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G58') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G59') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G28') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G30') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
if (name === 'G92') {
|
||||
t.same(value, { x: '0.000', y: '0.000', z: '0.000' });
|
||||
}
|
||||
|
||||
++i;
|
||||
if (i >= lines.length) {
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
|
||||
lines.forEach(line => {
|
||||
runner.parse(line);
|
||||
});
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultParameters:TLO', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('parameters', ({ name, value, raw }) => {
|
||||
t.equal(raw, '[TLO:0.000]');
|
||||
t.equal(name, 'TLO');
|
||||
t.equal(value, '0.000');
|
||||
t.end();
|
||||
});
|
||||
|
||||
runner.parse('[TLO:0.000]');
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultParameters:PRB', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('parameters', ({ name, value, raw }) => {
|
||||
t.equal(raw, '[PRB:0.000,0.000,1.492:1]');
|
||||
t.equal(name, 'PRB');
|
||||
t.same(value, {
|
||||
result: 1,
|
||||
x: '0.000',
|
||||
y: '0.000',
|
||||
z: '1.492'
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
runner.parse('[PRB:0.000,0.000,1.492:1]');
|
||||
});
|
||||
|
||||
test('SmoothieRunnerLineParserResultVersion', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('version', ({ raw, ...others }) => {
|
||||
t.equal(raw, 'Build version: edge-3332442, Build date: xxx, MCU: LPC1769, System Clock: 120MHz');
|
||||
t.same(others, {
|
||||
build: {
|
||||
version: 'edge-3332442',
|
||||
date: 'xxx'
|
||||
},
|
||||
mcu: 'LPC1769',
|
||||
sysclk: '120MHz'
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Build version: edge-3332442, Build date: xxx, MCU: LPC1769, System Clock: 120MHz';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
test('Not supported output format', (t) => {
|
||||
const runner = new SmoothieRunner();
|
||||
runner.on('others', ({ raw }) => {
|
||||
t.equal(raw, 'Not supported output format');
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = 'Not supported output format';
|
||||
runner.parse(line);
|
||||
});
|
||||
172
cncjs/test/tinyg.js
Normal file
172
cncjs/test/tinyg.js
Normal file
@@ -0,0 +1,172 @@
|
||||
import { test } from 'tap';
|
||||
import TinyGRunner from '../src/server/controllers/TinyG/TinyGRunner';
|
||||
|
||||
test('TinyGParserResultMotorTimeout', (t) => {
|
||||
t.test('{"r":{"mt":2},"f":[1,0,8]}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('mt', (mt) => {
|
||||
t.equal(mt, 2);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"r":{"mt":2},"f":[1,0,8]}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('TinyGParserResultPowerManagement', (t) => {
|
||||
t.test('{"r":{"pwr":{"1":0,"2":0,"3":0,"4":0}},"f":[1,0,9]}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('pwr', (pwr) => {
|
||||
t.same(pwr, { '1': 0, '2': 0, '3': 0, '4': 0 });
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"r":{"pwr":{"1":0,"2":0,"3":0,"4":0}},"f":[1,0,9]}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('TinyGParserResultQueueReports', (t) => {
|
||||
t.test('{"qr":48}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
|
||||
runner.on('qr', ({ qr, qi, qo }) => {
|
||||
t.equal(qr, 48);
|
||||
t.equal(qi, 0);
|
||||
t.equal(qo, 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
runner.parse('{"qr":48}');
|
||||
});
|
||||
|
||||
t.test('{"r":{"qr":32,"qi":0,"qo":1},"f":[1,0,8]}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
|
||||
runner.on('qr', ({ qr, qi, qo }) => {
|
||||
t.equal(qr, 32);
|
||||
t.equal(qi, 0);
|
||||
t.equal(qo, 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
runner.parse('{"r":{"qr":32,"qi":0,"qo":1},"f":[1,0,8]}');
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('TinyGParserResultStatusReports', (t) => {
|
||||
t.test('{"sr":{"line":8,"stat":5,"cycs":1,"mots":1}}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('sr', ({ line, stat, cycs, mots }) => {
|
||||
t.equal(line, 8);
|
||||
t.equal(stat, 5);
|
||||
t.equal(cycs, 1);
|
||||
t.equal(mots, 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"sr":{"line":8,"stat":5,"cycs":1,"mots":1}}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.test('{"sr":{"line":0,"vel":688.81,"mots":2,"dist":1,"posx":0.248,"posy":0.248,"mpox":0.248,"mpoy":0.248}}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('sr', ({ line, vel, mots, dist, posx, posy, mpox, mpoy }) => {
|
||||
t.equal(line, 0);
|
||||
t.equal(vel, 688.81);
|
||||
t.equal(mots, 2);
|
||||
t.equal(dist, 1);
|
||||
t.equal(posx, 0.248);
|
||||
t.equal(posy, 0.248);
|
||||
t.equal(mpox, 0.248);
|
||||
t.equal(mpoy, 0.248);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"sr":{"line":0,"vel":688.81,"mots":2,"dist":1,"posx":0.248,"posy":0.248,"mpox":0.248,"mpoy":0.248}}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
// active tool number
|
||||
t.test('{"sr":{"stat":4,"tool":3}}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('sr', ({ stat, tool }) => {
|
||||
t.equal(tool, 3);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"sr":{"stat":4,"tool":3}}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('TinyGParserResultSystemSettings', (t) => {
|
||||
t.test('{"r":{"sys":{"fb":100.19,"fbs":"100.19-17-g129b","fbc":"settings_othermill.h","fv":0.99,"hp":3,"hv":0,"id":"0084-7bd6-29c6-7bd","jt":0.75,"ct":0.01,"sl":0,"lim":1,"saf":1,"m48e":1,"mfoe":0,"mfo":1,"mtoe":0,"mto":1,"mt":2,"spep":1,"spdp":0,"spph":1,"spdw":1.5,"ssoe":0,"sso":1,"cofp":1,"comp":1,"coph":1,"tv":1,"ej":1,"jv":4,"qv":1,"sv":1,"si":100,"gpl":0,"gun":1,"gco":2,"gpa":2,"gdi":0}},"f":[1,0,9]}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('sys', ({ fv, fb, fbs, fbc, hp, hv, id, mfo, mto, sso }) => {
|
||||
t.equal(fv, 0.99);
|
||||
t.equal(fb, 100.19);
|
||||
t.equal(fbs, '100.19-17-g129b');
|
||||
t.equal(fbc, 'settings_othermill.h');
|
||||
t.equal(hp, 3);
|
||||
t.equal(hv, 0);
|
||||
t.equal(id, '0084-7bd6-29c6-7bd');
|
||||
t.equal(mfo, 1);
|
||||
t.equal(mto, 1);
|
||||
t.equal(sso, 1);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"r":{"sys":{"fb":100.19,"fbs":"100.19-17-g129b","fbc":"settings_othermill.h","fv":0.99,"hp":3,"hv":0,"id":"0084-7bd6-29c6-7bd","jt":0.75,"ct":0.01,"sl":0,"lim":1,"saf":1,"m48e":1,"mfoe":0,"mfo":1,"mtoe":0,"mto":1,"mt":2,"spep":1,"spdp":0,"spph":1,"spdw":1.5,"ssoe":0,"sso":1,"cofp":1,"comp":1,"coph":1,"tv":1,"ej":1,"jv":4,"qv":1,"sv":1,"si":100,"gpl":0,"gun":1,"gco":2,"gpa":2,"gdi":0}},"f":[1,0,9]}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('TinyGParserResultOverrides', (t) => {
|
||||
t.test('{"r":{"mfo":1.0,"mto":1.0,"sso":1.0},"f":[1,0,21]}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('ov', ({ mfo, mto, sso }) => {
|
||||
t.assert(mfo, 1.0);
|
||||
t.assert(mto, 1.0);
|
||||
t.assert(sso, 1.0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"r":{"mfo":1.0,"mto":1.0,"sso":1.0},"f":[1,0,21]}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('TinyGParserResultReceiveReports', (t) => {
|
||||
t.test('{"r":{},"f":[1,0,4]}', (t) => {
|
||||
const runner = new TinyGRunner();
|
||||
runner.on('r', (r) => {
|
||||
t.same(r, {});
|
||||
});
|
||||
runner.on('f', (f) => {
|
||||
const [revision, statusCode, rxBufferInfo] = f;
|
||||
t.equal(revision, 1);
|
||||
t.equal(statusCode, 0);
|
||||
t.equal(rxBufferInfo, 4);
|
||||
t.end();
|
||||
});
|
||||
|
||||
const line = '{"r":{},"f":[1,0,4]}';
|
||||
runner.parse(line);
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
28
cncjs/test/translate-expression.js
Normal file
28
cncjs/test/translate-expression.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { test } from 'tap';
|
||||
import translateExpression from '../src/server/lib/translate-expression';
|
||||
|
||||
test('exceptions', (t) => {
|
||||
// Not a string type
|
||||
t.equal(translateExpression(0), '');
|
||||
|
||||
// Unexpected end of input
|
||||
t.equal(translateExpression('X[!]', {}), 'X[!]');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('expressions', (t) => {
|
||||
const data = 'G0 X[_x] Y[_y]\nG4 P[delay]\nG0 Z[_z]';
|
||||
const context = {
|
||||
_x: 10,
|
||||
_y: 20,
|
||||
_z: 30,
|
||||
delay: 1000
|
||||
};
|
||||
|
||||
const found = translateExpression(data, context);
|
||||
const wanted = 'G0 X10 Y20\nG4 P1000\nG0 Z30';
|
||||
t.equal(found, wanted);
|
||||
|
||||
t.end();
|
||||
});
|
||||
Reference in New Issue
Block a user