Skip to content
This repository has been archived by the owner on Mar 23, 2021. It is now read-only.

Add port initialization and validation for SerialCommunicator #22

Open
wants to merge 1 commit into
base: GUIelectron
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions webgui/src/flipmouse/js/flipcomm.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function FlipMouse(initFinished) {
var _SLOT_CONSTANT = 'Slot:';
var _AT_CMD_BUSY_RESPONSE = 'BUSY';
var _AT_CMD_OK_RESPONSE = 'OK';
var _AT_CMD_MIN_WAITTIME_MS = 5000;
var _AT_CMD_MIN_WAITTIME_MS = 50;
var _timestampLastAtCmd = new Date().getTime();
var _atCmdQueue = [];
var _sendingAtCmds = false;
Expand Down Expand Up @@ -387,12 +387,12 @@ function FlipMouse(initFinished) {
if (userAgent.indexOf(' electron/') > -1) {
var promise = new Promise(function(resolve) {
_communicator = new SerialCommunicator();
resolve();
return;
_communicator.init().then(function () {
resolve();
});
});
} else {
var promise = new Promise(function(resolve) {

if(window.location.href.indexOf('mock') > -1) {
_communicator = new MockCommunicator();
resolve();
Expand Down
217 changes: 102 additions & 115 deletions webgui/src/flipmouse/js/sercomm.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
function SerialCommunicator() {
const SerialPort = require('serialport');
const Readline = require('@serialport/parser-readline')
const Delimiter = require('@serialport/parser-delimiter')
const parser = new Delimiter({ delimiter: '\r\n' })
const Readline = require('@serialport/parser-readline');
const Delimiter = require('@serialport/parser-delimiter');
const parser = new Delimiter({ delimiter: '\r\n' });

//serial port instance
var _port;
Expand All @@ -15,141 +15,129 @@ function SerialCommunicator() {
this.setValueHandler = function (handler) {
_valueHandler = handler;
};

function ping(port_name){
try {
const port = new SerialPort(port_name,{
baudRate: 115200,
parser: new SerialPort.parsers.Readline('\n')
});
port.on('open',function(){
port.write("AT ID \r\n");
data = port.read();
//TODO: test for valid id
console.log(i + data);
port.close();
});

return new Promise(resolve => port.on("close", resolve));
} catch(err) {
console.log("Not a valid port");
return new Promise(function (resolve, reject) {
reject();
});
}


}


this.connect = async function() {


let portname = await this.getValidPort();

serialport = "/dev/ttyACM0";


//})();

/*(async function() {
const portlist = await SerialPort.list();
let serialport = "";
for(const port of portlist) {
//open port
probePort = new SerialPort(port['comName'], {baudRate: 115200 })
probePort.pipe(parser);

//send data

//await for feedback

// if flipmouse -> set _port & return
}*/



//is port defined?

//attach parser to serial port
_port = new SerialPort(serialport, {
baudRate: 115200 })
_port.pipe(parser);
console.log("Found valid device @" + serialport);


//on a fully received line,
//check if the data is a reported raw value
//or returned data for a dedicated command (see sendData)
parser.on('data', function(data) {
console.log("data evt: " + data);
function isATCOM({ comName }, device = 'FABI v2.3') {
return new Promise((resolve, reject) => {
const port = new SerialPort(
comName,
{
baudRate: 115200,
parser: new SerialPort.parsers.Readline('\n')
},
function(error) {
if (!error) {
let found = false;
port.on('data', chunk => {
const msg = chunk.toString();
if (msg.startsWith(device)) {
found = true;
console.log(
`Found AT COM device at ${comName}`
);
port.close();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we use the parser event for a fully received line?
parser.on('data' ...

Copy link
Contributor Author

@sabicalija sabicalija Dec 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I didn't know about this possibility.

Sure. I think you're right. It's probably better to safeguard the communication/transmission somehow.

} else {
console.error(`No ${device} at ${comName}.`);
reject();
}
});
port.on('close', () => resolve(port));
port.write('AT ID \r\n');
setTimeout(() => {
if (!found) {
console.error(
`Serial device ${comName} is not responding.`
);
reject();
}
}, 2000); // Reject if serial port is not responding.
} else {
console.log(error.message);
reject();
}
}
);
});
}

if (data && data.toString().indexOf(C.LIVE_VALUE_CONSTANT) > -1) {
if (L.isFunction(_valueHandler)) {
_valueHandler(data.toString());
}
return;
}

if(_internalValueFunction) {
_internalValueFunction(data);
}
});
//})();
this.init = function() {
return SerialPort.list().then(function(ports, errors) {
const device = 'FABI v2.3'; // Proper AT COM device name
console.log(`Searching for ${device} ...`);
if (typeof errors === 'undefined') {
// race to (first) success, cf. https://stackoverflow.com/a/37235274/5728717
return Promise.all(
ports
.map(port => isATCOM(port, device))
.map(port => {
return port.then(
resolve => Promise.reject(resolve),
reject => Promise.resolve(reject)
);
})
)
.then(
resolve => Promise.reject(resolve),
reject => Promise.resolve(reject)
)
.then(port => {
_port = port;
return Promise.resolve();
})
.catch(() => {
// throw 'No AT command capabale COM port found.';
console.error('No AT command capabale COM port found.');
});
} else {
console.error(errors);
}
});
};

this.getValidPort = async function() {
const portlist = await SerialPort.list();
for(let i = 0; i<portlist.length; i++) {
await ping(portlist[i].comName);
}


this.getPorts = function() {
if(_port) {
var list = new Array();
_port.list().forEach( function(port) {
list.push(port['path'] + port['manufacturer']);
});
return list;
}
Comment on lines +97 to +104
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this block?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep

};


this.disconnect = function() {
if(_port) _port.close();
if(_port) _port.close();
_port = null;
};

this.sendData = function (value, timeout) {
const that = this;
(async function() {

if (!value) return;


if(!_port) await that.connect();

//if still no port exists, we cannot send data...
if(!_port) {
console.log("no ports found");
return new Promise(function(resolve) {
resolve("");
});
if (!value) return;
if (!_port) {
throw 'sercomm: port not initialized. call init() before sending data.';
}

//send data via serial port
_port.write(value, function(err) {
if (err) {
return console.log('Error on write: ', err.message)
return console.log('Error on write: ', err.message);
}
console.log('message written')
})
console.log('message written');
});
//add NL/CR (not needed on websockets)
_port.write('\r\n', function(err) {
if (err) {
return console.log('Error on write delimiter: ', err.message)
return console.log('Error on write delimiter: ', err.message);
}
console.log('message written')
})
console.log('message written');
});

var timeout = 3000;
//wait for a response to this command
//(there might be a timeout for commands with no response)
return new Promise(function(resolve) {
var result = '';
var timeoutHandler = setTimeout(function () {
console.log("timeout von command: " + value);
console.log("timeout of command: " + value);
resolve(result);
}, timeout);
_internalValueFunction = function(data) {
Expand All @@ -160,8 +148,7 @@ function SerialCommunicator() {
resolve(result);
_internalValueFunction = null;
}, 50);
}
};
});
})();
};
}