From a64e746b186c5d59d84876deb380cab36dad3b92 Mon Sep 17 00:00:00 2001 From: DarkFrost Date: Thu, 13 May 2021 11:35:43 -0400 Subject: [PATCH 1/5] fix multi autoconnect problem --- src/pos.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/pos.js b/src/pos.js index a7aec96..2f55202 100644 --- a/src/pos.js +++ b/src/pos.js @@ -16,6 +16,7 @@ module.exports = class POS { this.port = null this.responseAsString = true this.waiting = false + this.connecting = false; this.responseCallback = function () { } @@ -77,7 +78,14 @@ module.exports = class POS { connect(portName = null, baudRate = 115200) { this.debug("Connecting to " + portName + " @" + baudRate) + return new Promise((resolve, reject) => { + // Block so just one connect command can be sent at a time + if (this.connecting === true) { + reject("Another connect command was already sent and it is still waiting") + return + } + if (this.connected) { this.debug("Trying to connect to a port while its already connected. Disconnecting... ") this.disconnect().then(() => { @@ -85,9 +93,12 @@ module.exports = class POS { }).catch(() => { resolve(this.connect(portName, baudRate)) }) + this.connecting = true return } + this.connecting = true + this.port = new SerialPort(portName, { baudRate, autoOpen: false }) this.port.open((err) => { @@ -130,7 +141,7 @@ module.exports = class POS { this.waiting = false this.currentPort = null try { - await this.port.close(); + if(this.port.isOpen) await this.port.close(); } catch (e) { } @@ -145,11 +156,19 @@ module.exports = class POS { this.waiting = false this.connected = false }) + + this.connecting = false }) } disconnect() { return new Promise((resolve, reject) => { + + if(!this.port.isOpen) { + resolve(true) + return + } + this.port.close((error) => { if (error) { this.debug("Error closing port", error) @@ -165,6 +184,12 @@ module.exports = class POS { } async autoconnect() { + // Block so just one autoconnect command can be sent at a time + if (this.connecting === true) { + this.debug("It is already trying to connect to a port and we wait for it to finish") + return false + } + let vendors = [ { vendor: "11ca", product: "0222" }, // Verifone VX520c { vendor: "0b00", product: "0054" }, // Ingenico 3500 @@ -184,12 +209,14 @@ module.exports = class POS { this.debug("Trying to connect to " + port.path) try { await this.connect(port.path) + this.connecting = false; return port } catch (e) { console.log(e); } } + this.connecting = false; this.debug("Autoconnection failed") return false } From 8d92d301525a6a811cbf7ec1d0da81f959b68904 Mon Sep 17 00:00:00 2001 From: DarkFrost Date: Thu, 13 May 2021 18:21:51 -0400 Subject: [PATCH 2/5] add port_opened and port_closed event --- src/pos.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pos.js b/src/pos.js index 2f55202..e1e2967 100644 --- a/src/pos.js +++ b/src/pos.js @@ -1,13 +1,15 @@ const LRC = require("lrc-calculator") const SerialPort = require("serialport") +const EventEmitter = require('events'); const InterByteTimeout = require("@serialport/parser-inter-byte-timeout") const responseMessages = require("./responseCodes") const ACK = 0x06 const FUNCTION_CODE_MULTICODE_SALE = '0271'; -module.exports = class POS { +module.exports = class POS extends EventEmitter { constructor() { + super() this.currentPort = null this.connected = false @@ -111,7 +113,9 @@ module.exports = class POS { this.parser.on("data", (data) => { let prettyData = '' - data.forEach(char=>{prettyData += (32 <= char && char<126) ? String.fromCharCode(char) : `{0x${char.toString(16).padStart(2, '0')}}`}, '') + data.forEach(char=>{ + prettyData += (32 <= char && char<126) ? String.fromCharCode(char) : `{0x${char.toString(16).padStart(2, '0')}}` + }, '') this.debug(`🤖 > ${prettyData}`, data) // Primero, se recibe un ACK @@ -135,6 +139,7 @@ module.exports = class POS { this.connected = true this.poll().then(() => { this.currentPort = portName + this.emit('port_opened', this.currentPort); resolve(true) }).catch(async (e) => { this.connected = false @@ -155,6 +160,7 @@ module.exports = class POS { this.currentPort = null this.waiting = false this.connected = false + this.emit('port_closed'); }) this.connecting = false @@ -174,7 +180,7 @@ module.exports = class POS { this.debug("Error closing port", error) reject(error) } else { - this.debug("Port closed sucessfully") + this.debug("Port closed successfully") resolve(true); } }) @@ -192,7 +198,7 @@ module.exports = class POS { let vendors = [ { vendor: "11ca", product: "0222" }, // Verifone VX520c - { vendor: "0b00", product: "0054" }, // Ingenico 3500 + { vendor: "0b00", product: "0054" }, // Ingenico DESK3500 ] let availablePorts = await this.listPorts() From 729cb07eb0e51a413888b71c881a7d8be4e08aea Mon Sep 17 00:00:00 2001 From: DarkFrost Date: Thu, 20 May 2021 11:03:18 -0400 Subject: [PATCH 3/5] add response timeout for POS --- src/pos.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/pos.js b/src/pos.js index e1e2967..d9042be 100644 --- a/src/pos.js +++ b/src/pos.js @@ -14,6 +14,7 @@ module.exports = class POS extends EventEmitter { this.connected = false this.ackTimeout = 2000 + this.posTimeout = 150000 this.debugEnabled = false this.port = null this.responseAsString = true @@ -243,6 +244,7 @@ module.exports = class POS extends EventEmitter { // Assert the ack arrives before the given timeout. let timeout = setTimeout(() => { this.waiting = false + clearTimeout(responseTimeout) reject("ACK has not been received in " + this.ackTimeout + " ms.") }, this.ackTimeout) @@ -269,8 +271,14 @@ module.exports = class POS extends EventEmitter { } }) + let responseTimeout = setTimeout(() => { + this.waiting = false + reject(`Response of POS has not been received in ${this.posTimeout/1000} seconds`) + }, this.posTimeout) + // Wait for the response and fullfill the Promise this.responseCallback = (data) => { + clearTimeout(responseTimeout) let response = data if (this.responseAsString) { response = data.toString().slice(1, -2) From 90d43a198f17c4e74a6ff8bdd59bcf2eec0e0822 Mon Sep 17 00:00:00 2001 From: DarkFrost Date: Thu, 20 May 2021 11:05:19 -0400 Subject: [PATCH 4/5] add protection for the param printOnPos --- src/pos.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pos.js b/src/pos.js index d9042be..dfa11af 100644 --- a/src/pos.js +++ b/src/pos.js @@ -374,6 +374,15 @@ module.exports = class POS extends EventEmitter { salesDetail(printOnPos = false) { return new Promise((resolve) => { + + if(typeof printOnPos !== 'boolean' && typeof printOnPos !== 'string') + return new Promise((resolve, reject) => { + reject("printOnPos must be of type boolean.") + }) + + if(typeof printOnPos === 'string') + printOnPos = (printOnPos === 'true' || printOnPos === '1') ? true:false + let print = printOnPos ? "0":"1" let sales = [] From bbfe5ba57ee8ba15615eae7a6267d5e305ede9b3 Mon Sep 17 00:00:00 2001 From: DarkFrost Date: Thu, 20 May 2021 16:25:56 -0400 Subject: [PATCH 5/5] change intermediate response, now is an object --- src/pos.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/pos.js b/src/pos.js index dfa11af..1fa6ba8 100644 --- a/src/pos.js +++ b/src/pos.js @@ -284,15 +284,17 @@ module.exports = class POS extends EventEmitter { response = data.toString().slice(1, -2) } let functionCode = data.toString().slice(1, 5) - if (functionCode==="0900") { // Sale status messages - if (typeof callback==="function") { - callback(response, data) - } - return - } + if (typeof callback==="function") { - callback(response, data) + if (functionCode==="0900") { // Sale status messages + callback(this.intermediateResponse(response), data) + return + } + + if (functionCode==="0261") + callback(response, data) } + this.waiting = false resolve(response, data) @@ -519,4 +521,14 @@ module.exports = class POS extends EventEmitter { } return response; } + + intermediateResponse(payload) { + let chunks = payload.split("|") + let response = { + responseCode: parseInt(chunks[1]), + responseMessage: this.getResponseMessage(parseInt(chunks[1])), + } + + return response; + } }