@point-of-sale/receipt-printer-status
Version:
This is an library that allows you to get the status information back from StarPRNT and ESC/POS printers.
3 lines (2 loc) • 9.61 kB
JavaScript
class EventEmitter{constructor(e){this._events={}}on(e,t){this._events[e]=this._events[e]||[],this._events[e].push(t)}emit(e,...t){let i=this._events[e];i&&i.forEach((e=>{setTimeout((()=>e(...t)),0)}))}}class ResponseBuffer{window=0;cursor=0;data=new Uint8Array(2048);add(e){this.cursor==this.window&&(this.cursor=this.window=0),this.data.set(new Uint8Array(e.buffer),this.window),this.window+=e.byteLength}get(e,t){return e||(e=0),t?this.data.subarray(e+this.cursor,t+this.cursor):this.data[e+this.cursor]}getWord(e){return this.data[e+this.cursor]|this.data[e+this.cursor+1]<<8}getBit(e,t){return this.data[e+this.cursor]>>t&1}getBits(e,t){"string"==typeof e&&(t=e,e=0);let i=t.split("").map(((e,t)=>[7-t,"."!=e?parseInt(e,10):null])).filter((e=>null!==e[1])),s=0;for(let t of i)s|=this.getBit(e,t[0])<<t[1];return s}scanUntilLineFeedNul(e){let t,i=!1;for(t=this.cursor;t<e;t++)if(10==this.data[t-1]&&0==this.data[t]){i=!0,t++;break}return i?t-this.cursor:null}scanUntilNul(e){let t,i=!1;for(t=this.cursor;t<e;t++)if(0==this.data[t]){i=!0,t++;break}return i?t-this.cursor:null}checkBit(e,t,i){return(this.data[e+this.cursor]>>t&1)===i}checkBits(e,t){"string"==typeof e&&(t=e,e=0),"string"==typeof t&&(t=t.split("").map(((e,t,i)=>[i.length-t-1,parseInt(e)])).filter((e=>!isNaN(e[1]))));for(let i of t)if(!this.checkBit(e,i[0],i[1]))return!1;return!0}checkSequence(e,t){e instanceof Array&&(t=e,e=0);for(let i=0;i<t.length;i++)if(this.data[e+this.cursor+i]!=t[i])return!1;return!0}get length(){return this.window-this.cursor}}class ChangeObserver{static create(e){let t=e.callback,i=e.target;return new Proxy(i,{get:(e,t,i)=>"target"===t?e:Reflect.get(e,t,i),set:(e,i,s)=>(e[i]!==s&&(e[i]=s,t(e)),!0)})}}class ReceiptPrinterInfo{buttonPressed=!1;online=!0;coverOpened=!1;paperLoaded=!0;paperLow=!1}class ReceiptPrinterBarcodeScanner{#e;#t;#i=!1;#s=!1;constructor(e){this.#e=e,this.#t=new EventEmitter,"star-prnt"==this.#e._language&&(this.#s=!0)}get supported(){return this.#s}get connected(){return this.#i}set connected(e){!this.#i&&e&&this.#t.emit("connected"),this.#i=e,this.#s=!0}set barcode(e){this.#t.emit("barcode",{value:e})}addEventListener(e,t){this.#t.on(e,t)}}class ReceiptPrinterCashDrawer{#e;#t;#n=!1;constructor(e){this.#e=e,this.#t=new EventEmitter}open(){this.#e.connected&&("esc-pos"==this.#e.language&&this.#e.send([27,112,0,25,250]),"star-prnt"!=this.#e.language&&"star-line"!=this.#e.language||this.#e.send([27,7,20,20,7]))}get supported(){return!0}get opened(){return this.#n}set opened(e){e!==this.#n&&(this.#t.emit("update",{opened:e}),e?this.#t.emit("open"):this.#t.emit("close")),this.#n=e}addEventListener(e,t){this.#t.on(e,t)}}class ReceiptPrinterStatus{constructor(e){if(this._connected=!1,e.language=e.language||"auto",void 0===e.printer)throw new Error("You need to provide a printer driver instance");if("ReceiptPrinterDriver"==Object.getPrototypeOf(e.printer).constructor.name)throw new Error("Printer driver not supported by this library");if(!["esc-pos","star-prnt","star-line","auto"].includes(e.language))throw new Error("Language not supported by this library");this._language=e.language,this._parsing=!1,this._polling=null,this._updates=0,this._pollForUpdates=!1,this._pollForBarcodes=!1,this._internal={emitter:new EventEmitter,decoder:new TextDecoder,buffer:new ResponseBuffer,status:ChangeObserver.create({target:new ReceiptPrinterInfo,callback:e=>{this._internal.emitter.emit("update",e)}}),printer:e.printer,language:e.language,polling:e.polling||"auto",callback:()=>{},response:()=>new Promise((e=>{this._internal.callback=e}))},this.barcodeScanner=new ReceiptPrinterBarcodeScanner(this),this.cashDrawer=new ReceiptPrinterCashDrawer(this),this.initialize()}async initialize(){this._internal.printer.addEventListener("data",(e=>this.receive(e))),await this._internal.printer.listen()?(this._internal.printer.addEventListener("disconnected",(()=>{this._polling&&clearInterval(this._polling),this._connected=!1,this._internal.emitter.emit("disconnected")})),"auto"==this._language&&this.initializeUnknownPrinter(),"star-line"!=this._language&&"star-prnt"!=this._language||this.initializeStarPrinter(),"esc-pos"==this._language&&this.initializeEscPosPrinter(),setTimeout((()=>{this._connected||this._internal.emitter.emit("unsupported")}),1500)):this._internal.emitter.emit("unsupported")}initializeUnknownPrinter(){this.send([27,6,1]),this.send([16,4,1])}initializeStarPrinter(){"star-line"!=this._language&&"star-prnt"!=this._language||this.send([27,6,1]),"auto"==this._internal.polling&&setTimeout((()=>{1==this._updates&&(this._pollForUpdates=!0,this.poll())}),1e3),!0===this._internal.polling&&(this._pollForUpdates=!0,this.poll())}initializeEscPosPrinter(){this.send([29,97,79]),this.send([16,20,7,1]),!0===this._internal.polling&&(this._pollForUpdates=!0,this.poll())}async query(e){let t,i,s;if(await new Promise((e=>{setTimeout(e,10)})),"star-prnt"==this._language||"star-line"==this._language)switch(e){case"manufacturer":t="Star";break;case"model":if(this.send([27,35,42,10,0]),i=await this._internal.response(),s=i.match(/^(.*)Ver[0-9\.]+$/),s&&(t=s[1],"POP10"===t))t="mPOP";break;case"firmware":this.send([27,35,42,10,0]),t=await this._internal.response()}if("star-prnt"==this._language)switch(e){case"serialnumber":this.send([27,29,41,73,1,0,49]),i=await this._internal.response(),s=i.match(/PrSrN=([0-9]+)[,$]/),s&&(t=s[1]);break;case"fonts":this.send([27,29,41,73,3,0,48,0,0]),i=await this._internal.response(),t=i.split(",").filter((e=>e));break;case"interfaces":this.send([27,29,41,73,3,0,51,0,0]),t=await this._internal.response()}if("esc-pos"==this._language)switch(e){case"firmware":this.send([29,73,65]),t=await this._internal.response();break;case"manufacturer":this.send([29,73,66]),t=await this._internal.response();break;case"model":this.send([29,73,67]),t=await this._internal.response();break;case"serialnumber":this.send([29,73,68]),t=await this._internal.response();break;case"fonts":this.send([29,73,69]);let e=await this._internal.response();t=e?[e]:[]}return t}send(e){this._internal.printer.print(new Uint8Array(e))}receive(e){this._internal.buffer.add(e),this.parseResponse()}connect(){!1===this._connected&&(this._connected=!0,this._internal.emitter.emit("connected"))}poll(){this._polling||(this._polling=setInterval((()=>{this._connected&&("star-prnt"==this._language&&(this._pollForBarcodes&&this.send([27,29,66,50]),this._pollForUpdates&&this.send([27,6,1])),"star-line"==this._language&&this._pollForUpdates&&this.send([27,6,1]),"esc-pos"==this._language&&this._pollForUpdates&&this.send([29,97,79]))}),500))}parseResponse(){if(!this._parsing){for(this._parsing=!0;this._internal.buffer.length;){let e=1;if("auto"==this._language&&(this._language=this.detectLanguage(this._internal.buffer)),"star-line"!=this._language&&"star-prnt"!=this._language||(e=this.parseStarResponse(this._internal.buffer)),"esc-pos"==this._language&&(e=this.parseEscPosResponse(this._internal.buffer)),0==e)break;this._internal.buffer.cursor+=e}this._parsing=!1}}detectLanguage(e){return e.checkBits("0..1..10")?(this.initializeEscPosPrinter(),"esc-pos"):e.checkBits("0..0...1")?(this.initializeStarPrinter(),"star-prnt"):"unknown"}parseEscPosResponse(e){let t=0,{window:i,length:s}=e;if(s>=4&&e.checkBits("0..1..00"))this._internal.status.online=e.checkBits("....0..."),this._internal.status.coverOpened=e.checkBits("..1....."),this._internal.status.buttonPressed=e.checkBits(".1......"),this._internal.status.paperLoaded=e.checkBits(2,"....00.."),this._internal.status.paperLow=e.checkBits(2,"......11"),this.cashDrawer.opened=e.checkBits(".....0.."),this._updates++,this.connect(),t=4;else if(s>=1&&e.checkBits("0..1..10"))this._internal.status.online=e.checkBits("....0..."),this._internal.status.buttonPressed=e.checkBits(".1......"),this.cashDrawer.opened=e.checkBits(".....0.."),t=1;else if(s>=2&&95==e.get()){let s=e.scanUntilNul(i);if(null!==s){let i=e.get(1,s-1);this._internal.callback(this._internal.decoder.decode(i)),t=s}}else t=1;return t}parseStarResponse(e){let t=0,{window:i,length:s}=e;if(e.checkBits("0..0...1")){let i=e.getBits("..3.210.");if(s>=i){if(0==this._updates){let t=e.getBits(1,"..3.210.");this._language=t>=4?"star-prnt":"star-line","star-prnt"==this._language&&this.send([27,29,66,49])}this._internal.status.online=e.checkBits(2,"....0..."),this._internal.status.coverOpened=e.checkBits(2,"..1....."),this._internal.status.buttonPressed=e.checkBits(2,".1......"),this._internal.status.paperLoaded=e.checkBits(5,"....0..."),this.cashDrawer.opened=e.checkBits(2,".....1.."),this._updates++,this.connect(),t=i}}else if(s>=7&&e.checkSequence([27,35,42,44])){let s=e.scanUntilLineFeedNul(i);if(null!==s){let i=e.get(4,s-2);this._internal.callback(this._internal.decoder.decode(i)),t=s}}else if(s>=9&&e.checkSequence([27,29,41,73])){let s=e.scanUntilLineFeedNul(i);if(null!==s){let i=e.getWord(4),n=e.get(6+i,s-2);this._internal.callback(this._internal.decoder.decode(n)),t=s}}else if(s>=5&&e.checkSequence([27,29,66,49]))2&e.get(4)&&(this.barcodeScanner.connected=!0,this._pollForBarcodes=!0,this.poll()),t=5;else if(s>=5&&e.checkSequence([27,29,66,50])){let i=e.getWord(4);if(i>0){let t=e.get(6,6+i-1);this._internal.decoder.decode(t).split("\r").forEach((e=>{""!=(e=e.trim())&&(this.barcodeScanner.barcode=e)}))}t=6+i}else t=27==e.get()?0:1;return t}addEventListener(e,t){this._internal.emitter.on(e,t)}get status(){return this._internal.status.target}get connected(){return this._connected}get language(){return this._language}}export{ReceiptPrinterStatus as default};
//# sourceMappingURL=receipt-printer-status.esm.js.map