'use strict' import { ipcRenderer } from 'electron'; import SerialPort from 'serialport'; const serials = {}; const ids = ipcRenderer.sendSync('windowsid', 'already'); /* ************ Functions ************ */ /** * Parse a incoming a list of messages of ports, & divide into two parts, based * on connected boards. * @param {Array} list A list of messages of ports * @returns {Object} A object which contains two arrays */ function parsePorts(list) { let result = { boards: [], wifi: [] }; list.forEach(val => { let mf = val.manufacturer; if (mf) { // if (mf.indexOf('Arduino') > -1) // result.boards.push(val); if (mf.indexOf('ftdi') > -1) result.wifi.push(val); } }); return result; } /** * Handle error, & send error back to the previous process. * @param {Error} err Incoming error * @param {string} event Event name * @param {Array} data Data to send * @returns {void} void */ function errorHandler(err, event, sid = '', data = []) { ipcRenderer.sendTo(ids[0], 'error', err, event, sid, data); return; } /** * Handle list event & return a set of messages of connected boards. * @returns {void} void */ function listHandler() { SerialPort.list() .then(result => { let res = parsePorts(result); ipcRenderer.sendTo(ids[0], 'result_list', res); }) .catch(err => errorHandler(err, 'list')); return; } /** * Handle open command, & receive messages from board. * @param {string} sid Socket's id * @param {string} comName Name of port * @param {number} baudRate Number of baud rate * @returns {void} void */ function openHandler(e, sid, comName, baudRate = 9600) { const serial = new SerialPort(comName, { baudRate: baudRate }, err => { if (!err) { ipcRenderer.sendTo(ids[0], 'result_open', sid, comName, baudRate); serial.on('readable', () => { let str = serial.read(); str instanceof Buffer ? str = str.toString('utf-8') : ''; ipcRenderer.sendTo(ids[0], 'message', sid, str); }) serials[sid] = serial; } else errorHandler(err, 'open', sid); }); return; } /** * Handle close command, & close the communication. * @param {string} sid Socket's id * @returns {void} void */ function closeHandler(e, sid) { const serial = serials[sid]; if (serial && serial.isOpen) serial.close(err => { if (!err) { delete serials[sid]; ipcRenderer.sendTo(ids[0], 'result_close', sid) } else errorHandler(err, 'close', sid); return; }); } /** * Handle send command, & send a message to board. * @param {string} sid Socket's id * @param {string} msg Incoming message * @param {string} postfix Postfix of sending message * @returns {void} void */ function sendHandler(e, sid, msg, postfix = '') { const serial = serials[sid]; if (serial && serial.isOpen) { if (postfix === 'nl') postfix = '\n'; else if (postfix === 'cr') postfix = '\r'; else if (postfix === 'blc') postfix = '\n\r'; msg += postfix; serial.write(msg, 'utf-8', e => console.warn(e)); } return; } /** * Handle update command, & update the communication to a specific * baud rate. * @param {string} sid Socket's id * @param {number} baudRate Baud rate to update to * @returns {void} void */ function updateHandler(e, sid, baudRate) { const serial = serials[sid]; if (serial && serial.isOpen) { serial.update({ baudRate: baudRate }, err => { err ? errorHandler(err, 'update', sid, [baudRate]) : ipcRenderer.sendTo(ids[0], 'result_update', sid, baudRate); }); } return; } /** * Parse a incoming a list of messages of ports, & compare with list map, & * check if it's get new boards connected. * @param {Array} map An array with comNames * @returns {void} void */ function detectListChange(map) { SerialPort.list() .then(result => { let is_changed = false, comNames = [], res = { boards: [], wifi: [] }; result.forEach(val => { if (val.manufacturer) { if (val.manufacturer.toLocaleLowerCase().indexOf('ftdi') > -1) res.wifi.push(val); // else if (val.manufacturer.toLocaleLowerCase().indexOf('silicon') > -1) // res.wifi.push(val); comNames.push(val.comName); } }); if (comNames.length !== map.length) is_changed = true; else { for (let i = 0; i < comNames.length; i++) if (map.indexOf(comNames[i]) < 0) { is_changed = true; break; } } if (is_changed) { ipcRenderer.sendTo(ids[0], 'result_list', res); map.length = 0; comNames.forEach(val => { map.push(val); }); } }) .catch(err => errorHandler(err, 'list')); return; } /** * Run detectListChange function every 3 secs. * @returns {void} void */ function loopDetectListChange() { let listMap = []; setInterval(() => { detectListChange(listMap); }, 3000); } // ------ bind functions to ipcRenderer's events ------ // ipcRenderer.on('handle_list', listHandler); ipcRenderer.on('handle_open', openHandler); ipcRenderer.on('handle_close', closeHandler); ipcRenderer.on('handle_send', sendHandler); ipcRenderer.on('handle_update', updateHandler); ipcRenderer.on('disconnect', sid => { const serial = serials[sid]; serial ? delete serials[sid] : ''; return; }); loopDetectListChange();