Skip to content

Commit

Permalink
Refactor g-code sender and line feeder
Browse files Browse the repository at this point in the history
  • Loading branch information
cheton committed Jan 11, 2017
1 parent d8cf212 commit 7d4fa30
Show file tree
Hide file tree
Showing 7 changed files with 360 additions and 266 deletions.
25 changes: 14 additions & 11 deletions src/app/api/api.gcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,18 @@ export const get = (req, res) => {
return;
}

const { sender } = controller;

res.send({
name: controller.sender.name,
data: controller.sender.gcode,
size: controller.sender.gcode.length,
total: controller.sender.total,
sent: controller.sender.sent,
received: controller.sender.received,
createdTime: controller.sender.createdTime,
startedTime: controller.sender.startedTime,
finishedTime: controller.sender.finishedTime
name: sender.state.name,
data: sender.state.gcode,
size: sender.state.gcode.length,
total: sender.state.total,
sent: sender.state.sent,
received: sender.state.received,
createdTime: sender.state.createdTime,
startedTime: sender.state.startedTime,
finishedTime: sender.state.finishedTime
});
};

Expand All @@ -87,6 +89,7 @@ export const download = (req, res) => {
return;
}

const { sender } = controller;
const filename = (function(req) {
const headers = req.headers || {};
const ua = headers['user-agent'] || '';
Expand All @@ -97,10 +100,10 @@ export const download = (req, res) => {
return (/Trident\/\d/).test(ua) && (!(/MSIE \d/).test(ua));
}(ua));

const name = controller.sender.name || 'noname.txt';
const name = sender.state.name || 'noname.txt';
return (isIE || isEdge) ? encodeURIComponent(name) : name;
}(req));
const content = controller.sender.gcode || '';
const content = sender.state.gcode || '';

res.setHeader('Content-Disposition', 'attachment; filename=' + JSON.stringify(filename));
res.setHeader('Connection', 'close');
Expand Down
8 changes: 4 additions & 4 deletions src/app/controllers/Grbl/Grbl.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ class GrblLineParserResultHelp {
static parse(line) {
// * Grbl v1.1
// [HLP:]
const r = line.match(/^\[(?:HLP:)?(.+)\]$/);
const r = line.match(/^\[(?:HLP:)(.+)\]$/);
if (!r) {
return null;
}
Expand All @@ -445,7 +445,7 @@ class GrblLineParserResultVersion {
static parse(line) {
// * Grbl v1.1
// [VER:]
const r = line.match(/^\[(?:VER:)?(.+)\]$/);
const r = line.match(/^\[(?:VER:)(.+)\]$/);
if (!r) {
return null;
}
Expand All @@ -465,7 +465,7 @@ class GrblLineParserResultOption {
static parse(line) {
// * Grbl v1.1
// [OPT:]
const r = line.match(/^\[(?:OPT:)?(.+)\]$/);
const r = line.match(/^\[(?:OPT:)(.+)\]$/);
if (!r) {
return null;
}
Expand All @@ -485,7 +485,7 @@ class GrblLineParserResultEcho {
static parse(line) {
// * Grbl v1.1
// [echo:]
const r = line.match(/^\[(?:echo:)?(.+)\]$/);
const r = line.match(/^\[(?:echo:)(.+)\]$/);
if (!r) {
return null;
}
Expand Down
38 changes: 21 additions & 17 deletions src/app/controllers/Grbl/GrblController.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _ from 'lodash';
import SerialPort from 'serialport';
import log from '../../lib/log';
import Feeder from '../../lib/feeder';
import Sender, { STREAMING_PROTOCOL_CHAR_COUNTING } from '../../lib/gcode-sender';
import Sender, { SP_TYPE_CHAR_COUNTING } from '../../lib/sender';
import config from '../../services/configstore';
import monitor from '../../services/monitor';
import store from '../../store';
Expand Down Expand Up @@ -117,16 +117,14 @@ class GrblController {
});

// Sender
this.sender = new Sender(STREAMING_PROTOCOL_CHAR_COUNTING, {
this.sender = new Sender(SP_TYPE_CHAR_COUNTING, {
// Grbl has a 127 character serial receive buffer.
// Use a lower value to deduct the length of regular commands:
// - parser state command ($G\n)
// - current status command: (?)
//
// The amount of free space in the serial receive buffer is 125 (i.e. 127 - 2 - 1).
// - parser state command: $G\n"
// - current status command: "?"
bufferSize: 120
});
this.sender.on('gcode', (gcode = '') => {
this.sender.on('data', (gcode = '') => {
if (this.isClose()) {
log.error(`[Grbl] The serial port "${this.options.port}" is not accessible`);
return;
Expand All @@ -152,6 +150,12 @@ class GrblController {
this.grbl.on('status', (res) => {
this.queryResponse.status = false;

if (res && res.buf && res.buf.rx) {
const rx = Number(res.buf.rx) || 0;
const bufferSize = Math.max(rx - 8, this.sender.sp.bufferSize);
this.sender.sp.bufferSize = bufferSize;
}

this.connections.forEach((c) => {
if (c.sentCommand.indexOf('?') === 0) {
c.sentCommand = '';
Expand Down Expand Up @@ -188,9 +192,11 @@ class GrblController {
this.grbl.on('error', (res) => {
// Sender
if (this.workflowState === WORKFLOW_STATE_RUNNING) {
const line = this.sender.lines[this.sender.received];
const { lines, received } = this.sender.state;
const line = lines[received];
const error = res.message;
this.emitAll('serialport:read', `> ${line}`);
this.emitAll('serialport:read', `error=${res.message}, line=${this.sender.received + 1}`);
this.emitAll('serialport:read', `error=${error}, line=${received + 1}`);

this.sender.ack();
this.sender.next();
Expand Down Expand Up @@ -308,14 +314,12 @@ class GrblController {

// Feeder
if (this.feeder.peek()) {
this.emitAll('feeder:status', {
'size': this.feeder.queue.length
});
this.emitAll('feeder:status', this.feeder.toJSON());
}

// Sender
if (this.sender.peek()) {
this.emitAll('sender:status', this.sender.state);
this.emitAll('sender:status', this.sender.toJSON());
}

// Grbl state
Expand Down Expand Up @@ -396,8 +400,8 @@ class GrblController {
state: this.state
},
workflowState: this.workflowState,
feeder: this.feeder.state,
sender: this.sender.state
feeder: this.feeder.toJSON(),
sender: this.sender.toJSON()
};
}
reset() {
Expand Down Expand Up @@ -487,7 +491,7 @@ class GrblController {

if (this.sender) {
// Send sender status to a newly connected client
socket.emit('sender:status', this.sender.state);
socket.emit('sender:status', this.sender.toJSON());
}
}
removeConnection(socket) {
Expand All @@ -512,7 +516,7 @@ class GrblController {
return;
}

log.debug(`[Grbl] Load G-code: name="${this.sender.name}", size=${this.sender.gcode.length}, total=${this.sender.total}`);
log.debug(`[Grbl] Load G-code: name="${this.sender.state.name}", size=${this.sender.state.gcode.length}, total=${this.sender.state.total}`);

this.workflowState = WORKFLOW_STATE_IDLE;
callback(null, { name: name, gcode: gcode });
Expand Down
26 changes: 13 additions & 13 deletions src/app/controllers/TinyG2/TinyG2Controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _ from 'lodash';
import SerialPort from 'serialport';
import log from '../../lib/log';
import Feeder from '../../lib/feeder';
import Sender, { STREAMING_PROTOCOL_SEND_RESPONSE } from '../../lib/gcode-sender';
import Sender, { SP_TYPE_SEND_RESPONSE } from '../../lib/sender';
import config from '../../services/configstore';
import monitor from '../../services/monitor';
import store from '../../store';
Expand Down Expand Up @@ -102,8 +102,8 @@ class TinyG2Controller {
});

// Sender
this.sender = new Sender(STREAMING_PROTOCOL_SEND_RESPONSE);
this.sender.on('gcode', (gcode = '') => {
this.sender = new Sender(SP_TYPE_SEND_RESPONSE);
this.sender.on('data', (gcode = '') => {
if (this.isClose()) {
log.error(`[TinyG2] The serial port "${this.options.port}" is not accessible`);
return;
Expand Down Expand Up @@ -177,9 +177,11 @@ class TinyG2Controller {
const prevPlannerQueueStatus = this.plannerQueueStatus;

if ((this.workflowState !== WORKFLOW_STATE_IDLE) && (statusCode !== 0)) {
const line = this.sender.lines[this.sender.received];
const { lines, received } = this.sender.state;
const line = lines[received];
const error = statusCode;
this.emitAll('serialport:read', `> ${line}`);
this.emitAll('serialport:read', `error=${statusCode}, line=${this.sender.received + 1}`);
this.emitAll('serialport:read', `error=${error}, line=${received + 1}`);
}

if (prevPlannerQueueStatus !== TINYG2_PLANNER_QUEUE_STATUS_BLOCKED) {
Expand Down Expand Up @@ -230,14 +232,12 @@ class TinyG2Controller {

// Feeder
if (this.feeder.peek()) {
this.emitAll('feeder:status', {
'size': this.feeder.queue.length
});
this.emitAll('feeder:status', this.feeder.toJSON());
}

// Sender
if (this.sender.peek()) {
this.emitAll('sender:status', this.sender.state);
this.emitAll('sender:status', this.sender.toJSON());
}

// TinyG2 state
Expand Down Expand Up @@ -377,8 +377,8 @@ class TinyG2Controller {
footer: this.tinyG2.footer
},
workflowState: this.workflowState,
feeder: this.feeder.state,
sender: this.sender.state
feeder: this.feeder.toJSON(),
sender: this.sender.toJSON()
};
}
reset() {
Expand Down Expand Up @@ -465,7 +465,7 @@ class TinyG2Controller {

if (this.sender) {
// Send sender status to a newly connected client
socket.emit('sender:status', this.sender.state);
socket.emit('sender:status', this.sender.toJSON());
}
}
removeConnection(socket) {
Expand Down Expand Up @@ -497,7 +497,7 @@ class TinyG2Controller {
return;
}

log.debug(`[TinyG2] Load G-code: name="${this.sender.name}", size=${this.sender.gcode.length}, total=${this.sender.total}`);
log.debug(`[TinyG2] Load G-code: name="${this.sender.state.name}", size=${this.sender.state.gcode.length}, total=${this.sender.state.total}`);

this.workflowState = WORKFLOW_STATE_IDLE;
callback(null, { name: name, gcode: gcode });
Expand Down
38 changes: 21 additions & 17 deletions src/app/lib/feeder.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,58 @@
import events from 'events';

class Feeder extends events.EventEmitter {
queue = [];
pending = false;
changed = false;
state = {
queue: [],
pending: false,
changed: false
};

constructor() {
super();

this.on('change', () => {
this.changed = true;
this.state.changed = true;
});
}
get state() {
toJSON() {
return {
queue: this.queue.length
queue: this.state.queue.length,
pending: this.state.pending,
changed: this.state.changed
};
}
feed(data) {
this.queue = this.queue.concat(data);
this.state.queue = this.state.queue.concat(data);
this.emit('change');
}
clear() {
this.queue = [];
this.pending = false;
this.state.queue = [];
this.state.pending = false;
this.emit('change');
}
size() {
return this.queue.length;
return this.state.queue.length;
}
next() {
if (this.queue.length === 0) {
this.pending = false;
if (this.state.queue.length === 0) {
this.state.pending = false;
return false;
}

const data = this.queue.shift();
this.pending = true;
const data = this.state.queue.shift();
this.state.pending = true;
this.emit('data', data);
this.emit('change');

return data;
}
isPending() {
return this.pending;
return this.state.pending;
}
// Returns true if any state have changes
peek() {
const changed = this.changed;
this.changed = false;
const changed = this.state.changed;
this.state.changed = false;
return changed;
}
}
Expand Down
Loading

0 comments on commit 7d4fa30

Please sign in to comment.