Initial commit
This commit is contained in:
971
.config.nodes.json
Normal file
971
.config.nodes.json
Normal file
@@ -0,0 +1,971 @@
|
|||||||
|
{
|
||||||
|
"node-red": {
|
||||||
|
"name": "node-red",
|
||||||
|
"version": "4.1.1",
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"nodes": {
|
||||||
|
"junction": {
|
||||||
|
"name": "junction",
|
||||||
|
"types": [
|
||||||
|
"junction"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/05-junction.js"
|
||||||
|
},
|
||||||
|
"inject": {
|
||||||
|
"name": "inject",
|
||||||
|
"types": [
|
||||||
|
"inject"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/20-inject.js"
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"name": "debug",
|
||||||
|
"types": [
|
||||||
|
"debug"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/21-debug.js"
|
||||||
|
},
|
||||||
|
"complete": {
|
||||||
|
"name": "complete",
|
||||||
|
"types": [
|
||||||
|
"complete"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/24-complete.js"
|
||||||
|
},
|
||||||
|
"catch": {
|
||||||
|
"name": "catch",
|
||||||
|
"types": [
|
||||||
|
"catch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/25-catch.js"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"types": [
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/25-status.js"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"name": "link",
|
||||||
|
"types": [
|
||||||
|
"link in",
|
||||||
|
"link out",
|
||||||
|
"link call"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/60-link.js"
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"name": "comment",
|
||||||
|
"types": [
|
||||||
|
"comment"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/90-comment.js"
|
||||||
|
},
|
||||||
|
"global-config": {
|
||||||
|
"name": "global-config",
|
||||||
|
"types": [
|
||||||
|
"global-config"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/91-global-config.js"
|
||||||
|
},
|
||||||
|
"unknown": {
|
||||||
|
"name": "unknown",
|
||||||
|
"types": [
|
||||||
|
"unknown"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/98-unknown.js"
|
||||||
|
},
|
||||||
|
"function": {
|
||||||
|
"name": "function",
|
||||||
|
"types": [
|
||||||
|
"function"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/10-function.js"
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"name": "switch",
|
||||||
|
"types": [
|
||||||
|
"switch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/10-switch.js"
|
||||||
|
},
|
||||||
|
"change": {
|
||||||
|
"name": "change",
|
||||||
|
"types": [
|
||||||
|
"change"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/15-change.js"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"name": "range",
|
||||||
|
"types": [
|
||||||
|
"range"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/16-range.js"
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"name": "template",
|
||||||
|
"types": [
|
||||||
|
"template"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/80-template.js"
|
||||||
|
},
|
||||||
|
"delay": {
|
||||||
|
"name": "delay",
|
||||||
|
"types": [
|
||||||
|
"delay"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/89-delay.js"
|
||||||
|
},
|
||||||
|
"trigger": {
|
||||||
|
"name": "trigger",
|
||||||
|
"types": [
|
||||||
|
"trigger"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/89-trigger.js"
|
||||||
|
},
|
||||||
|
"exec": {
|
||||||
|
"name": "exec",
|
||||||
|
"types": [
|
||||||
|
"exec"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/90-exec.js"
|
||||||
|
},
|
||||||
|
"rbe": {
|
||||||
|
"name": "rbe",
|
||||||
|
"types": [
|
||||||
|
"rbe"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/rbe.js"
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"name": "tls",
|
||||||
|
"types": [
|
||||||
|
"tls-config"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/05-tls.js"
|
||||||
|
},
|
||||||
|
"httpproxy": {
|
||||||
|
"name": "httpproxy",
|
||||||
|
"types": [
|
||||||
|
"http proxy"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/06-httpproxy.js"
|
||||||
|
},
|
||||||
|
"mqtt": {
|
||||||
|
"name": "mqtt",
|
||||||
|
"types": [
|
||||||
|
"mqtt in",
|
||||||
|
"mqtt out",
|
||||||
|
"mqtt-broker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/10-mqtt.js"
|
||||||
|
},
|
||||||
|
"httpin": {
|
||||||
|
"name": "httpin",
|
||||||
|
"types": [
|
||||||
|
"http in",
|
||||||
|
"http response"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/21-httpin.js"
|
||||||
|
},
|
||||||
|
"httprequest": {
|
||||||
|
"name": "httprequest",
|
||||||
|
"types": [
|
||||||
|
"http request"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/21-httprequest.js"
|
||||||
|
},
|
||||||
|
"websocket": {
|
||||||
|
"name": "websocket",
|
||||||
|
"types": [
|
||||||
|
"websocket in",
|
||||||
|
"websocket out",
|
||||||
|
"websocket-listener",
|
||||||
|
"websocket-client"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/22-websocket.js"
|
||||||
|
},
|
||||||
|
"tcpin": {
|
||||||
|
"name": "tcpin",
|
||||||
|
"types": [
|
||||||
|
"tcp in",
|
||||||
|
"tcp out",
|
||||||
|
"tcp request"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/31-tcpin.js"
|
||||||
|
},
|
||||||
|
"udp": {
|
||||||
|
"name": "udp",
|
||||||
|
"types": [
|
||||||
|
"udp in",
|
||||||
|
"udp out"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/32-udp.js"
|
||||||
|
},
|
||||||
|
"CSV": {
|
||||||
|
"name": "CSV",
|
||||||
|
"types": [
|
||||||
|
"csv"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-CSV.js"
|
||||||
|
},
|
||||||
|
"HTML": {
|
||||||
|
"name": "HTML",
|
||||||
|
"types": [
|
||||||
|
"html"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-HTML.js"
|
||||||
|
},
|
||||||
|
"JSON": {
|
||||||
|
"name": "JSON",
|
||||||
|
"types": [
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-JSON.js"
|
||||||
|
},
|
||||||
|
"XML": {
|
||||||
|
"name": "XML",
|
||||||
|
"types": [
|
||||||
|
"xml"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-XML.js"
|
||||||
|
},
|
||||||
|
"YAML": {
|
||||||
|
"name": "YAML",
|
||||||
|
"types": [
|
||||||
|
"yaml"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-YAML.js"
|
||||||
|
},
|
||||||
|
"split": {
|
||||||
|
"name": "split",
|
||||||
|
"types": [
|
||||||
|
"split",
|
||||||
|
"join"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/sequence/17-split.js"
|
||||||
|
},
|
||||||
|
"sort": {
|
||||||
|
"name": "sort",
|
||||||
|
"types": [
|
||||||
|
"sort"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/sequence/18-sort.js"
|
||||||
|
},
|
||||||
|
"batch": {
|
||||||
|
"name": "batch",
|
||||||
|
"types": [
|
||||||
|
"batch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/sequence/19-batch.js"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"types": [
|
||||||
|
"file",
|
||||||
|
"file in"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/storage/10-file.js"
|
||||||
|
},
|
||||||
|
"watch": {
|
||||||
|
"name": "watch",
|
||||||
|
"types": [
|
||||||
|
"watch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/storage/23-watch.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-buffer-parser": {
|
||||||
|
"name": "node-red-contrib-buffer-parser",
|
||||||
|
"version": "3.2.2",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"buffer-parser": {
|
||||||
|
"name": "buffer-parser",
|
||||||
|
"types": [
|
||||||
|
"buffer-parser"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-buffer-parser",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-buffer-parser/buffer-parser.js"
|
||||||
|
},
|
||||||
|
"buffer-maker": {
|
||||||
|
"name": "buffer-maker",
|
||||||
|
"types": [
|
||||||
|
"buffer-maker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-buffer-parser",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-buffer-parser/buffer-maker.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-play-audio": {
|
||||||
|
"name": "node-red-contrib-play-audio",
|
||||||
|
"version": "2.5.0",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"play-audio": {
|
||||||
|
"name": "play-audio",
|
||||||
|
"types": [
|
||||||
|
"play audio"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-play-audio",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-play-audio/play-audio.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-pi-gpio": {
|
||||||
|
"name": "node-red-node-pi-gpio",
|
||||||
|
"version": "2.0.6",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"rpi-gpio": {
|
||||||
|
"name": "rpi-gpio",
|
||||||
|
"types": [
|
||||||
|
"rpi-gpio in",
|
||||||
|
"rpi-gpio out",
|
||||||
|
"rpi-mouse",
|
||||||
|
"rpi-keyboard"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-pi-gpio",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-pi-gpio/36-rpi-gpio.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-ping": {
|
||||||
|
"name": "node-red-node-ping",
|
||||||
|
"version": "0.3.3",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"ping": {
|
||||||
|
"name": "ping",
|
||||||
|
"types": [
|
||||||
|
"ping"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-ping",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-ping/88-ping.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-random": {
|
||||||
|
"name": "node-red-node-random",
|
||||||
|
"version": "0.4.1",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"random": {
|
||||||
|
"name": "random",
|
||||||
|
"types": [
|
||||||
|
"random"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-random",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-random/random.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-serialport": {
|
||||||
|
"name": "node-red-node-serialport",
|
||||||
|
"version": "2.0.3",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"serialport": {
|
||||||
|
"name": "serialport",
|
||||||
|
"types": [
|
||||||
|
"serial in",
|
||||||
|
"serial out",
|
||||||
|
"serial request",
|
||||||
|
"serial-port",
|
||||||
|
"serial control"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-serialport",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-serialport/25-serial.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-smooth": {
|
||||||
|
"name": "node-red-node-smooth",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"smooth": {
|
||||||
|
"name": "smooth",
|
||||||
|
"types": [
|
||||||
|
"smooth"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-smooth",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-smooth/17-smooth.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-dashboard": {
|
||||||
|
"name": "node-red-dashboard",
|
||||||
|
"version": "3.6.6",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"ui_base": {
|
||||||
|
"name": "ui_base",
|
||||||
|
"types": [
|
||||||
|
"ui_base"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_base.js"
|
||||||
|
},
|
||||||
|
"ui_button": {
|
||||||
|
"name": "ui_button",
|
||||||
|
"types": [
|
||||||
|
"ui_button"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_button.js"
|
||||||
|
},
|
||||||
|
"ui_dropdown": {
|
||||||
|
"name": "ui_dropdown",
|
||||||
|
"types": [
|
||||||
|
"ui_dropdown"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_dropdown.js"
|
||||||
|
},
|
||||||
|
"ui_switch": {
|
||||||
|
"name": "ui_switch",
|
||||||
|
"types": [
|
||||||
|
"ui_switch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_switch.js"
|
||||||
|
},
|
||||||
|
"ui_slider": {
|
||||||
|
"name": "ui_slider",
|
||||||
|
"types": [
|
||||||
|
"ui_slider"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_slider.js"
|
||||||
|
},
|
||||||
|
"ui_numeric": {
|
||||||
|
"name": "ui_numeric",
|
||||||
|
"types": [
|
||||||
|
"ui_numeric"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_numeric.js"
|
||||||
|
},
|
||||||
|
"ui_text_input": {
|
||||||
|
"name": "ui_text_input",
|
||||||
|
"types": [
|
||||||
|
"ui_text_input"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_text_input.js"
|
||||||
|
},
|
||||||
|
"ui_date_picker": {
|
||||||
|
"name": "ui_date_picker",
|
||||||
|
"types": [
|
||||||
|
"ui_date_picker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_date_picker.js"
|
||||||
|
},
|
||||||
|
"ui_colour_picker": {
|
||||||
|
"name": "ui_colour_picker",
|
||||||
|
"types": [
|
||||||
|
"ui_colour_picker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_colour_picker.js"
|
||||||
|
},
|
||||||
|
"ui_form": {
|
||||||
|
"name": "ui_form",
|
||||||
|
"types": [
|
||||||
|
"ui_form"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_form.js"
|
||||||
|
},
|
||||||
|
"ui_text": {
|
||||||
|
"name": "ui_text",
|
||||||
|
"types": [
|
||||||
|
"ui_text"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_text.js"
|
||||||
|
},
|
||||||
|
"ui_gauge": {
|
||||||
|
"name": "ui_gauge",
|
||||||
|
"types": [
|
||||||
|
"ui_gauge"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_gauge.js"
|
||||||
|
},
|
||||||
|
"ui_chart": {
|
||||||
|
"name": "ui_chart",
|
||||||
|
"types": [
|
||||||
|
"ui_chart"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_chart.js"
|
||||||
|
},
|
||||||
|
"ui_audio": {
|
||||||
|
"name": "ui_audio",
|
||||||
|
"types": [
|
||||||
|
"ui_audio"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_audio.js"
|
||||||
|
},
|
||||||
|
"ui_toast": {
|
||||||
|
"name": "ui_toast",
|
||||||
|
"types": [
|
||||||
|
"ui_toast"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_toast.js"
|
||||||
|
},
|
||||||
|
"ui_ui_control": {
|
||||||
|
"name": "ui_ui_control",
|
||||||
|
"types": [
|
||||||
|
"ui_ui_control"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_ui_control.js"
|
||||||
|
},
|
||||||
|
"ui_template": {
|
||||||
|
"name": "ui_template",
|
||||||
|
"types": [
|
||||||
|
"ui_template"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_template.js"
|
||||||
|
},
|
||||||
|
"ui_link": {
|
||||||
|
"name": "ui_link",
|
||||||
|
"types": [
|
||||||
|
"ui_link"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_link.js"
|
||||||
|
},
|
||||||
|
"ui_tab": {
|
||||||
|
"name": "ui_tab",
|
||||||
|
"types": [
|
||||||
|
"ui_tab"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_tab.js"
|
||||||
|
},
|
||||||
|
"ui_group": {
|
||||||
|
"name": "ui_group",
|
||||||
|
"types": [
|
||||||
|
"ui_group"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_group.js"
|
||||||
|
},
|
||||||
|
"ui_spacer": {
|
||||||
|
"name": "ui_spacer",
|
||||||
|
"types": [
|
||||||
|
"ui_spacer"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_spacer.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-mysql": {
|
||||||
|
"name": "node-red-node-mysql",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"mysql": {
|
||||||
|
"name": "mysql",
|
||||||
|
"types": [
|
||||||
|
"MySQLdatabase",
|
||||||
|
"mysql"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-mysql",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-mysql/68-mysql.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-excel": {
|
||||||
|
"name": "node-red-contrib-excel",
|
||||||
|
"version": "0.0.3",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"xlsx": {
|
||||||
|
"name": "xlsx",
|
||||||
|
"types": [
|
||||||
|
"excel"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-excel",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-excel/excel/excel.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-browser-utils": {
|
||||||
|
"name": "node-red-contrib-browser-utils",
|
||||||
|
"version": "0.0.11",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"fileinject": {
|
||||||
|
"name": "fileinject",
|
||||||
|
"types": [
|
||||||
|
"fileinject"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-browser-utils",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-browser-utils/fileinject/fileinject.js"
|
||||||
|
},
|
||||||
|
"microphone": {
|
||||||
|
"name": "microphone",
|
||||||
|
"types": [
|
||||||
|
"microphone"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-browser-utils",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-browser-utils/microphone/microphone.js"
|
||||||
|
},
|
||||||
|
"camera": {
|
||||||
|
"name": "camera",
|
||||||
|
"types": [
|
||||||
|
"camera"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-browser-utils",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-browser-utils/camera/camera.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-xlsx-to-json": {
|
||||||
|
"name": "node-red-contrib-xlsx-to-json",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"xlsxtojson": {
|
||||||
|
"name": "xlsxtojson",
|
||||||
|
"types": [
|
||||||
|
"XLSX-to-json"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-xlsx-to-json",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-xlsx-to-json/xlsx-to-json.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-spreadsheet-in": {
|
||||||
|
"name": "node-red-contrib-spreadsheet-in",
|
||||||
|
"version": "0.7.2",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"book": {
|
||||||
|
"name": "book",
|
||||||
|
"types": [
|
||||||
|
"book"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-spreadsheet-in",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-spreadsheet-in/book.js"
|
||||||
|
},
|
||||||
|
"sheet": {
|
||||||
|
"name": "sheet",
|
||||||
|
"types": [
|
||||||
|
"sheet"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-spreadsheet-in",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-spreadsheet-in/sheet.js"
|
||||||
|
},
|
||||||
|
"cell": {
|
||||||
|
"name": "cell",
|
||||||
|
"types": [
|
||||||
|
"cell"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-spreadsheet-in",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-spreadsheet-in/cell.js"
|
||||||
|
},
|
||||||
|
"sheet-to-json": {
|
||||||
|
"name": "sheet-to-json",
|
||||||
|
"types": [
|
||||||
|
"sheet-to-json"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-spreadsheet-in",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-spreadsheet-in/sheet-to-json.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
919
.config.nodes.json.backup
Normal file
919
.config.nodes.json.backup
Normal file
@@ -0,0 +1,919 @@
|
|||||||
|
{
|
||||||
|
"node-red": {
|
||||||
|
"name": "node-red",
|
||||||
|
"version": "4.1.1",
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"nodes": {
|
||||||
|
"junction": {
|
||||||
|
"name": "junction",
|
||||||
|
"types": [
|
||||||
|
"junction"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/05-junction.js"
|
||||||
|
},
|
||||||
|
"inject": {
|
||||||
|
"name": "inject",
|
||||||
|
"types": [
|
||||||
|
"inject"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/20-inject.js"
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"name": "debug",
|
||||||
|
"types": [
|
||||||
|
"debug"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/21-debug.js"
|
||||||
|
},
|
||||||
|
"complete": {
|
||||||
|
"name": "complete",
|
||||||
|
"types": [
|
||||||
|
"complete"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/24-complete.js"
|
||||||
|
},
|
||||||
|
"catch": {
|
||||||
|
"name": "catch",
|
||||||
|
"types": [
|
||||||
|
"catch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/25-catch.js"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"types": [
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/25-status.js"
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"name": "link",
|
||||||
|
"types": [
|
||||||
|
"link in",
|
||||||
|
"link out",
|
||||||
|
"link call"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/60-link.js"
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"name": "comment",
|
||||||
|
"types": [
|
||||||
|
"comment"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/90-comment.js"
|
||||||
|
},
|
||||||
|
"global-config": {
|
||||||
|
"name": "global-config",
|
||||||
|
"types": [
|
||||||
|
"global-config"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/91-global-config.js"
|
||||||
|
},
|
||||||
|
"unknown": {
|
||||||
|
"name": "unknown",
|
||||||
|
"types": [
|
||||||
|
"unknown"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/common/98-unknown.js"
|
||||||
|
},
|
||||||
|
"function": {
|
||||||
|
"name": "function",
|
||||||
|
"types": [
|
||||||
|
"function"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/10-function.js"
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"name": "switch",
|
||||||
|
"types": [
|
||||||
|
"switch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/10-switch.js"
|
||||||
|
},
|
||||||
|
"change": {
|
||||||
|
"name": "change",
|
||||||
|
"types": [
|
||||||
|
"change"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/15-change.js"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"name": "range",
|
||||||
|
"types": [
|
||||||
|
"range"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/16-range.js"
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"name": "template",
|
||||||
|
"types": [
|
||||||
|
"template"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/80-template.js"
|
||||||
|
},
|
||||||
|
"delay": {
|
||||||
|
"name": "delay",
|
||||||
|
"types": [
|
||||||
|
"delay"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/89-delay.js"
|
||||||
|
},
|
||||||
|
"trigger": {
|
||||||
|
"name": "trigger",
|
||||||
|
"types": [
|
||||||
|
"trigger"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/89-trigger.js"
|
||||||
|
},
|
||||||
|
"exec": {
|
||||||
|
"name": "exec",
|
||||||
|
"types": [
|
||||||
|
"exec"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/90-exec.js"
|
||||||
|
},
|
||||||
|
"rbe": {
|
||||||
|
"name": "rbe",
|
||||||
|
"types": [
|
||||||
|
"rbe"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/function/rbe.js"
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"name": "tls",
|
||||||
|
"types": [
|
||||||
|
"tls-config"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/05-tls.js"
|
||||||
|
},
|
||||||
|
"httpproxy": {
|
||||||
|
"name": "httpproxy",
|
||||||
|
"types": [
|
||||||
|
"http proxy"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/06-httpproxy.js"
|
||||||
|
},
|
||||||
|
"mqtt": {
|
||||||
|
"name": "mqtt",
|
||||||
|
"types": [
|
||||||
|
"mqtt in",
|
||||||
|
"mqtt out",
|
||||||
|
"mqtt-broker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/10-mqtt.js"
|
||||||
|
},
|
||||||
|
"httpin": {
|
||||||
|
"name": "httpin",
|
||||||
|
"types": [
|
||||||
|
"http in",
|
||||||
|
"http response"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/21-httpin.js"
|
||||||
|
},
|
||||||
|
"httprequest": {
|
||||||
|
"name": "httprequest",
|
||||||
|
"types": [
|
||||||
|
"http request"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/21-httprequest.js"
|
||||||
|
},
|
||||||
|
"websocket": {
|
||||||
|
"name": "websocket",
|
||||||
|
"types": [
|
||||||
|
"websocket in",
|
||||||
|
"websocket out",
|
||||||
|
"websocket-listener",
|
||||||
|
"websocket-client"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/22-websocket.js"
|
||||||
|
},
|
||||||
|
"tcpin": {
|
||||||
|
"name": "tcpin",
|
||||||
|
"types": [
|
||||||
|
"tcp in",
|
||||||
|
"tcp out",
|
||||||
|
"tcp request"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/31-tcpin.js"
|
||||||
|
},
|
||||||
|
"udp": {
|
||||||
|
"name": "udp",
|
||||||
|
"types": [
|
||||||
|
"udp in",
|
||||||
|
"udp out"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/network/32-udp.js"
|
||||||
|
},
|
||||||
|
"CSV": {
|
||||||
|
"name": "CSV",
|
||||||
|
"types": [
|
||||||
|
"csv"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-CSV.js"
|
||||||
|
},
|
||||||
|
"HTML": {
|
||||||
|
"name": "HTML",
|
||||||
|
"types": [
|
||||||
|
"html"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-HTML.js"
|
||||||
|
},
|
||||||
|
"JSON": {
|
||||||
|
"name": "JSON",
|
||||||
|
"types": [
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-JSON.js"
|
||||||
|
},
|
||||||
|
"XML": {
|
||||||
|
"name": "XML",
|
||||||
|
"types": [
|
||||||
|
"xml"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-XML.js"
|
||||||
|
},
|
||||||
|
"YAML": {
|
||||||
|
"name": "YAML",
|
||||||
|
"types": [
|
||||||
|
"yaml"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/parsers/70-YAML.js"
|
||||||
|
},
|
||||||
|
"split": {
|
||||||
|
"name": "split",
|
||||||
|
"types": [
|
||||||
|
"split",
|
||||||
|
"join"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/sequence/17-split.js"
|
||||||
|
},
|
||||||
|
"sort": {
|
||||||
|
"name": "sort",
|
||||||
|
"types": [
|
||||||
|
"sort"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/sequence/18-sort.js"
|
||||||
|
},
|
||||||
|
"batch": {
|
||||||
|
"name": "batch",
|
||||||
|
"types": [
|
||||||
|
"batch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/sequence/19-batch.js"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"types": [
|
||||||
|
"file",
|
||||||
|
"file in"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/storage/10-file.js"
|
||||||
|
},
|
||||||
|
"watch": {
|
||||||
|
"name": "watch",
|
||||||
|
"types": [
|
||||||
|
"watch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": false,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red",
|
||||||
|
"file": "/usr/local/lib/node_modules/node-red/node_modules/@node-red/nodes/core/storage/23-watch.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-buffer-parser": {
|
||||||
|
"name": "node-red-contrib-buffer-parser",
|
||||||
|
"version": "3.2.2",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"buffer-parser": {
|
||||||
|
"name": "buffer-parser",
|
||||||
|
"types": [
|
||||||
|
"buffer-parser"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-buffer-parser",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-buffer-parser/buffer-parser.js"
|
||||||
|
},
|
||||||
|
"buffer-maker": {
|
||||||
|
"name": "buffer-maker",
|
||||||
|
"types": [
|
||||||
|
"buffer-maker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-buffer-parser",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-buffer-parser/buffer-maker.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-play-audio": {
|
||||||
|
"name": "node-red-contrib-play-audio",
|
||||||
|
"version": "2.5.0",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"play-audio": {
|
||||||
|
"name": "play-audio",
|
||||||
|
"types": [
|
||||||
|
"play audio"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-play-audio",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-play-audio/play-audio.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-pi-gpio": {
|
||||||
|
"name": "node-red-node-pi-gpio",
|
||||||
|
"version": "2.0.6",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"rpi-gpio": {
|
||||||
|
"name": "rpi-gpio",
|
||||||
|
"types": [
|
||||||
|
"rpi-gpio in",
|
||||||
|
"rpi-gpio out",
|
||||||
|
"rpi-mouse",
|
||||||
|
"rpi-keyboard"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-pi-gpio",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-pi-gpio/36-rpi-gpio.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-ping": {
|
||||||
|
"name": "node-red-node-ping",
|
||||||
|
"version": "0.3.3",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"ping": {
|
||||||
|
"name": "ping",
|
||||||
|
"types": [
|
||||||
|
"ping"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-ping",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-ping/88-ping.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-random": {
|
||||||
|
"name": "node-red-node-random",
|
||||||
|
"version": "0.4.1",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"random": {
|
||||||
|
"name": "random",
|
||||||
|
"types": [
|
||||||
|
"random"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-random",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-random/random.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-serialport": {
|
||||||
|
"name": "node-red-node-serialport",
|
||||||
|
"version": "2.0.3",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"serialport": {
|
||||||
|
"name": "serialport",
|
||||||
|
"types": [
|
||||||
|
"serial in",
|
||||||
|
"serial out",
|
||||||
|
"serial request",
|
||||||
|
"serial-port",
|
||||||
|
"serial control"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-serialport",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-serialport/25-serial.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-smooth": {
|
||||||
|
"name": "node-red-node-smooth",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"smooth": {
|
||||||
|
"name": "smooth",
|
||||||
|
"types": [
|
||||||
|
"smooth"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-smooth",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-smooth/17-smooth.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-dashboard": {
|
||||||
|
"name": "node-red-dashboard",
|
||||||
|
"version": "3.6.6",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"ui_base": {
|
||||||
|
"name": "ui_base",
|
||||||
|
"types": [
|
||||||
|
"ui_base"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_base.js"
|
||||||
|
},
|
||||||
|
"ui_button": {
|
||||||
|
"name": "ui_button",
|
||||||
|
"types": [
|
||||||
|
"ui_button"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_button.js"
|
||||||
|
},
|
||||||
|
"ui_dropdown": {
|
||||||
|
"name": "ui_dropdown",
|
||||||
|
"types": [
|
||||||
|
"ui_dropdown"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_dropdown.js"
|
||||||
|
},
|
||||||
|
"ui_switch": {
|
||||||
|
"name": "ui_switch",
|
||||||
|
"types": [
|
||||||
|
"ui_switch"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_switch.js"
|
||||||
|
},
|
||||||
|
"ui_slider": {
|
||||||
|
"name": "ui_slider",
|
||||||
|
"types": [
|
||||||
|
"ui_slider"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_slider.js"
|
||||||
|
},
|
||||||
|
"ui_numeric": {
|
||||||
|
"name": "ui_numeric",
|
||||||
|
"types": [
|
||||||
|
"ui_numeric"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_numeric.js"
|
||||||
|
},
|
||||||
|
"ui_text_input": {
|
||||||
|
"name": "ui_text_input",
|
||||||
|
"types": [
|
||||||
|
"ui_text_input"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_text_input.js"
|
||||||
|
},
|
||||||
|
"ui_date_picker": {
|
||||||
|
"name": "ui_date_picker",
|
||||||
|
"types": [
|
||||||
|
"ui_date_picker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_date_picker.js"
|
||||||
|
},
|
||||||
|
"ui_colour_picker": {
|
||||||
|
"name": "ui_colour_picker",
|
||||||
|
"types": [
|
||||||
|
"ui_colour_picker"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_colour_picker.js"
|
||||||
|
},
|
||||||
|
"ui_form": {
|
||||||
|
"name": "ui_form",
|
||||||
|
"types": [
|
||||||
|
"ui_form"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_form.js"
|
||||||
|
},
|
||||||
|
"ui_text": {
|
||||||
|
"name": "ui_text",
|
||||||
|
"types": [
|
||||||
|
"ui_text"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_text.js"
|
||||||
|
},
|
||||||
|
"ui_gauge": {
|
||||||
|
"name": "ui_gauge",
|
||||||
|
"types": [
|
||||||
|
"ui_gauge"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_gauge.js"
|
||||||
|
},
|
||||||
|
"ui_chart": {
|
||||||
|
"name": "ui_chart",
|
||||||
|
"types": [
|
||||||
|
"ui_chart"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_chart.js"
|
||||||
|
},
|
||||||
|
"ui_audio": {
|
||||||
|
"name": "ui_audio",
|
||||||
|
"types": [
|
||||||
|
"ui_audio"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_audio.js"
|
||||||
|
},
|
||||||
|
"ui_toast": {
|
||||||
|
"name": "ui_toast",
|
||||||
|
"types": [
|
||||||
|
"ui_toast"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_toast.js"
|
||||||
|
},
|
||||||
|
"ui_ui_control": {
|
||||||
|
"name": "ui_ui_control",
|
||||||
|
"types": [
|
||||||
|
"ui_ui_control"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_ui_control.js"
|
||||||
|
},
|
||||||
|
"ui_template": {
|
||||||
|
"name": "ui_template",
|
||||||
|
"types": [
|
||||||
|
"ui_template"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_template.js"
|
||||||
|
},
|
||||||
|
"ui_link": {
|
||||||
|
"name": "ui_link",
|
||||||
|
"types": [
|
||||||
|
"ui_link"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_link.js"
|
||||||
|
},
|
||||||
|
"ui_tab": {
|
||||||
|
"name": "ui_tab",
|
||||||
|
"types": [
|
||||||
|
"ui_tab"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_tab.js"
|
||||||
|
},
|
||||||
|
"ui_group": {
|
||||||
|
"name": "ui_group",
|
||||||
|
"types": [
|
||||||
|
"ui_group"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_group.js"
|
||||||
|
},
|
||||||
|
"ui_spacer": {
|
||||||
|
"name": "ui_spacer",
|
||||||
|
"types": [
|
||||||
|
"ui_spacer"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-dashboard",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-dashboard/nodes/ui_spacer.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-node-mysql": {
|
||||||
|
"name": "node-red-node-mysql",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"mysql": {
|
||||||
|
"name": "mysql",
|
||||||
|
"types": [
|
||||||
|
"MySQLdatabase",
|
||||||
|
"mysql"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-node-mysql",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-node-mysql/68-mysql.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-excel": {
|
||||||
|
"name": "node-red-contrib-excel",
|
||||||
|
"version": "0.0.3",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"xlsx": {
|
||||||
|
"name": "xlsx",
|
||||||
|
"types": [
|
||||||
|
"excel"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-excel",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-excel/excel/excel.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-browser-utils": {
|
||||||
|
"name": "node-red-contrib-browser-utils",
|
||||||
|
"version": "0.0.11",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"fileinject": {
|
||||||
|
"name": "fileinject",
|
||||||
|
"types": [
|
||||||
|
"fileinject"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-browser-utils",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-browser-utils/fileinject/fileinject.js"
|
||||||
|
},
|
||||||
|
"microphone": {
|
||||||
|
"name": "microphone",
|
||||||
|
"types": [
|
||||||
|
"microphone"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-browser-utils",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-browser-utils/microphone/microphone.js"
|
||||||
|
},
|
||||||
|
"camera": {
|
||||||
|
"name": "camera",
|
||||||
|
"types": [
|
||||||
|
"camera"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-browser-utils",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-browser-utils/camera/camera.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node-red-contrib-xlsx-to-json": {
|
||||||
|
"name": "node-red-contrib-xlsx-to-json",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"local": true,
|
||||||
|
"user": true,
|
||||||
|
"nodes": {
|
||||||
|
"xlsxtojson": {
|
||||||
|
"name": "xlsxtojson",
|
||||||
|
"types": [
|
||||||
|
"XLSX-to-json"
|
||||||
|
],
|
||||||
|
"enabled": true,
|
||||||
|
"local": true,
|
||||||
|
"user": false,
|
||||||
|
"module": "node-red-contrib-xlsx-to-json",
|
||||||
|
"file": "/home/mdares/.node-red/node_modules/node-red-contrib-xlsx-to-json/xlsx-to-json.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
.config.projects.json
Normal file
8
.config.projects.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"Plastico": {
|
||||||
|
"credentialSecret": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"activeProject": "Plastico"
|
||||||
|
}
|
||||||
7
.config.projects.json.backup
Normal file
7
.config.projects.json.backup
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"Plastico": {
|
||||||
|
"credentialSecret": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
.config.runtime.json
Normal file
5
.config.runtime.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"instanceId": "686f5534fab975c3",
|
||||||
|
"_credentialSecret": "a2260947d173b23ac8dedd1b91c4d9ef7834b54d6d22160bb2bc2d18d4c366cf",
|
||||||
|
"telemetryEnabled": false
|
||||||
|
}
|
||||||
4
.config.runtime.json.backup
Normal file
4
.config.runtime.json.backup
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"instanceId": "686f5534fab975c3",
|
||||||
|
"_credentialSecret": "a2260947d173b23ac8dedd1b91c4d9ef7834b54d6d22160bb2bc2d18d4c366cf"
|
||||||
|
}
|
||||||
30
.config.users.json
Normal file
30
.config.users.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"_": {
|
||||||
|
"editor": {
|
||||||
|
"view": {
|
||||||
|
"view-store-zoom": false,
|
||||||
|
"view-store-position": false,
|
||||||
|
"view-show-grid": true,
|
||||||
|
"view-snap-grid": true,
|
||||||
|
"view-grid-size": "20",
|
||||||
|
"view-node-status": true,
|
||||||
|
"view-node-info-icon": true,
|
||||||
|
"view-node-show-label": true,
|
||||||
|
"view-show-tips": true,
|
||||||
|
"view-show-welcome-tours": true
|
||||||
|
},
|
||||||
|
"tours": {
|
||||||
|
"welcome": "4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"filter": "filterCurrent"
|
||||||
|
},
|
||||||
|
"git": {
|
||||||
|
"user": {
|
||||||
|
"name": "Mdares",
|
||||||
|
"email": "mdares@maliountech.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
.config.users.json.backup
Normal file
24
.config.users.json.backup
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"_": {
|
||||||
|
"editor": {
|
||||||
|
"view": {
|
||||||
|
"view-store-zoom": false,
|
||||||
|
"view-store-position": false,
|
||||||
|
"view-show-grid": true,
|
||||||
|
"view-snap-grid": true,
|
||||||
|
"view-grid-size": "20",
|
||||||
|
"view-node-status": true,
|
||||||
|
"view-node-info-icon": true,
|
||||||
|
"view-node-show-label": true,
|
||||||
|
"view-show-tips": true,
|
||||||
|
"view-show-welcome-tours": true
|
||||||
|
},
|
||||||
|
"tours": {
|
||||||
|
"welcome": "4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"filter": "filterCurrent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1259
.flows.json.backup
Normal file
1259
.flows.json.backup
Normal file
File diff suppressed because one or more lines are too long
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.log
|
||||||
|
node_modules/
|
||||||
|
flows_cred.json
|
||||||
|
|
||||||
1293
flows.json
Normal file
1293
flows.json
Normal file
File diff suppressed because one or more lines are too long
1314
flows.json.backup-20251119-200256
Normal file
1314
flows.json.backup-20251119-200256
Normal file
File diff suppressed because one or more lines are too long
1312
flows.json.backup_20251119_204032
Normal file
1312
flows.json.backup_20251119_204032
Normal file
File diff suppressed because one or more lines are too long
1292
flows.json.backup_scrap_20251120_001129
Normal file
1292
flows.json.backup_scrap_20251120_001129
Normal file
File diff suppressed because one or more lines are too long
3
flows_cred.json
Normal file
3
flows_cred.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"$": "fd201cc3a5dc5f3a99f5c3c6bf5530bfqRHo9Yh9QCKU9Eo5XSQVCaBwBy2eAuNC5Y4Jgy7ohZDbrknQSkH/nQTZnK5d4nBJykKYTy5E45thhtELUH5dS7OKvNgK0G5muwGxDa8="
|
||||||
|
}
|
||||||
0
format.txt
Normal file
0
format.txt
Normal file
21
globals-reference.md
Normal file
21
globals-reference.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Global Variable Reference
|
||||||
|
|
||||||
|
| Variable | Type | Used in Tab | Purpose |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `kpiOeePercent` | number | Home | Overall Equipment Effectiveness (%) KPI summary card. |
|
||||||
|
| `kpiAvailabilityPercent` | number | Home | Availability KPI value shown in the top metrics row. |
|
||||||
|
| `kpiPerformancePercent` | number | Home | Performance KPI value shown in the top metrics row. |
|
||||||
|
| `kpiQualityPercent` | number | Home | Quality KPI value shown in the top metrics row. |
|
||||||
|
| `currentWorkOrderId` | string | Home | Identifier of the active work order displayed in the Work Order panel. |
|
||||||
|
| `currentSku` | string | Home | SKU associated with the current work order. |
|
||||||
|
| `currentCycleTime` | number | Home | Cycle time (seconds/minutes) displayed for the active work order. |
|
||||||
|
| `currentProgressPercent` | number | Home | Percent complete for the active work order and its progress bar. |
|
||||||
|
| `goodPartsCount` | number | Home | Count of accepted parts produced, displayed in Good Parts card. |
|
||||||
|
| `goodPartsTarget` | number | Home | Planned quantity for the current work order (`out of` value). |
|
||||||
|
| `machineOnline` | boolean | Home | Indicates whether the machine is online (affects status badge color/text). |
|
||||||
|
| `productionStarted` | boolean | Home | Indicates whether production is currently started (affects status badge). |
|
||||||
|
| `workOrders` | array | Work Orders | Array of work order objects rendered in the Work Orders table (id, sku, target, good, scrap, progressPercent, status, lastUpdateIso). |
|
||||||
|
| `moldTotalCavities` | number | Settings | Total number of mold cavities displayed in Mold Configuration. |
|
||||||
|
| `moldActiveCavities` | number | Settings | Number of active mold cavities displayed in Mold Configuration. |
|
||||||
|
|
||||||
|
All values can be updated dynamically from Node-RED function nodes via `ui_control` messages or `msg.payload`, and re-rendered using the corresponding render functions.
|
||||||
31
mold_presets_migration.sql
Normal file
31
mold_presets_migration.sql
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
-- Migration script for mold_presets table
|
||||||
|
-- Run this script in your MariaDB database: machine_data
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `mold_presets` (
|
||||||
|
`id` INT NOT NULL AUTO_INCREMENT,
|
||||||
|
`mold_name` VARCHAR(255) NOT NULL,
|
||||||
|
`manufacturer` VARCHAR(100) NOT NULL,
|
||||||
|
`theoretical_cavities` INT NOT NULL,
|
||||||
|
`functional_cavities` INT NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
INDEX `idx_manufacturer` (`manufacturer`),
|
||||||
|
INDEX `idx_mold_name` (`mold_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Insert seed data
|
||||||
|
INSERT INTO `mold_presets` (`mold_name`, `manufacturer`, `theoretical_cavities`, `functional_cavities`) VALUES
|
||||||
|
('Mold ABC', 'Nissan', 10, 8),
|
||||||
|
('Mold XYZ', 'Toyota', 12, 10),
|
||||||
|
('Mold DEF', 'Honda', 8, 7),
|
||||||
|
('Mold GHI', 'Ford', 16, 14),
|
||||||
|
('Mold JKL', 'BMW', 6, 6),
|
||||||
|
('Mold MNO', 'Nissan', 14, 12),
|
||||||
|
('Mold PQR', 'Toyota', 10, 9),
|
||||||
|
('Mold STU', 'Honda', 12, 11),
|
||||||
|
('Mold VWX', 'Ford', 8, 8),
|
||||||
|
('Mold YZ1', 'BMW', 20, 18);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1
node_modules/.bin/convert-excel-to-json
generated
vendored
Symbolic link
1
node_modules/.bin/convert-excel-to-json
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../convert-excel-to-json/bin/cli.js
|
||||||
1
node_modules/.bin/crc32
generated
vendored
Symbolic link
1
node_modules/.bin/crc32
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../crc-32/bin/crc32.njs
|
||||||
1
node_modules/.bin/inspect-function
generated
vendored
Symbolic link
1
node_modules/.bin/inspect-function
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../inspect-function/bin/magicli.js
|
||||||
1
node_modules/.bin/inspect-parameters-declaration
generated
vendored
Symbolic link
1
node_modules/.bin/inspect-parameters-declaration
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../inspect-parameters-declaration/bin/cli.js
|
||||||
1
node_modules/.bin/mime
generated
vendored
Symbolic link
1
node_modules/.bin/mime
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../mime/cli.js
|
||||||
1
node_modules/.bin/node-gyp-build
generated
vendored
Symbolic link
1
node_modules/.bin/node-gyp-build
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../node-gyp-build/bin.js
|
||||||
1
node_modules/.bin/node-gyp-build-optional
generated
vendored
Symbolic link
1
node_modules/.bin/node-gyp-build-optional
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../node-gyp-build/optional.js
|
||||||
1
node_modules/.bin/node-gyp-build-test
generated
vendored
Symbolic link
1
node_modules/.bin/node-gyp-build-test
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../node-gyp-build/build-test.js
|
||||||
1
node_modules/.bin/nodezip
generated
vendored
Symbolic link
1
node_modules/.bin/nodezip
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../node-zip/bin/nodezip
|
||||||
1
node_modules/.bin/object-to-arguments
generated
vendored
Symbolic link
1
node_modules/.bin/object-to-arguments
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../object-to-arguments/bin/cli.js
|
||||||
1
node_modules/.bin/printj
generated
vendored
Symbolic link
1
node_modules/.bin/printj
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../printj/bin/printj.njs
|
||||||
1
node_modules/.bin/stringify-parameters
generated
vendored
Symbolic link
1
node_modules/.bin/stringify-parameters
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../stringify-parameters/bin/cli.js
|
||||||
1
node_modules/.bin/xlsx
generated
vendored
Symbolic link
1
node_modules/.bin/xlsx
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../xlsx/bin/xlsx.njs
|
||||||
2104
node_modules/.package-lock.json
generated
vendored
Normal file
2104
node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
node_modules/@serialport/binding-mock/.releaserc
generated
vendored
Normal file
6
node_modules/@serialport/binding-mock/.releaserc
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"branches": [
|
||||||
|
"main",
|
||||||
|
"next"
|
||||||
|
]
|
||||||
|
}
|
||||||
21
node_modules/@serialport/binding-mock/LICENSE
generated
vendored
Normal file
21
node_modules/@serialport/binding-mock/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Francis Gulotta
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
9
node_modules/@serialport/binding-mock/README.md
generated
vendored
Normal file
9
node_modules/@serialport/binding-mock/README.md
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# @serialport/binding-mock
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { MockBinding } from '@serialport/binding-mock'
|
||||||
|
const MockBinding = new MockBinding()
|
||||||
|
|
||||||
|
MockBinding.createPort('/dev/fakePort', { echo: true })
|
||||||
|
await MockBinding.write(Buffer.from('data')))
|
||||||
|
```
|
||||||
271
node_modules/@serialport/binding-mock/dist/index-esm.mjs
generated
vendored
Normal file
271
node_modules/@serialport/binding-mock/dist/index-esm.mjs
generated
vendored
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
import debugFactory from 'debug';
|
||||||
|
|
||||||
|
const debug = debugFactory('serialport/binding-mock');
|
||||||
|
let ports = {};
|
||||||
|
let serialNumber = 0;
|
||||||
|
function resolveNextTick() {
|
||||||
|
return new Promise(resolve => process.nextTick(() => resolve()));
|
||||||
|
}
|
||||||
|
class CanceledError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.canceled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const MockBinding = {
|
||||||
|
reset() {
|
||||||
|
ports = {};
|
||||||
|
serialNumber = 0;
|
||||||
|
},
|
||||||
|
// Create a mock port
|
||||||
|
createPort(path, options = {}) {
|
||||||
|
serialNumber++;
|
||||||
|
const optWithDefaults = Object.assign({ echo: false, record: false, manufacturer: 'The J5 Robotics Company', vendorId: undefined, productId: undefined, maxReadSize: 1024 }, options);
|
||||||
|
ports[path] = {
|
||||||
|
data: Buffer.alloc(0),
|
||||||
|
echo: optWithDefaults.echo,
|
||||||
|
record: optWithDefaults.record,
|
||||||
|
readyData: optWithDefaults.readyData,
|
||||||
|
maxReadSize: optWithDefaults.maxReadSize,
|
||||||
|
info: {
|
||||||
|
path,
|
||||||
|
manufacturer: optWithDefaults.manufacturer,
|
||||||
|
serialNumber: `${serialNumber}`,
|
||||||
|
pnpId: undefined,
|
||||||
|
locationId: undefined,
|
||||||
|
vendorId: optWithDefaults.vendorId,
|
||||||
|
productId: optWithDefaults.productId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
debug(serialNumber, 'created port', JSON.stringify({ path, opt: options }));
|
||||||
|
},
|
||||||
|
async list() {
|
||||||
|
debug(null, 'list');
|
||||||
|
return Object.values(ports).map(port => port.info);
|
||||||
|
},
|
||||||
|
async open(options) {
|
||||||
|
var _a;
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (!options.path) {
|
||||||
|
throw new TypeError('"path" is not a valid port');
|
||||||
|
}
|
||||||
|
if (!options.baudRate) {
|
||||||
|
throw new TypeError('"baudRate" is not a valid baudRate');
|
||||||
|
}
|
||||||
|
const openOptions = Object.assign({ dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, xon: false, xoff: false, xany: false, hupcl: true }, options);
|
||||||
|
const { path } = openOptions;
|
||||||
|
debug(null, `open: opening path ${path}`);
|
||||||
|
const port = ports[path];
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!port) {
|
||||||
|
throw new Error(`Port does not exist - please call MockBinding.createPort('${path}') first`);
|
||||||
|
}
|
||||||
|
const serialNumber = port.info.serialNumber;
|
||||||
|
if ((_a = port.openOpt) === null || _a === void 0 ? void 0 : _a.lock) {
|
||||||
|
debug(serialNumber, 'open: Port is locked cannot open');
|
||||||
|
throw new Error('Port is locked cannot open');
|
||||||
|
}
|
||||||
|
debug(serialNumber, `open: opened path ${path}`);
|
||||||
|
port.openOpt = Object.assign({}, openOptions);
|
||||||
|
return new MockPortBinding(port, openOptions);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Mock bindings for pretend serialport access
|
||||||
|
*/
|
||||||
|
class MockPortBinding {
|
||||||
|
constructor(port, openOptions) {
|
||||||
|
this.port = port;
|
||||||
|
this.openOptions = openOptions;
|
||||||
|
this.pendingRead = null;
|
||||||
|
this.isOpen = true;
|
||||||
|
this.lastWrite = null;
|
||||||
|
this.recording = Buffer.alloc(0);
|
||||||
|
this.writeOperation = null; // in flight promise or null
|
||||||
|
this.serialNumber = port.info.serialNumber;
|
||||||
|
if (port.readyData) {
|
||||||
|
const data = port.readyData;
|
||||||
|
process.nextTick(() => {
|
||||||
|
if (this.isOpen) {
|
||||||
|
debug(this.serialNumber, 'emitting ready data');
|
||||||
|
this.emitData(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Emit data on a mock port
|
||||||
|
emitData(data) {
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port must be open to pretend to receive data');
|
||||||
|
}
|
||||||
|
const bufferData = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
||||||
|
debug(this.serialNumber, 'emitting data - pending read:', Boolean(this.pendingRead));
|
||||||
|
this.port.data = Buffer.concat([this.port.data, bufferData]);
|
||||||
|
if (this.pendingRead) {
|
||||||
|
process.nextTick(this.pendingRead);
|
||||||
|
this.pendingRead = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async close() {
|
||||||
|
debug(this.serialNumber, 'close');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
const port = this.port;
|
||||||
|
if (!port) {
|
||||||
|
throw new Error('already closed');
|
||||||
|
}
|
||||||
|
port.openOpt = undefined;
|
||||||
|
// reset data on close
|
||||||
|
port.data = Buffer.alloc(0);
|
||||||
|
debug(this.serialNumber, 'port is closed');
|
||||||
|
this.serialNumber = undefined;
|
||||||
|
this.isOpen = false;
|
||||||
|
if (this.pendingRead) {
|
||||||
|
this.pendingRead(new CanceledError('port is closed'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async read(buffer, offset, length) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
if (typeof offset !== 'number' || isNaN(offset)) {
|
||||||
|
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
||||||
|
}
|
||||||
|
if (typeof length !== 'number' || isNaN(length)) {
|
||||||
|
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
||||||
|
}
|
||||||
|
if (buffer.length < offset + length) {
|
||||||
|
throw new Error('buffer is too small');
|
||||||
|
}
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'read', length, 'bytes');
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new CanceledError('Read canceled');
|
||||||
|
}
|
||||||
|
if (this.port.data.length <= 0) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.pendingRead = err => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
this.read(buffer, offset, length).then(resolve, reject);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const lengthToRead = this.port.maxReadSize > length ? length : this.port.maxReadSize;
|
||||||
|
const data = this.port.data.slice(0, lengthToRead);
|
||||||
|
const bytesRead = data.copy(buffer, offset);
|
||||||
|
this.port.data = this.port.data.slice(lengthToRead);
|
||||||
|
debug(this.serialNumber, 'read', bytesRead, 'bytes');
|
||||||
|
return { bytesRead, buffer };
|
||||||
|
}
|
||||||
|
async write(buffer) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
debug('write', 'error port is not open');
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'write', buffer.length, 'bytes');
|
||||||
|
if (this.writeOperation) {
|
||||||
|
throw new Error('Overlapping writes are not supported and should be queued by the serialport object');
|
||||||
|
}
|
||||||
|
this.writeOperation = (async () => {
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Write canceled');
|
||||||
|
}
|
||||||
|
const data = (this.lastWrite = Buffer.from(buffer)); // copy
|
||||||
|
if (this.port.record) {
|
||||||
|
this.recording = Buffer.concat([this.recording, data]);
|
||||||
|
}
|
||||||
|
if (this.port.echo) {
|
||||||
|
process.nextTick(() => {
|
||||||
|
if (this.isOpen) {
|
||||||
|
this.emitData(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.writeOperation = null;
|
||||||
|
debug(this.serialNumber, 'writing finished');
|
||||||
|
})();
|
||||||
|
return this.writeOperation;
|
||||||
|
}
|
||||||
|
async update(options) {
|
||||||
|
if (typeof options !== 'object') {
|
||||||
|
throw TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (typeof options.baudRate !== 'number') {
|
||||||
|
throw new TypeError('"options.baudRate" is not a number');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'update');
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
if (this.port.openOpt) {
|
||||||
|
this.port.openOpt.baudRate = options.baudRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async set(options) {
|
||||||
|
if (typeof options !== 'object') {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'set');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
}
|
||||||
|
async get() {
|
||||||
|
debug(this.serialNumber, 'get');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
return {
|
||||||
|
cts: true,
|
||||||
|
dsr: false,
|
||||||
|
dcd: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async getBaudRate() {
|
||||||
|
var _a;
|
||||||
|
debug(this.serialNumber, 'getBaudRate');
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!((_a = this.port.openOpt) === null || _a === void 0 ? void 0 : _a.baudRate)) {
|
||||||
|
throw new Error('Internal Error');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
baudRate: this.port.openOpt.baudRate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async flush() {
|
||||||
|
debug(this.serialNumber, 'flush');
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
this.port.data = Buffer.alloc(0);
|
||||||
|
}
|
||||||
|
async drain() {
|
||||||
|
debug(this.serialNumber, 'drain');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await this.writeOperation;
|
||||||
|
await resolveNextTick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CanceledError, MockBinding, MockPortBinding };
|
||||||
73
node_modules/@serialport/binding-mock/dist/index.d.ts
generated
vendored
Normal file
73
node_modules/@serialport/binding-mock/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
|
||||||
|
import { BindingInterface } from '@serialport/bindings-interface';
|
||||||
|
import { BindingPortInterface } from '@serialport/bindings-interface';
|
||||||
|
import { OpenOptions } from '@serialport/bindings-interface';
|
||||||
|
import { PortInfo } from '@serialport/bindings-interface';
|
||||||
|
import { PortStatus } from '@serialport/bindings-interface';
|
||||||
|
import { SetOptions } from '@serialport/bindings-interface';
|
||||||
|
import { UpdateOptions } from '@serialport/bindings-interface';
|
||||||
|
|
||||||
|
export declare class CanceledError extends Error {
|
||||||
|
canceled: true;
|
||||||
|
constructor(message: string);
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface CreatePortOptions {
|
||||||
|
echo?: boolean;
|
||||||
|
record?: boolean;
|
||||||
|
readyData?: Buffer;
|
||||||
|
maxReadSize?: number;
|
||||||
|
manufacturer?: string;
|
||||||
|
vendorId?: string;
|
||||||
|
productId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare const MockBinding: MockBindingInterface;
|
||||||
|
|
||||||
|
export declare interface MockBindingInterface extends BindingInterface<MockPortBinding> {
|
||||||
|
reset(): void;
|
||||||
|
createPort(path: string, opt?: CreatePortOptions): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock bindings for pretend serialport access
|
||||||
|
*/
|
||||||
|
export declare class MockPortBinding implements BindingPortInterface {
|
||||||
|
readonly openOptions: Required<OpenOptions>;
|
||||||
|
readonly port: MockPortInternal;
|
||||||
|
private pendingRead;
|
||||||
|
lastWrite: null | Buffer;
|
||||||
|
recording: Buffer;
|
||||||
|
writeOperation: null | Promise<void>;
|
||||||
|
isOpen: boolean;
|
||||||
|
serialNumber?: string;
|
||||||
|
constructor(port: MockPortInternal, openOptions: Required<OpenOptions>);
|
||||||
|
emitData(data: Buffer | string): void;
|
||||||
|
close(): Promise<void>;
|
||||||
|
read(buffer: Buffer, offset: number, length: number): Promise<{
|
||||||
|
buffer: Buffer;
|
||||||
|
bytesRead: number;
|
||||||
|
}>;
|
||||||
|
write(buffer: Buffer): Promise<void>;
|
||||||
|
update(options: UpdateOptions): Promise<void>;
|
||||||
|
set(options: SetOptions): Promise<void>;
|
||||||
|
get(): Promise<PortStatus>;
|
||||||
|
getBaudRate(): Promise<{
|
||||||
|
baudRate: number;
|
||||||
|
}>;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
drain(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface MockPortInternal {
|
||||||
|
data: Buffer;
|
||||||
|
echo: boolean;
|
||||||
|
record: boolean;
|
||||||
|
info: PortInfo;
|
||||||
|
maxReadSize: number;
|
||||||
|
readyData?: Buffer;
|
||||||
|
openOpt?: OpenOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { }
|
||||||
281
node_modules/@serialport/binding-mock/dist/index.js
generated
vendored
Normal file
281
node_modules/@serialport/binding-mock/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
|
var debugFactory = require('debug');
|
||||||
|
|
||||||
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
||||||
|
|
||||||
|
var debugFactory__default = /*#__PURE__*/_interopDefaultLegacy(debugFactory);
|
||||||
|
|
||||||
|
const debug = debugFactory__default["default"]('serialport/binding-mock');
|
||||||
|
let ports = {};
|
||||||
|
let serialNumber = 0;
|
||||||
|
function resolveNextTick() {
|
||||||
|
return new Promise(resolve => process.nextTick(() => resolve()));
|
||||||
|
}
|
||||||
|
class CanceledError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.canceled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const MockBinding = {
|
||||||
|
reset() {
|
||||||
|
ports = {};
|
||||||
|
serialNumber = 0;
|
||||||
|
},
|
||||||
|
// Create a mock port
|
||||||
|
createPort(path, options = {}) {
|
||||||
|
serialNumber++;
|
||||||
|
const optWithDefaults = Object.assign({ echo: false, record: false, manufacturer: 'The J5 Robotics Company', vendorId: undefined, productId: undefined, maxReadSize: 1024 }, options);
|
||||||
|
ports[path] = {
|
||||||
|
data: Buffer.alloc(0),
|
||||||
|
echo: optWithDefaults.echo,
|
||||||
|
record: optWithDefaults.record,
|
||||||
|
readyData: optWithDefaults.readyData,
|
||||||
|
maxReadSize: optWithDefaults.maxReadSize,
|
||||||
|
info: {
|
||||||
|
path,
|
||||||
|
manufacturer: optWithDefaults.manufacturer,
|
||||||
|
serialNumber: `${serialNumber}`,
|
||||||
|
pnpId: undefined,
|
||||||
|
locationId: undefined,
|
||||||
|
vendorId: optWithDefaults.vendorId,
|
||||||
|
productId: optWithDefaults.productId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
debug(serialNumber, 'created port', JSON.stringify({ path, opt: options }));
|
||||||
|
},
|
||||||
|
async list() {
|
||||||
|
debug(null, 'list');
|
||||||
|
return Object.values(ports).map(port => port.info);
|
||||||
|
},
|
||||||
|
async open(options) {
|
||||||
|
var _a;
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (!options.path) {
|
||||||
|
throw new TypeError('"path" is not a valid port');
|
||||||
|
}
|
||||||
|
if (!options.baudRate) {
|
||||||
|
throw new TypeError('"baudRate" is not a valid baudRate');
|
||||||
|
}
|
||||||
|
const openOptions = Object.assign({ dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, xon: false, xoff: false, xany: false, hupcl: true }, options);
|
||||||
|
const { path } = openOptions;
|
||||||
|
debug(null, `open: opening path ${path}`);
|
||||||
|
const port = ports[path];
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!port) {
|
||||||
|
throw new Error(`Port does not exist - please call MockBinding.createPort('${path}') first`);
|
||||||
|
}
|
||||||
|
const serialNumber = port.info.serialNumber;
|
||||||
|
if ((_a = port.openOpt) === null || _a === void 0 ? void 0 : _a.lock) {
|
||||||
|
debug(serialNumber, 'open: Port is locked cannot open');
|
||||||
|
throw new Error('Port is locked cannot open');
|
||||||
|
}
|
||||||
|
debug(serialNumber, `open: opened path ${path}`);
|
||||||
|
port.openOpt = Object.assign({}, openOptions);
|
||||||
|
return new MockPortBinding(port, openOptions);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Mock bindings for pretend serialport access
|
||||||
|
*/
|
||||||
|
class MockPortBinding {
|
||||||
|
constructor(port, openOptions) {
|
||||||
|
this.port = port;
|
||||||
|
this.openOptions = openOptions;
|
||||||
|
this.pendingRead = null;
|
||||||
|
this.isOpen = true;
|
||||||
|
this.lastWrite = null;
|
||||||
|
this.recording = Buffer.alloc(0);
|
||||||
|
this.writeOperation = null; // in flight promise or null
|
||||||
|
this.serialNumber = port.info.serialNumber;
|
||||||
|
if (port.readyData) {
|
||||||
|
const data = port.readyData;
|
||||||
|
process.nextTick(() => {
|
||||||
|
if (this.isOpen) {
|
||||||
|
debug(this.serialNumber, 'emitting ready data');
|
||||||
|
this.emitData(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Emit data on a mock port
|
||||||
|
emitData(data) {
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port must be open to pretend to receive data');
|
||||||
|
}
|
||||||
|
const bufferData = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
||||||
|
debug(this.serialNumber, 'emitting data - pending read:', Boolean(this.pendingRead));
|
||||||
|
this.port.data = Buffer.concat([this.port.data, bufferData]);
|
||||||
|
if (this.pendingRead) {
|
||||||
|
process.nextTick(this.pendingRead);
|
||||||
|
this.pendingRead = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async close() {
|
||||||
|
debug(this.serialNumber, 'close');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
const port = this.port;
|
||||||
|
if (!port) {
|
||||||
|
throw new Error('already closed');
|
||||||
|
}
|
||||||
|
port.openOpt = undefined;
|
||||||
|
// reset data on close
|
||||||
|
port.data = Buffer.alloc(0);
|
||||||
|
debug(this.serialNumber, 'port is closed');
|
||||||
|
this.serialNumber = undefined;
|
||||||
|
this.isOpen = false;
|
||||||
|
if (this.pendingRead) {
|
||||||
|
this.pendingRead(new CanceledError('port is closed'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async read(buffer, offset, length) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
if (typeof offset !== 'number' || isNaN(offset)) {
|
||||||
|
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
||||||
|
}
|
||||||
|
if (typeof length !== 'number' || isNaN(length)) {
|
||||||
|
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
||||||
|
}
|
||||||
|
if (buffer.length < offset + length) {
|
||||||
|
throw new Error('buffer is too small');
|
||||||
|
}
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'read', length, 'bytes');
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new CanceledError('Read canceled');
|
||||||
|
}
|
||||||
|
if (this.port.data.length <= 0) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.pendingRead = err => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
this.read(buffer, offset, length).then(resolve, reject);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const lengthToRead = this.port.maxReadSize > length ? length : this.port.maxReadSize;
|
||||||
|
const data = this.port.data.slice(0, lengthToRead);
|
||||||
|
const bytesRead = data.copy(buffer, offset);
|
||||||
|
this.port.data = this.port.data.slice(lengthToRead);
|
||||||
|
debug(this.serialNumber, 'read', bytesRead, 'bytes');
|
||||||
|
return { bytesRead, buffer };
|
||||||
|
}
|
||||||
|
async write(buffer) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
debug('write', 'error port is not open');
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'write', buffer.length, 'bytes');
|
||||||
|
if (this.writeOperation) {
|
||||||
|
throw new Error('Overlapping writes are not supported and should be queued by the serialport object');
|
||||||
|
}
|
||||||
|
this.writeOperation = (async () => {
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Write canceled');
|
||||||
|
}
|
||||||
|
const data = (this.lastWrite = Buffer.from(buffer)); // copy
|
||||||
|
if (this.port.record) {
|
||||||
|
this.recording = Buffer.concat([this.recording, data]);
|
||||||
|
}
|
||||||
|
if (this.port.echo) {
|
||||||
|
process.nextTick(() => {
|
||||||
|
if (this.isOpen) {
|
||||||
|
this.emitData(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.writeOperation = null;
|
||||||
|
debug(this.serialNumber, 'writing finished');
|
||||||
|
})();
|
||||||
|
return this.writeOperation;
|
||||||
|
}
|
||||||
|
async update(options) {
|
||||||
|
if (typeof options !== 'object') {
|
||||||
|
throw TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (typeof options.baudRate !== 'number') {
|
||||||
|
throw new TypeError('"options.baudRate" is not a number');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'update');
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
if (this.port.openOpt) {
|
||||||
|
this.port.openOpt.baudRate = options.baudRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async set(options) {
|
||||||
|
if (typeof options !== 'object') {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
debug(this.serialNumber, 'set');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
}
|
||||||
|
async get() {
|
||||||
|
debug(this.serialNumber, 'get');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
return {
|
||||||
|
cts: true,
|
||||||
|
dsr: false,
|
||||||
|
dcd: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async getBaudRate() {
|
||||||
|
var _a;
|
||||||
|
debug(this.serialNumber, 'getBaudRate');
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
if (!((_a = this.port.openOpt) === null || _a === void 0 ? void 0 : _a.baudRate)) {
|
||||||
|
throw new Error('Internal Error');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
baudRate: this.port.openOpt.baudRate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async flush() {
|
||||||
|
debug(this.serialNumber, 'flush');
|
||||||
|
if (!this.isOpen || !this.port) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await resolveNextTick();
|
||||||
|
this.port.data = Buffer.alloc(0);
|
||||||
|
}
|
||||||
|
async drain() {
|
||||||
|
debug(this.serialNumber, 'drain');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await this.writeOperation;
|
||||||
|
await resolveNextTick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.CanceledError = CanceledError;
|
||||||
|
exports.MockBinding = MockBinding;
|
||||||
|
exports.MockPortBinding = MockPortBinding;
|
||||||
58
node_modules/@serialport/binding-mock/package.json
generated
vendored
Normal file
58
node_modules/@serialport/binding-mock/package.json
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"name": "@serialport/binding-mock",
|
||||||
|
"version": "10.2.2",
|
||||||
|
"description": "The mock serialport bindings",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"exports": {
|
||||||
|
"require": "./dist/index.js",
|
||||||
|
"default": "./dist/index-esm.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"repository": "git@github.com:serialport/binding-mock.git",
|
||||||
|
"homepage": "https://github.com/serialport/binding-mock",
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha",
|
||||||
|
"lint": "tsc && eslint lib/**/*.ts",
|
||||||
|
"format": "eslint lib/**/*.ts --fix",
|
||||||
|
"clean": "rm -rf dist-ts dist",
|
||||||
|
"build": "npm run clean && tsc -p tsconfig-build.json && rollup -c && node -r esbuild-register bundle-types",
|
||||||
|
"prepublishOnly": "npm run build",
|
||||||
|
"semantic-release": "semantic-release"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"serialport-binding",
|
||||||
|
"debug"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"@microsoft/api-extractor": "7.19.4",
|
||||||
|
"@types/chai": "4.3.0",
|
||||||
|
"@types/mocha": "9.1.0",
|
||||||
|
"@types/node": "17.0.15",
|
||||||
|
"@typescript-eslint/eslint-plugin": "5.10.2",
|
||||||
|
"@typescript-eslint/parser": "5.10.2",
|
||||||
|
"chai": "4.3.6",
|
||||||
|
"esbuild": "0.14.18",
|
||||||
|
"esbuild-register": "3.3.2",
|
||||||
|
"eslint": "8.8.0",
|
||||||
|
"mocha": "9.2.0",
|
||||||
|
"rollup": "2.67.0",
|
||||||
|
"rollup-plugin-node-resolve": "5.2.0",
|
||||||
|
"semantic-release": "19.0.2",
|
||||||
|
"typescript": "4.5.5"
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"bail": true,
|
||||||
|
"require": [
|
||||||
|
"esbuild-register"
|
||||||
|
],
|
||||||
|
"spec": "lib/**/*-test.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@serialport/bindings-interface": "^1.2.1",
|
||||||
|
"debug": "^4.3.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
node_modules/@serialport/bindings-cpp/LICENSE
generated
vendored
Normal file
21
node_modules/@serialport/bindings-cpp/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright 2010 Christopher Williams. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
deal in the Software without restriction, including without limitation the
|
||||||
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
||||||
95
node_modules/@serialport/bindings-cpp/README.md
generated
vendored
Normal file
95
node_modules/@serialport/bindings-cpp/README.md
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# @serialport/bindings-cpp
|
||||||
|
|
||||||
|
[](#backers)
|
||||||
|
[](#sponsors)
|
||||||
|
[](https://codecov.io/gh/serialport/bindings-cpp)
|
||||||
|
[](https://github.com/serialport/bindings-cpp/actions/workflows/test.yml)
|
||||||
|
|
||||||
|
Access serial ports with JavaScript. Linux, OSX and Windows. Welcome your robotic JavaScript overlords. Better yet, program them!
|
||||||
|
|
||||||
|
> Go to https://serialport.io/ to learn more, find guides and api documentation.
|
||||||
|
|
||||||
|
## Quick Links
|
||||||
|
|
||||||
|
- 📚 [**Guides**](https://serialport.io/docs/)
|
||||||
|
- [**API Docs**](https://serialport.io/docs/api-serialport)
|
||||||
|
- [`@serialport/bindings-cpp`](https://www.npmjs.com/package/@serialport/bindings-cpp)
|
||||||
|
- 🐛 [Help and Bugs](https://github.com/serialport/node-serialport/issues/new/choose) All serialport issues are pointed to the main serialport repo.
|
||||||
|
|
||||||
|
### Bindings
|
||||||
|
|
||||||
|
The Bindings provide a low level interface to work with your serialport. It is possible to use them alone but it's usually easier to use them with an interface.
|
||||||
|
|
||||||
|
- [`@serialport/bindings-cpp`](https://serialport.io/docs/api-bindings-cpp) bindings for Linux, Mac and Windows
|
||||||
|
- [`@serialport/binding-interface`](https://serialport.io/docs/api-bindings-interface) as an interface to use if you're making your own bindings
|
||||||
|
- [`@serialport/binding-mock`](https://serialport.io/docs/api-binding-mock) for a mock binding package for testing
|
||||||
|
|
||||||
|
## Developing
|
||||||
|
|
||||||
|
### Developing node serialport projects
|
||||||
|
|
||||||
|
1. Clone this repo `git clone git@github.com:serialport/bindings-cpp.git`
|
||||||
|
1. Run `npm install` to setup local package dependencies (run this any time you depend on a package local to this repo)
|
||||||
|
1. Run `npm test` to ensure everything is working properly
|
||||||
|
1. If you have a serial loopback device (TX to RX) you can run run `TEST_PORT=/path/to/port npm test` for a more comprehensive test suite. (Defaults to 115200 baud customize with the TEST_BAUD env.) You can use an arduino with the `test/arduino-echo` sketch.
|
||||||
|
|
||||||
|
### Developing Docs
|
||||||
|
|
||||||
|
See https://github.com/serialport/website
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
SerialPort packages are all [MIT licensed](LICENSE) and all it's dependencies are MIT licensed.
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
SerialPort follows the [Nodebots Code of Conduct](http://nodebots.io/conduct.html). While the code is MIT licensed participation in the community has some rules to make this a good place to work and learn.
|
||||||
|
|
||||||
|
### TLDR
|
||||||
|
|
||||||
|
- Be respectful.
|
||||||
|
- Abusive behavior is never tolerated.
|
||||||
|
- Data published to NodeBots is hosted at the discretion of the service administrators, and may be removed.
|
||||||
|
- Don't build evil robots.
|
||||||
|
- Violations of this code may result in swift and permanent expulsion from the NodeBots community.
|
||||||
|
|
||||||
|
## Governance and Community
|
||||||
|
|
||||||
|
SerialPort is currently employees a [governance](https://medium.com/the-node-js-collection/healthy-open-source-967fa8be7951) with a group of maintainers, committers and contributors, all fixing bugs and adding features and improving documentation. You need not apply to work on SerialPort, all are welcome to join, build, and maintain this project.
|
||||||
|
|
||||||
|
- A Contributor is any individual creating or commenting on an issue or pull request. By participating, this is you.
|
||||||
|
- Committers are contributors who have been given write access to the repository. They can review and merge pull requests.
|
||||||
|
- Maintainers are committers representing the required technical expertise to resolve rare disputes.
|
||||||
|
|
||||||
|
If you have a PR that improves the project people in any or all of the above people will help you land it.
|
||||||
|
|
||||||
|
**Maintainers**
|
||||||
|
|
||||||
|
- [Francis Gulotta](https://twitter.com/reconbot) | [reconbot](https://github.com/reconbot)
|
||||||
|
- [Nick Hehr](https://twitter.com/hipsterbrown) | [hipsterbrown](https://github.com/hipsterbrown)
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||||
|
<a href="https://github.com/serialport/node-serialport/graphs/contributors"><img src="https://opencollective.com/serialport/contributors.svg?width=890&button=false" /></a>
|
||||||
|
|
||||||
|
### Backers
|
||||||
|
|
||||||
|
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/serialport#backer)]
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/serialport#backers" target="_blank"><img src="https://opencollective.com/serialport/backers.svg?width=890"></a>
|
||||||
|
|
||||||
|
### Sponsors
|
||||||
|
|
||||||
|
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/serialport#sponsor)]
|
||||||
|
|
||||||
|
<!-- <a href="https://opencollective.com/serialport/sponsor/0/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/0/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/1/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/2/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/3/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/4/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/5/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/6/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/7/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/8/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/serialport/sponsor/9/website" target="_blank"><img src="https://opencollective.com/serialport/sponsor/9/avatar.svg"></a> -->
|
||||||
80
node_modules/@serialport/bindings-cpp/binding.gyp
generated
vendored
Normal file
80
node_modules/@serialport/bindings-cpp/binding.gyp
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
{
|
||||||
|
'variables': {
|
||||||
|
'openssl_fips': ''
|
||||||
|
},
|
||||||
|
'targets': [{
|
||||||
|
'target_name': 'bindings',
|
||||||
|
'sources': [
|
||||||
|
'src/serialport.cpp'
|
||||||
|
],
|
||||||
|
'include_dirs': ["<!(node -p \"require('node-addon-api').include_dir\")"],
|
||||||
|
'cflags!': [ '-fno-exceptions' ],
|
||||||
|
'cflags_cc!': [ '-fno-exceptions' ],
|
||||||
|
"defines": ["NAPI_CPP_EXCEPTIONS"],
|
||||||
|
'conditions': [
|
||||||
|
['OS=="win"',
|
||||||
|
{
|
||||||
|
'defines': ['CHECK_NODE_MODULE_VERSION'],
|
||||||
|
'sources': [
|
||||||
|
'src/serialport_win.cpp'
|
||||||
|
],
|
||||||
|
'msvs_settings': {
|
||||||
|
'VCCLCompilerTool': {
|
||||||
|
'ExceptionHandling': '1',
|
||||||
|
'DisableSpecificWarnings': [ '4530', '4506' ],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['OS=="mac"',
|
||||||
|
{
|
||||||
|
'sources': [
|
||||||
|
'src/serialport_unix.cpp',
|
||||||
|
'src/poller.cpp',
|
||||||
|
'src/darwin_list.cpp'
|
||||||
|
],
|
||||||
|
'xcode_settings': {
|
||||||
|
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
||||||
|
'MACOSX_DEPLOYMENT_TARGET': '10.9',
|
||||||
|
'OTHER_CFLAGS': [
|
||||||
|
'-arch x86_64',
|
||||||
|
'-arch arm64'
|
||||||
|
],
|
||||||
|
'OTHER_LDFLAGS': [
|
||||||
|
'-framework CoreFoundation',
|
||||||
|
'-framework IOKit',
|
||||||
|
'-arch x86_64',
|
||||||
|
'-arch arm64'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['OS=="linux"',
|
||||||
|
{
|
||||||
|
'sources': [
|
||||||
|
'src/serialport_unix.cpp',
|
||||||
|
'src/poller.cpp',
|
||||||
|
'src/serialport_linux.cpp'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['OS=="android"',
|
||||||
|
{
|
||||||
|
'sources': [
|
||||||
|
'src/serialport_unix.cpp',
|
||||||
|
'src/poller.cpp',
|
||||||
|
'src/serialport_linux.cpp'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['OS!="win"',
|
||||||
|
{
|
||||||
|
'sources': [
|
||||||
|
'src/serialport_unix.cpp',
|
||||||
|
'src/poller.cpp'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
}
|
||||||
39
node_modules/@serialport/bindings-cpp/dist/darwin.d.ts
generated
vendored
Normal file
39
node_modules/@serialport/bindings-cpp/dist/darwin.d.ts
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
import { BindingPortInterface } from '.';
|
||||||
|
import { BindingInterface, OpenOptions, PortStatus, SetOptions, UpdateOptions } from '@serialport/bindings-interface';
|
||||||
|
import { Poller } from './poller';
|
||||||
|
export interface DarwinOpenOptions extends OpenOptions {
|
||||||
|
/** Defaults to none */
|
||||||
|
parity?: 'none' | 'even' | 'odd';
|
||||||
|
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 1 */
|
||||||
|
vmin?: number;
|
||||||
|
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 0 */
|
||||||
|
vtime?: number;
|
||||||
|
}
|
||||||
|
export type DarwinBindingInterface = BindingInterface<DarwinPortBinding, DarwinOpenOptions>;
|
||||||
|
export declare const DarwinBinding: DarwinBindingInterface;
|
||||||
|
/**
|
||||||
|
* The Darwin binding layer for OSX
|
||||||
|
*/
|
||||||
|
export declare class DarwinPortBinding implements BindingPortInterface {
|
||||||
|
readonly openOptions: Required<DarwinOpenOptions>;
|
||||||
|
readonly poller: Poller;
|
||||||
|
private writeOperation;
|
||||||
|
fd: null | number;
|
||||||
|
constructor(fd: number, options: Required<DarwinOpenOptions>);
|
||||||
|
get isOpen(): boolean;
|
||||||
|
close(): Promise<void>;
|
||||||
|
read(buffer: Buffer, offset: number, length: number): Promise<{
|
||||||
|
buffer: Buffer;
|
||||||
|
bytesRead: number;
|
||||||
|
}>;
|
||||||
|
write(buffer: Buffer): Promise<void>;
|
||||||
|
update(options: UpdateOptions): Promise<void>;
|
||||||
|
set(options: SetOptions): Promise<void>;
|
||||||
|
get(): Promise<PortStatus>;
|
||||||
|
getBaudRate(): Promise<{
|
||||||
|
baudRate: number;
|
||||||
|
}>;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
drain(): Promise<void>;
|
||||||
|
}
|
||||||
148
node_modules/@serialport/bindings-cpp/dist/darwin.js
generated
vendored
Normal file
148
node_modules/@serialport/bindings-cpp/dist/darwin.js
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.DarwinPortBinding = exports.DarwinBinding = void 0;
|
||||||
|
const debug_1 = __importDefault(require("debug"));
|
||||||
|
const load_bindings_1 = require("./load-bindings");
|
||||||
|
const poller_1 = require("./poller");
|
||||||
|
const unix_read_1 = require("./unix-read");
|
||||||
|
const unix_write_1 = require("./unix-write");
|
||||||
|
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
||||||
|
exports.DarwinBinding = {
|
||||||
|
list() {
|
||||||
|
debug('list');
|
||||||
|
return (0, load_bindings_1.asyncList)();
|
||||||
|
},
|
||||||
|
async open(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (!options.path) {
|
||||||
|
throw new TypeError('"path" is not a valid port');
|
||||||
|
}
|
||||||
|
if (!options.baudRate) {
|
||||||
|
throw new TypeError('"baudRate" is not a valid baudRate');
|
||||||
|
}
|
||||||
|
debug('open');
|
||||||
|
const openOptions = Object.assign({ vmin: 1, vtime: 0, dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, xon: false, xoff: false, xany: false, hupcl: true }, options);
|
||||||
|
const fd = await (0, load_bindings_1.asyncOpen)(openOptions.path, openOptions);
|
||||||
|
return new DarwinPortBinding(fd, openOptions);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The Darwin binding layer for OSX
|
||||||
|
*/
|
||||||
|
class DarwinPortBinding {
|
||||||
|
constructor(fd, options) {
|
||||||
|
this.fd = fd;
|
||||||
|
this.openOptions = options;
|
||||||
|
this.poller = new poller_1.Poller(fd);
|
||||||
|
this.writeOperation = null;
|
||||||
|
}
|
||||||
|
get isOpen() {
|
||||||
|
return this.fd !== null;
|
||||||
|
}
|
||||||
|
async close() {
|
||||||
|
debug('close');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
const fd = this.fd;
|
||||||
|
this.poller.stop();
|
||||||
|
this.poller.destroy();
|
||||||
|
this.fd = null;
|
||||||
|
await (0, load_bindings_1.asyncClose)(fd);
|
||||||
|
}
|
||||||
|
async read(buffer, offset, length) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
if (typeof offset !== 'number' || isNaN(offset)) {
|
||||||
|
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
||||||
|
}
|
||||||
|
if (typeof length !== 'number' || isNaN(length)) {
|
||||||
|
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
||||||
|
}
|
||||||
|
debug('read');
|
||||||
|
if (buffer.length < offset + length) {
|
||||||
|
throw new Error('buffer is too small');
|
||||||
|
}
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, unix_read_1.unixRead)({ binding: this, buffer, offset, length });
|
||||||
|
}
|
||||||
|
async write(buffer) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
debug('write', buffer.length, 'bytes');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
debug('write', 'error port is not open');
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
this.writeOperation = (async () => {
|
||||||
|
if (buffer.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await (0, unix_write_1.unixWrite)({ binding: this, buffer });
|
||||||
|
this.writeOperation = null;
|
||||||
|
})();
|
||||||
|
return this.writeOperation;
|
||||||
|
}
|
||||||
|
async update(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (typeof options.baudRate !== 'number') {
|
||||||
|
throw new TypeError('"options.baudRate" is not a number');
|
||||||
|
}
|
||||||
|
debug('update');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncUpdate)(this.fd, options);
|
||||||
|
}
|
||||||
|
async set(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
debug('set', options);
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncSet)(this.fd, options);
|
||||||
|
}
|
||||||
|
async get() {
|
||||||
|
debug('get');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, load_bindings_1.asyncGet)(this.fd);
|
||||||
|
}
|
||||||
|
async getBaudRate() {
|
||||||
|
debug('getBaudRate');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
throw new Error('getBaudRate is not implemented on darwin');
|
||||||
|
}
|
||||||
|
async flush() {
|
||||||
|
debug('flush');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncFlush)(this.fd);
|
||||||
|
}
|
||||||
|
async drain() {
|
||||||
|
debug('drain');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await this.writeOperation;
|
||||||
|
await (0, load_bindings_1.asyncDrain)(this.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.DarwinPortBinding = DarwinPortBinding;
|
||||||
7
node_modules/@serialport/bindings-cpp/dist/errors.d.ts
generated
vendored
Normal file
7
node_modules/@serialport/bindings-cpp/dist/errors.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { BindingsErrorInterface } from '@serialport/bindings-interface';
|
||||||
|
export declare class BindingsError extends Error implements BindingsErrorInterface {
|
||||||
|
canceled: boolean;
|
||||||
|
constructor(message: string, { canceled }?: {
|
||||||
|
canceled?: boolean | undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
10
node_modules/@serialport/bindings-cpp/dist/errors.js
generated
vendored
Normal file
10
node_modules/@serialport/bindings-cpp/dist/errors.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.BindingsError = void 0;
|
||||||
|
class BindingsError extends Error {
|
||||||
|
constructor(message, { canceled = false } = {}) {
|
||||||
|
super(message);
|
||||||
|
this.canceled = canceled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.BindingsError = BindingsError;
|
||||||
13
node_modules/@serialport/bindings-cpp/dist/index.d.ts
generated
vendored
Normal file
13
node_modules/@serialport/bindings-cpp/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { DarwinBindingInterface } from './darwin';
|
||||||
|
import { LinuxBindingInterface } from './linux';
|
||||||
|
import { WindowsBindingInterface } from './win32';
|
||||||
|
export * from '@serialport/bindings-interface';
|
||||||
|
export * from './darwin';
|
||||||
|
export * from './linux';
|
||||||
|
export * from './win32';
|
||||||
|
export * from './errors';
|
||||||
|
export type AutoDetectTypes = DarwinBindingInterface | WindowsBindingInterface | LinuxBindingInterface;
|
||||||
|
/**
|
||||||
|
* This is an auto detected binding for your current platform
|
||||||
|
*/
|
||||||
|
export declare function autoDetect(): AutoDetectTypes;
|
||||||
48
node_modules/@serialport/bindings-cpp/dist/index.js
generated
vendored
Normal file
48
node_modules/@serialport/bindings-cpp/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||||
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||||
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.autoDetect = void 0;
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
const debug_1 = __importDefault(require("debug"));
|
||||||
|
const darwin_1 = require("./darwin");
|
||||||
|
const linux_1 = require("./linux");
|
||||||
|
const win32_1 = require("./win32");
|
||||||
|
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
||||||
|
__exportStar(require("@serialport/bindings-interface"), exports);
|
||||||
|
__exportStar(require("./darwin"), exports);
|
||||||
|
__exportStar(require("./linux"), exports);
|
||||||
|
__exportStar(require("./win32"), exports);
|
||||||
|
__exportStar(require("./errors"), exports);
|
||||||
|
/**
|
||||||
|
* This is an auto detected binding for your current platform
|
||||||
|
*/
|
||||||
|
function autoDetect() {
|
||||||
|
switch (process.platform) {
|
||||||
|
case 'win32':
|
||||||
|
debug('loading WindowsBinding');
|
||||||
|
return win32_1.WindowsBinding;
|
||||||
|
case 'darwin':
|
||||||
|
debug('loading DarwinBinding');
|
||||||
|
return darwin_1.DarwinBinding;
|
||||||
|
default:
|
||||||
|
debug('loading LinuxBinding');
|
||||||
|
return linux_1.LinuxBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.autoDetect = autoDetect;
|
||||||
4
node_modules/@serialport/bindings-cpp/dist/linux-list.d.ts
generated
vendored
Normal file
4
node_modules/@serialport/bindings-cpp/dist/linux-list.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
import { spawn } from 'child_process';
|
||||||
|
import { PortInfo } from '@serialport/bindings-interface';
|
||||||
|
export declare function linuxList(spawnCmd?: typeof spawn): Promise<PortInfo[]>;
|
||||||
115
node_modules/@serialport/bindings-cpp/dist/linux-list.js
generated
vendored
Normal file
115
node_modules/@serialport/bindings-cpp/dist/linux-list.js
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.linuxList = void 0;
|
||||||
|
const child_process_1 = require("child_process");
|
||||||
|
const parser_readline_1 = require("@serialport/parser-readline");
|
||||||
|
// get only serial port names
|
||||||
|
function checkPathOfDevice(path) {
|
||||||
|
return /(tty(S|WCH|ACM|USB|AMA|MFD|O|XRUSB)|rfcomm)/.test(path) && path;
|
||||||
|
}
|
||||||
|
function propName(name) {
|
||||||
|
return {
|
||||||
|
DEVNAME: 'path',
|
||||||
|
ID_VENDOR_ENC: 'manufacturer',
|
||||||
|
ID_SERIAL_SHORT: 'serialNumber',
|
||||||
|
ID_VENDOR_ID: 'vendorId',
|
||||||
|
ID_MODEL_ID: 'productId',
|
||||||
|
DEVLINKS: 'pnpId',
|
||||||
|
/**
|
||||||
|
* Workaround for systemd defect
|
||||||
|
* see https://github.com/serialport/bindings-cpp/issues/115
|
||||||
|
*/
|
||||||
|
ID_USB_VENDOR_ENC: 'manufacturer',
|
||||||
|
ID_USB_SERIAL_SHORT: 'serialNumber',
|
||||||
|
ID_USB_VENDOR_ID: 'vendorId',
|
||||||
|
ID_USB_MODEL_ID: 'productId',
|
||||||
|
// End of workaround
|
||||||
|
}[name.toUpperCase()];
|
||||||
|
}
|
||||||
|
function decodeHexEscape(str) {
|
||||||
|
return str.replace(/\\x([a-fA-F0-9]{2})/g, (a, b) => {
|
||||||
|
return String.fromCharCode(parseInt(b, 16));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function propVal(name, val) {
|
||||||
|
if (name === 'pnpId') {
|
||||||
|
const match = val.match(/\/by-id\/([^\s]+)/);
|
||||||
|
return (match === null || match === void 0 ? void 0 : match[1]) || undefined;
|
||||||
|
}
|
||||||
|
if (name === 'manufacturer') {
|
||||||
|
return decodeHexEscape(val);
|
||||||
|
}
|
||||||
|
if (/^0x/.test(val)) {
|
||||||
|
return val.substr(2);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
function linuxList(spawnCmd = child_process_1.spawn) {
|
||||||
|
const ports = [];
|
||||||
|
const udevadm = spawnCmd('udevadm', ['info', '-e']);
|
||||||
|
const lines = udevadm.stdout.pipe(new parser_readline_1.ReadlineParser());
|
||||||
|
let skipPort = false;
|
||||||
|
let port = {
|
||||||
|
path: '',
|
||||||
|
manufacturer: undefined,
|
||||||
|
serialNumber: undefined,
|
||||||
|
pnpId: undefined,
|
||||||
|
locationId: undefined,
|
||||||
|
vendorId: undefined,
|
||||||
|
productId: undefined,
|
||||||
|
};
|
||||||
|
lines.on('data', (line) => {
|
||||||
|
const lineType = line.slice(0, 1);
|
||||||
|
const data = line.slice(3);
|
||||||
|
// new port entry
|
||||||
|
if (lineType === 'P') {
|
||||||
|
port = {
|
||||||
|
path: '',
|
||||||
|
manufacturer: undefined,
|
||||||
|
serialNumber: undefined,
|
||||||
|
pnpId: undefined,
|
||||||
|
locationId: undefined,
|
||||||
|
vendorId: undefined,
|
||||||
|
productId: undefined,
|
||||||
|
};
|
||||||
|
skipPort = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (skipPort) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check dev name and save port if it matches flag to skip the rest of the data if not
|
||||||
|
if (lineType === 'N') {
|
||||||
|
if (checkPathOfDevice(data)) {
|
||||||
|
ports.push(port);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skipPort = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// parse data about each port
|
||||||
|
if (lineType === 'E') {
|
||||||
|
const keyValue = data.match(/^(.+)=(.*)/);
|
||||||
|
if (!keyValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = propName(keyValue[1]);
|
||||||
|
if (!key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
port[key] = propVal(key, keyValue[2]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
udevadm.on('close', (code) => {
|
||||||
|
if (code) {
|
||||||
|
reject(new Error(`Error listing ports udevadm exited with error code: ${code}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
udevadm.on('error', reject);
|
||||||
|
lines.on('error', reject);
|
||||||
|
lines.on('finish', () => resolve(ports));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.linuxList = linuxList;
|
||||||
46
node_modules/@serialport/bindings-cpp/dist/linux.d.ts
generated
vendored
Normal file
46
node_modules/@serialport/bindings-cpp/dist/linux.d.ts
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
import { Poller } from './poller';
|
||||||
|
import { BindingInterface, OpenOptions, PortStatus, SetOptions, UpdateOptions } from '@serialport/bindings-interface';
|
||||||
|
import { BindingPortInterface } from '.';
|
||||||
|
export interface LinuxOpenOptions extends OpenOptions {
|
||||||
|
/** Defaults to none */
|
||||||
|
parity?: 'none' | 'even' | 'odd';
|
||||||
|
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 1 */
|
||||||
|
vmin?: number;
|
||||||
|
/** see [`man termios`](http://linux.die.net/man/3/termios) defaults to 0 */
|
||||||
|
vtime?: number;
|
||||||
|
}
|
||||||
|
export interface LinuxPortStatus extends PortStatus {
|
||||||
|
lowLatency: boolean;
|
||||||
|
}
|
||||||
|
export interface LinuxSetOptions extends SetOptions {
|
||||||
|
/** Low latency mode */
|
||||||
|
lowLatency?: boolean;
|
||||||
|
}
|
||||||
|
export type LinuxBindingInterface = BindingInterface<LinuxPortBinding, LinuxOpenOptions>;
|
||||||
|
export declare const LinuxBinding: LinuxBindingInterface;
|
||||||
|
/**
|
||||||
|
* The linux binding layer
|
||||||
|
*/
|
||||||
|
export declare class LinuxPortBinding implements BindingPortInterface {
|
||||||
|
readonly openOptions: Required<LinuxOpenOptions>;
|
||||||
|
readonly poller: Poller;
|
||||||
|
private writeOperation;
|
||||||
|
fd: number | null;
|
||||||
|
constructor(fd: number, openOptions: Required<LinuxOpenOptions>);
|
||||||
|
get isOpen(): boolean;
|
||||||
|
close(): Promise<void>;
|
||||||
|
read(buffer: Buffer, offset: number, length: number): Promise<{
|
||||||
|
buffer: Buffer;
|
||||||
|
bytesRead: number;
|
||||||
|
}>;
|
||||||
|
write(buffer: Buffer): Promise<void>;
|
||||||
|
update(options: UpdateOptions): Promise<void>;
|
||||||
|
set(options: LinuxSetOptions): Promise<void>;
|
||||||
|
get(): Promise<LinuxPortStatus>;
|
||||||
|
getBaudRate(): Promise<{
|
||||||
|
baudRate: number;
|
||||||
|
}>;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
drain(): Promise<void>;
|
||||||
|
}
|
||||||
150
node_modules/@serialport/bindings-cpp/dist/linux.js
generated
vendored
Normal file
150
node_modules/@serialport/bindings-cpp/dist/linux.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.LinuxPortBinding = exports.LinuxBinding = void 0;
|
||||||
|
const debug_1 = __importDefault(require("debug"));
|
||||||
|
const linux_list_1 = require("./linux-list");
|
||||||
|
const poller_1 = require("./poller");
|
||||||
|
const unix_read_1 = require("./unix-read");
|
||||||
|
const unix_write_1 = require("./unix-write");
|
||||||
|
const load_bindings_1 = require("./load-bindings");
|
||||||
|
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
||||||
|
exports.LinuxBinding = {
|
||||||
|
list() {
|
||||||
|
debug('list');
|
||||||
|
return (0, linux_list_1.linuxList)();
|
||||||
|
},
|
||||||
|
async open(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (!options.path) {
|
||||||
|
throw new TypeError('"path" is not a valid port');
|
||||||
|
}
|
||||||
|
if (!options.baudRate) {
|
||||||
|
throw new TypeError('"baudRate" is not a valid baudRate');
|
||||||
|
}
|
||||||
|
debug('open');
|
||||||
|
const openOptions = Object.assign({ vmin: 1, vtime: 0, dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, xon: false, xoff: false, xany: false, hupcl: true }, options);
|
||||||
|
const fd = await (0, load_bindings_1.asyncOpen)(openOptions.path, openOptions);
|
||||||
|
this.fd = fd;
|
||||||
|
return new LinuxPortBinding(fd, openOptions);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The linux binding layer
|
||||||
|
*/
|
||||||
|
class LinuxPortBinding {
|
||||||
|
constructor(fd, openOptions) {
|
||||||
|
this.fd = fd;
|
||||||
|
this.openOptions = openOptions;
|
||||||
|
this.poller = new poller_1.Poller(fd);
|
||||||
|
this.writeOperation = null;
|
||||||
|
}
|
||||||
|
get isOpen() {
|
||||||
|
return this.fd !== null;
|
||||||
|
}
|
||||||
|
async close() {
|
||||||
|
debug('close');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
const fd = this.fd;
|
||||||
|
this.poller.stop();
|
||||||
|
this.poller.destroy();
|
||||||
|
this.fd = null;
|
||||||
|
await (0, load_bindings_1.asyncClose)(fd);
|
||||||
|
}
|
||||||
|
async read(buffer, offset, length) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
if (typeof offset !== 'number' || isNaN(offset)) {
|
||||||
|
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
||||||
|
}
|
||||||
|
if (typeof length !== 'number' || isNaN(length)) {
|
||||||
|
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
||||||
|
}
|
||||||
|
debug('read');
|
||||||
|
if (buffer.length < offset + length) {
|
||||||
|
throw new Error('buffer is too small');
|
||||||
|
}
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, unix_read_1.unixRead)({ binding: this, buffer, offset, length });
|
||||||
|
}
|
||||||
|
async write(buffer) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
debug('write', buffer.length, 'bytes');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
debug('write', 'error port is not open');
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
this.writeOperation = (async () => {
|
||||||
|
if (buffer.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await (0, unix_write_1.unixWrite)({ binding: this, buffer });
|
||||||
|
this.writeOperation = null;
|
||||||
|
})();
|
||||||
|
return this.writeOperation;
|
||||||
|
}
|
||||||
|
async update(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (typeof options.baudRate !== 'number') {
|
||||||
|
throw new TypeError('"options.baudRate" is not a number');
|
||||||
|
}
|
||||||
|
debug('update');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncUpdate)(this.fd, options);
|
||||||
|
}
|
||||||
|
async set(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
debug('set');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncSet)(this.fd, options);
|
||||||
|
}
|
||||||
|
async get() {
|
||||||
|
debug('get');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, load_bindings_1.asyncGet)(this.fd);
|
||||||
|
}
|
||||||
|
async getBaudRate() {
|
||||||
|
debug('getBaudRate');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, load_bindings_1.asyncGetBaudRate)(this.fd);
|
||||||
|
}
|
||||||
|
async flush() {
|
||||||
|
debug('flush');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncFlush)(this.fd);
|
||||||
|
}
|
||||||
|
async drain() {
|
||||||
|
debug('drain');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await this.writeOperation;
|
||||||
|
await (0, load_bindings_1.asyncDrain)(this.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.LinuxPortBinding = LinuxPortBinding;
|
||||||
11
node_modules/@serialport/bindings-cpp/dist/load-bindings.d.ts
generated
vendored
Normal file
11
node_modules/@serialport/bindings-cpp/dist/load-bindings.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export declare const asyncClose: Function;
|
||||||
|
export declare const asyncDrain: Function;
|
||||||
|
export declare const asyncFlush: Function;
|
||||||
|
export declare const asyncGet: Function;
|
||||||
|
export declare const asyncGetBaudRate: Function;
|
||||||
|
export declare const asyncList: Function;
|
||||||
|
export declare const asyncOpen: Function;
|
||||||
|
export declare const asyncSet: Function;
|
||||||
|
export declare const asyncUpdate: Function;
|
||||||
|
export declare const asyncRead: Function;
|
||||||
|
export declare const asyncWrite: Function;
|
||||||
22
node_modules/@serialport/bindings-cpp/dist/load-bindings.js
generated
vendored
Normal file
22
node_modules/@serialport/bindings-cpp/dist/load-bindings.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.asyncWrite = exports.asyncRead = exports.asyncUpdate = exports.asyncSet = exports.asyncOpen = exports.asyncList = exports.asyncGetBaudRate = exports.asyncGet = exports.asyncFlush = exports.asyncDrain = exports.asyncClose = void 0;
|
||||||
|
const node_gyp_build_1 = __importDefault(require("node-gyp-build"));
|
||||||
|
const util_1 = require("util");
|
||||||
|
const path_1 = require("path");
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const binding = (0, node_gyp_build_1.default)((0, path_1.join)(__dirname, '../'));
|
||||||
|
exports.asyncClose = binding.close ? (0, util_1.promisify)(binding.close) : async () => { throw new Error('"binding.close" Method not implemented'); };
|
||||||
|
exports.asyncDrain = binding.drain ? (0, util_1.promisify)(binding.drain) : async () => { throw new Error('"binding.drain" Method not implemented'); };
|
||||||
|
exports.asyncFlush = binding.flush ? (0, util_1.promisify)(binding.flush) : async () => { throw new Error('"binding.flush" Method not implemented'); };
|
||||||
|
exports.asyncGet = binding.get ? (0, util_1.promisify)(binding.get) : async () => { throw new Error('"binding.get" Method not implemented'); };
|
||||||
|
exports.asyncGetBaudRate = binding.getBaudRate ? (0, util_1.promisify)(binding.getBaudRate) : async () => { throw new Error('"binding.getBaudRate" Method not implemented'); };
|
||||||
|
exports.asyncList = binding.list ? (0, util_1.promisify)(binding.list) : async () => { throw new Error('"binding.list" Method not implemented'); };
|
||||||
|
exports.asyncOpen = binding.open ? (0, util_1.promisify)(binding.open) : async () => { throw new Error('"binding.open" Method not implemented'); };
|
||||||
|
exports.asyncSet = binding.set ? (0, util_1.promisify)(binding.set) : async () => { throw new Error('"binding.set" Method not implemented'); };
|
||||||
|
exports.asyncUpdate = binding.update ? (0, util_1.promisify)(binding.update) : async () => { throw new Error('"binding.update" Method not implemented'); };
|
||||||
|
exports.asyncRead = binding.read ? (0, util_1.promisify)(binding.read) : async () => { throw new Error('"binding.read" Method not implemented'); };
|
||||||
|
exports.asyncWrite = binding.write ? (0, util_1.promisify)(binding.write) : async () => { throw new Error('"binding.write" Method not implemented'); };
|
||||||
40
node_modules/@serialport/bindings-cpp/dist/poller.d.ts
generated
vendored
Normal file
40
node_modules/@serialport/bindings-cpp/dist/poller.d.ts
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
|
interface PollerClass {
|
||||||
|
new (fd: number, cb: (err: Error, flag: number) => void): PollerInstance;
|
||||||
|
}
|
||||||
|
interface PollerInstance {
|
||||||
|
poll(flag: number): void;
|
||||||
|
stop(): void;
|
||||||
|
destroy(): void;
|
||||||
|
}
|
||||||
|
export declare const EVENTS: {
|
||||||
|
UV_READABLE: number;
|
||||||
|
UV_WRITABLE: number;
|
||||||
|
UV_DISCONNECT: number;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Polls unix systems for readable or writable states of a file or serialport
|
||||||
|
*/
|
||||||
|
export declare class Poller extends EventEmitter {
|
||||||
|
poller: PollerInstance;
|
||||||
|
constructor(fd: number, FDPoller?: PollerClass);
|
||||||
|
/**
|
||||||
|
* Wait for the next event to occur
|
||||||
|
* @param {string} event ('readable'|'writable'|'disconnect')
|
||||||
|
* @returns {Poller} returns itself
|
||||||
|
*/
|
||||||
|
once(event: 'readable' | 'writable' | 'disconnect', callback: (err: null | Error) => void): this;
|
||||||
|
/**
|
||||||
|
* Ask the bindings to listen for an event, it is recommend to use `.once()` for easy use
|
||||||
|
* @param {EVENTS} eventFlag polls for an event or group of events based upon a flag.
|
||||||
|
*/
|
||||||
|
poll(eventFlag?: number): void;
|
||||||
|
/**
|
||||||
|
* Stop listening for events and cancel all outstanding listening with an error
|
||||||
|
*/
|
||||||
|
stop(): void;
|
||||||
|
destroy(): void;
|
||||||
|
emitCanceled(): void;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
104
node_modules/@serialport/bindings-cpp/dist/poller.js
generated
vendored
Normal file
104
node_modules/@serialport/bindings-cpp/dist/poller.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.Poller = exports.EVENTS = void 0;
|
||||||
|
const debug_1 = __importDefault(require("debug"));
|
||||||
|
const events_1 = require("events");
|
||||||
|
const path_1 = require("path");
|
||||||
|
const node_gyp_build_1 = __importDefault(require("node-gyp-build"));
|
||||||
|
const errors_1 = require("./errors");
|
||||||
|
const { Poller: PollerBindings } = (0, node_gyp_build_1.default)((0, path_1.join)(__dirname, '../'));
|
||||||
|
const logger = (0, debug_1.default)('serialport/bindings-cpp/poller');
|
||||||
|
exports.EVENTS = {
|
||||||
|
UV_READABLE: 0b0001,
|
||||||
|
UV_WRITABLE: 0b0010,
|
||||||
|
UV_DISCONNECT: 0b0100,
|
||||||
|
};
|
||||||
|
function handleEvent(error, eventFlag) {
|
||||||
|
if (error) {
|
||||||
|
logger('error', error);
|
||||||
|
this.emit('readable', error);
|
||||||
|
this.emit('writable', error);
|
||||||
|
this.emit('disconnect', error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (eventFlag & exports.EVENTS.UV_READABLE) {
|
||||||
|
logger('received "readable"');
|
||||||
|
this.emit('readable', null);
|
||||||
|
}
|
||||||
|
if (eventFlag & exports.EVENTS.UV_WRITABLE) {
|
||||||
|
logger('received "writable"');
|
||||||
|
this.emit('writable', null);
|
||||||
|
}
|
||||||
|
if (eventFlag & exports.EVENTS.UV_DISCONNECT) {
|
||||||
|
logger('received "disconnect"');
|
||||||
|
this.emit('disconnect', null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Polls unix systems for readable or writable states of a file or serialport
|
||||||
|
*/
|
||||||
|
class Poller extends events_1.EventEmitter {
|
||||||
|
constructor(fd, FDPoller = PollerBindings) {
|
||||||
|
logger('Creating poller');
|
||||||
|
super();
|
||||||
|
this.poller = new FDPoller(fd, handleEvent.bind(this));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Wait for the next event to occur
|
||||||
|
* @param {string} event ('readable'|'writable'|'disconnect')
|
||||||
|
* @returns {Poller} returns itself
|
||||||
|
*/
|
||||||
|
once(event, callback) {
|
||||||
|
switch (event) {
|
||||||
|
case 'readable':
|
||||||
|
this.poll(exports.EVENTS.UV_READABLE);
|
||||||
|
break;
|
||||||
|
case 'writable':
|
||||||
|
this.poll(exports.EVENTS.UV_WRITABLE);
|
||||||
|
break;
|
||||||
|
case 'disconnect':
|
||||||
|
this.poll(exports.EVENTS.UV_DISCONNECT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return super.once(event, callback);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Ask the bindings to listen for an event, it is recommend to use `.once()` for easy use
|
||||||
|
* @param {EVENTS} eventFlag polls for an event or group of events based upon a flag.
|
||||||
|
*/
|
||||||
|
poll(eventFlag = 0) {
|
||||||
|
if (eventFlag & exports.EVENTS.UV_READABLE) {
|
||||||
|
logger('Polling for "readable"');
|
||||||
|
}
|
||||||
|
if (eventFlag & exports.EVENTS.UV_WRITABLE) {
|
||||||
|
logger('Polling for "writable"');
|
||||||
|
}
|
||||||
|
if (eventFlag & exports.EVENTS.UV_DISCONNECT) {
|
||||||
|
logger('Polling for "disconnect"');
|
||||||
|
}
|
||||||
|
this.poller.poll(eventFlag);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Stop listening for events and cancel all outstanding listening with an error
|
||||||
|
*/
|
||||||
|
stop() {
|
||||||
|
logger('Stopping poller');
|
||||||
|
this.poller.stop();
|
||||||
|
this.emitCanceled();
|
||||||
|
}
|
||||||
|
destroy() {
|
||||||
|
logger('Destroying poller');
|
||||||
|
this.poller.destroy();
|
||||||
|
this.emitCanceled();
|
||||||
|
}
|
||||||
|
emitCanceled() {
|
||||||
|
const err = new errors_1.BindingsError('Canceled', { canceled: true });
|
||||||
|
this.emit('readable', err);
|
||||||
|
this.emit('writable', err);
|
||||||
|
this.emit('disconnect', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.Poller = Poller;
|
||||||
18
node_modules/@serialport/bindings-cpp/dist/unix-read.d.ts
generated
vendored
Normal file
18
node_modules/@serialport/bindings-cpp/dist/unix-read.d.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
/// <reference types="node" />
|
||||||
|
import { read as fsRead } from 'fs';
|
||||||
|
import { LinuxPortBinding } from './linux';
|
||||||
|
import { DarwinPortBinding } from './darwin';
|
||||||
|
declare const readAsync: typeof fsRead.__promisify__;
|
||||||
|
interface UnixReadOptions {
|
||||||
|
binding: LinuxPortBinding | DarwinPortBinding;
|
||||||
|
buffer: Buffer;
|
||||||
|
offset: number;
|
||||||
|
length: number;
|
||||||
|
fsReadAsync?: typeof readAsync;
|
||||||
|
}
|
||||||
|
export declare const unixRead: ({ binding, buffer, offset, length, fsReadAsync, }: UnixReadOptions) => Promise<{
|
||||||
|
buffer: Buffer;
|
||||||
|
bytesRead: number;
|
||||||
|
}>;
|
||||||
|
export {};
|
||||||
55
node_modules/@serialport/bindings-cpp/dist/unix-read.js
generated
vendored
Normal file
55
node_modules/@serialport/bindings-cpp/dist/unix-read.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.unixRead = void 0;
|
||||||
|
const util_1 = require("util");
|
||||||
|
const fs_1 = require("fs");
|
||||||
|
const errors_1 = require("./errors");
|
||||||
|
const debug_1 = __importDefault(require("debug"));
|
||||||
|
const logger = (0, debug_1.default)('serialport/bindings-cpp/unixRead');
|
||||||
|
const readAsync = (0, util_1.promisify)(fs_1.read);
|
||||||
|
const readable = (binding) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!binding.poller) {
|
||||||
|
throw new Error('No poller on bindings');
|
||||||
|
}
|
||||||
|
binding.poller.once('readable', err => (err ? reject(err) : resolve()));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const unixRead = async ({ binding, buffer, offset, length, fsReadAsync = readAsync, }) => {
|
||||||
|
logger('Starting read');
|
||||||
|
if (!binding.isOpen || !binding.fd) {
|
||||||
|
throw new errors_1.BindingsError('Port is not open', { canceled: true });
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { bytesRead } = await fsReadAsync(binding.fd, buffer, offset, length, null);
|
||||||
|
if (bytesRead === 0) {
|
||||||
|
return (0, exports.unixRead)({ binding, buffer, offset, length, fsReadAsync });
|
||||||
|
}
|
||||||
|
logger('Finished read', bytesRead, 'bytes');
|
||||||
|
return { bytesRead, buffer };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
logger('read error', err);
|
||||||
|
if (err.code === 'EAGAIN' || err.code === 'EWOULDBLOCK' || err.code === 'EINTR') {
|
||||||
|
if (!binding.isOpen) {
|
||||||
|
throw new errors_1.BindingsError('Port is not open', { canceled: true });
|
||||||
|
}
|
||||||
|
logger('waiting for readable because of code:', err.code);
|
||||||
|
await readable(binding);
|
||||||
|
return (0, exports.unixRead)({ binding, buffer, offset, length, fsReadAsync });
|
||||||
|
}
|
||||||
|
const disconnectError = err.code === 'EBADF' || // Bad file number means we got closed
|
||||||
|
err.code === 'ENXIO' || // No such device or address probably usb disconnect
|
||||||
|
err.code === 'UNKNOWN' ||
|
||||||
|
err.errno === -1; // generic error
|
||||||
|
if (disconnectError) {
|
||||||
|
err.disconnect = true;
|
||||||
|
logger('disconnecting', err);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.unixRead = unixRead;
|
||||||
14
node_modules/@serialport/bindings-cpp/dist/unix-write.d.ts
generated
vendored
Normal file
14
node_modules/@serialport/bindings-cpp/dist/unix-write.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
/// <reference types="node" />
|
||||||
|
import { write } from 'fs';
|
||||||
|
import { LinuxPortBinding } from './linux';
|
||||||
|
import { DarwinPortBinding } from './darwin';
|
||||||
|
declare const writeAsync: typeof write.__promisify__;
|
||||||
|
interface UnixWriteOptions {
|
||||||
|
binding: LinuxPortBinding | DarwinPortBinding;
|
||||||
|
buffer: Buffer;
|
||||||
|
offset?: number;
|
||||||
|
fsWriteAsync?: typeof writeAsync;
|
||||||
|
}
|
||||||
|
export declare const unixWrite: ({ binding, buffer, offset, fsWriteAsync }: UnixWriteOptions) => Promise<void>;
|
||||||
|
export {};
|
||||||
56
node_modules/@serialport/bindings-cpp/dist/unix-write.js
generated
vendored
Normal file
56
node_modules/@serialport/bindings-cpp/dist/unix-write.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.unixWrite = void 0;
|
||||||
|
const fs_1 = require("fs");
|
||||||
|
const debug_1 = __importDefault(require("debug"));
|
||||||
|
const util_1 = require("util");
|
||||||
|
const logger = (0, debug_1.default)('serialport/bindings-cpp/unixWrite');
|
||||||
|
const writeAsync = (0, util_1.promisify)(fs_1.write);
|
||||||
|
const writable = (binding) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
binding.poller.once('writable', err => (err ? reject(err) : resolve()));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const unixWrite = async ({ binding, buffer, offset = 0, fsWriteAsync = writeAsync }) => {
|
||||||
|
const bytesToWrite = buffer.length - offset;
|
||||||
|
logger('Starting write', buffer.length, 'bytes offset', offset, 'bytesToWrite', bytesToWrite);
|
||||||
|
if (!binding.isOpen || !binding.fd) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { bytesWritten } = await fsWriteAsync(binding.fd, buffer, offset, bytesToWrite);
|
||||||
|
logger('write returned: wrote', bytesWritten, 'bytes');
|
||||||
|
if (bytesWritten + offset < buffer.length) {
|
||||||
|
if (!binding.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, exports.unixWrite)({ binding, buffer, offset: bytesWritten + offset, fsWriteAsync });
|
||||||
|
}
|
||||||
|
logger('Finished writing', bytesWritten + offset, 'bytes');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
logger('write errored', err);
|
||||||
|
if (err.code === 'EAGAIN' || err.code === 'EWOULDBLOCK' || err.code === 'EINTR') {
|
||||||
|
if (!binding.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
logger('waiting for writable because of code:', err.code);
|
||||||
|
await writable(binding);
|
||||||
|
return (0, exports.unixWrite)({ binding, buffer, offset, fsWriteAsync });
|
||||||
|
}
|
||||||
|
const disconnectError = err.code === 'EBADF' || // Bad file number means we got closed
|
||||||
|
err.code === 'ENXIO' || // No such device or address probably usb disconnect
|
||||||
|
err.code === 'UNKNOWN' ||
|
||||||
|
err.errno === -1; // generic error
|
||||||
|
if (disconnectError) {
|
||||||
|
err.disconnect = true;
|
||||||
|
logger('disconnecting', err);
|
||||||
|
}
|
||||||
|
logger('error', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.unixWrite = unixWrite;
|
||||||
1
node_modules/@serialport/bindings-cpp/dist/win32-sn-parser.d.ts
generated
vendored
Normal file
1
node_modules/@serialport/bindings-cpp/dist/win32-sn-parser.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export declare const serialNumParser: (pnpId?: string) => string | null;
|
||||||
17
node_modules/@serialport/bindings-cpp/dist/win32-sn-parser.js
generated
vendored
Normal file
17
node_modules/@serialport/bindings-cpp/dist/win32-sn-parser.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.serialNumParser = void 0;
|
||||||
|
const PARSERS = [/USB\\(?:.+)\\(.+)/, /FTDIBUS\\(?:.+)\+(.+?)A?\\.+/];
|
||||||
|
const serialNumParser = (pnpId) => {
|
||||||
|
if (!pnpId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const parser of PARSERS) {
|
||||||
|
const sn = pnpId.match(parser);
|
||||||
|
if (sn) {
|
||||||
|
return sn[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
exports.serialNumParser = serialNumParser;
|
||||||
35
node_modules/@serialport/bindings-cpp/dist/win32.d.ts
generated
vendored
Normal file
35
node_modules/@serialport/bindings-cpp/dist/win32.d.ts
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
import { BindingPortInterface } from '.';
|
||||||
|
import { BindingInterface, OpenOptions, PortStatus, SetOptions, UpdateOptions } from '@serialport/bindings-interface';
|
||||||
|
export interface WindowsOpenOptions extends OpenOptions {
|
||||||
|
/** Device parity defaults to none */
|
||||||
|
parity?: 'none' | 'even' | 'odd' | 'mark' | 'space';
|
||||||
|
/** RTS mode defaults to handshake */
|
||||||
|
rtsMode?: 'handshake' | 'enable' | 'toggle';
|
||||||
|
}
|
||||||
|
export type WindowsBindingInterface = BindingInterface<WindowsPortBinding, WindowsOpenOptions>;
|
||||||
|
export declare const WindowsBinding: WindowsBindingInterface;
|
||||||
|
/**
|
||||||
|
* The Windows binding layer
|
||||||
|
*/
|
||||||
|
export declare class WindowsPortBinding implements BindingPortInterface {
|
||||||
|
fd: null | number;
|
||||||
|
writeOperation: Promise<void> | null;
|
||||||
|
openOptions: Required<OpenOptions>;
|
||||||
|
constructor(fd: number, options: Required<OpenOptions>);
|
||||||
|
get isOpen(): boolean;
|
||||||
|
close(): Promise<void>;
|
||||||
|
read(buffer: Buffer, offset: number, length: number): Promise<{
|
||||||
|
buffer: Buffer;
|
||||||
|
bytesRead: number;
|
||||||
|
}>;
|
||||||
|
write(buffer: Buffer): Promise<void>;
|
||||||
|
update(options: UpdateOptions): Promise<void>;
|
||||||
|
set(options: SetOptions): Promise<void>;
|
||||||
|
get(): Promise<PortStatus>;
|
||||||
|
getBaudRate(): Promise<{
|
||||||
|
baudRate: number;
|
||||||
|
}>;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
drain(): Promise<void>;
|
||||||
|
}
|
||||||
162
node_modules/@serialport/bindings-cpp/dist/win32.js
generated
vendored
Normal file
162
node_modules/@serialport/bindings-cpp/dist/win32.js
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.WindowsPortBinding = exports.WindowsBinding = void 0;
|
||||||
|
const debug_1 = __importDefault(require("debug"));
|
||||||
|
const _1 = require(".");
|
||||||
|
const load_bindings_1 = require("./load-bindings");
|
||||||
|
const win32_sn_parser_1 = require("./win32-sn-parser");
|
||||||
|
const debug = (0, debug_1.default)('serialport/bindings-cpp');
|
||||||
|
exports.WindowsBinding = {
|
||||||
|
async list() {
|
||||||
|
const ports = await (0, load_bindings_1.asyncList)();
|
||||||
|
// Grab the serial number from the pnp id
|
||||||
|
return ports.map(port => {
|
||||||
|
if (port.pnpId && !port.serialNumber) {
|
||||||
|
const serialNumber = (0, win32_sn_parser_1.serialNumParser)(port.pnpId);
|
||||||
|
if (serialNumber) {
|
||||||
|
return Object.assign(Object.assign({}, port), { serialNumber });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async open(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (!options.path) {
|
||||||
|
throw new TypeError('"path" is not a valid port');
|
||||||
|
}
|
||||||
|
if (!options.baudRate) {
|
||||||
|
throw new TypeError('"baudRate" is not a valid baudRate');
|
||||||
|
}
|
||||||
|
debug('open');
|
||||||
|
const openOptions = Object.assign({ dataBits: 8, lock: true, stopBits: 1, parity: 'none', rtscts: false, rtsMode: 'handshake', xon: false, xoff: false, xany: false, hupcl: true }, options);
|
||||||
|
const fd = await (0, load_bindings_1.asyncOpen)(openOptions.path, openOptions);
|
||||||
|
return new WindowsPortBinding(fd, openOptions);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The Windows binding layer
|
||||||
|
*/
|
||||||
|
class WindowsPortBinding {
|
||||||
|
constructor(fd, options) {
|
||||||
|
this.fd = fd;
|
||||||
|
this.openOptions = options;
|
||||||
|
this.writeOperation = null;
|
||||||
|
}
|
||||||
|
get isOpen() {
|
||||||
|
return this.fd !== null;
|
||||||
|
}
|
||||||
|
async close() {
|
||||||
|
debug('close');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
const fd = this.fd;
|
||||||
|
this.fd = null;
|
||||||
|
await (0, load_bindings_1.asyncClose)(fd);
|
||||||
|
}
|
||||||
|
async read(buffer, offset, length) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
if (typeof offset !== 'number' || isNaN(offset)) {
|
||||||
|
throw new TypeError(`"offset" is not an integer got "${isNaN(offset) ? 'NaN' : typeof offset}"`);
|
||||||
|
}
|
||||||
|
if (typeof length !== 'number' || isNaN(length)) {
|
||||||
|
throw new TypeError(`"length" is not an integer got "${isNaN(length) ? 'NaN' : typeof length}"`);
|
||||||
|
}
|
||||||
|
debug('read');
|
||||||
|
if (buffer.length < offset + length) {
|
||||||
|
throw new Error('buffer is too small');
|
||||||
|
}
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const bytesRead = await (0, load_bindings_1.asyncRead)(this.fd, buffer, offset, length);
|
||||||
|
return { bytesRead, buffer };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new _1.BindingsError(err.message, { canceled: true });
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async write(buffer) {
|
||||||
|
if (!Buffer.isBuffer(buffer)) {
|
||||||
|
throw new TypeError('"buffer" is not a Buffer');
|
||||||
|
}
|
||||||
|
debug('write', buffer.length, 'bytes');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
debug('write', 'error port is not open');
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
this.writeOperation = (async () => {
|
||||||
|
if (buffer.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncWrite)(this.fd, buffer);
|
||||||
|
this.writeOperation = null;
|
||||||
|
})();
|
||||||
|
return this.writeOperation;
|
||||||
|
}
|
||||||
|
async update(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
if (typeof options.baudRate !== 'number') {
|
||||||
|
throw new TypeError('"options.baudRate" is not a number');
|
||||||
|
}
|
||||||
|
debug('update');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncUpdate)(this.fd, options);
|
||||||
|
}
|
||||||
|
async set(options) {
|
||||||
|
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
||||||
|
throw new TypeError('"options" is not an object');
|
||||||
|
}
|
||||||
|
debug('set', options);
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncSet)(this.fd, options);
|
||||||
|
}
|
||||||
|
async get() {
|
||||||
|
debug('get');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, load_bindings_1.asyncGet)(this.fd);
|
||||||
|
}
|
||||||
|
async getBaudRate() {
|
||||||
|
debug('getBaudRate');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
return (0, load_bindings_1.asyncGetBaudRate)(this.fd);
|
||||||
|
}
|
||||||
|
async flush() {
|
||||||
|
debug('flush');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await (0, load_bindings_1.asyncFlush)(this.fd);
|
||||||
|
}
|
||||||
|
async drain() {
|
||||||
|
debug('drain');
|
||||||
|
if (!this.isOpen) {
|
||||||
|
throw new Error('Port is not open');
|
||||||
|
}
|
||||||
|
await this.writeOperation;
|
||||||
|
await (0, load_bindings_1.asyncDrain)(this.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.WindowsPortBinding = WindowsPortBinding;
|
||||||
21
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/LICENSE
generated
vendored
Normal file
21
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright 2010 Christopher Williams. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
deal in the Software without restriction, including without limitation the
|
||||||
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
||||||
3
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/README.md
generated
vendored
Normal file
3
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# @serialport/parser-delimiter
|
||||||
|
|
||||||
|
See our api docs https://serialport.io/docs/api-parser-delimiter
|
||||||
23
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/dist/index.d.ts
generated
vendored
Normal file
23
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
/// <reference types="node" />
|
||||||
|
import { Transform, TransformCallback, TransformOptions } from 'stream';
|
||||||
|
export interface DelimiterOptions extends TransformOptions {
|
||||||
|
/** The delimiter on which to split incoming data. */
|
||||||
|
delimiter: string | Buffer | number[];
|
||||||
|
/** Should the delimiter be included at the end of data. Defaults to `false` */
|
||||||
|
includeDelimiter?: boolean;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A transform stream that emits data each time a byte sequence is received.
|
||||||
|
* @extends Transform
|
||||||
|
*
|
||||||
|
* To use the `Delimiter` parser, provide a delimiter as a string, buffer, or array of bytes. Runs in O(n) time.
|
||||||
|
*/
|
||||||
|
export declare class DelimiterParser extends Transform {
|
||||||
|
includeDelimiter: boolean;
|
||||||
|
delimiter: Buffer;
|
||||||
|
buffer: Buffer;
|
||||||
|
constructor({ delimiter, includeDelimiter, ...options }: DelimiterOptions);
|
||||||
|
_transform(chunk: Buffer, encoding: BufferEncoding, cb: TransformCallback): void;
|
||||||
|
_flush(cb: TransformCallback): void;
|
||||||
|
}
|
||||||
40
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/dist/index.js
generated
vendored
Normal file
40
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.DelimiterParser = void 0;
|
||||||
|
const stream_1 = require("stream");
|
||||||
|
/**
|
||||||
|
* A transform stream that emits data each time a byte sequence is received.
|
||||||
|
* @extends Transform
|
||||||
|
*
|
||||||
|
* To use the `Delimiter` parser, provide a delimiter as a string, buffer, or array of bytes. Runs in O(n) time.
|
||||||
|
*/
|
||||||
|
class DelimiterParser extends stream_1.Transform {
|
||||||
|
constructor({ delimiter, includeDelimiter = false, ...options }) {
|
||||||
|
super(options);
|
||||||
|
if (delimiter === undefined) {
|
||||||
|
throw new TypeError('"delimiter" is not a bufferable object');
|
||||||
|
}
|
||||||
|
if (delimiter.length === 0) {
|
||||||
|
throw new TypeError('"delimiter" has a 0 or undefined length');
|
||||||
|
}
|
||||||
|
this.includeDelimiter = includeDelimiter;
|
||||||
|
this.delimiter = Buffer.from(delimiter);
|
||||||
|
this.buffer = Buffer.alloc(0);
|
||||||
|
}
|
||||||
|
_transform(chunk, encoding, cb) {
|
||||||
|
let data = Buffer.concat([this.buffer, chunk]);
|
||||||
|
let position;
|
||||||
|
while ((position = data.indexOf(this.delimiter)) !== -1) {
|
||||||
|
this.push(data.slice(0, position + (this.includeDelimiter ? this.delimiter.length : 0)));
|
||||||
|
data = data.slice(position + this.delimiter.length);
|
||||||
|
}
|
||||||
|
this.buffer = data;
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
_flush(cb) {
|
||||||
|
this.push(this.buffer);
|
||||||
|
this.buffer = Buffer.alloc(0);
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.DelimiterParser = DelimiterParser;
|
||||||
25
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/package.json
generated
vendored
Normal file
25
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-delimiter/package.json
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "@serialport/parser-delimiter",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"version": "11.0.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc --build tsconfig-build.json"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/serialport/node-serialport.git"
|
||||||
|
},
|
||||||
|
"funding": "https://opencollective.com/serialport/donate",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "5.0.4"
|
||||||
|
},
|
||||||
|
"gitHead": "6a8202cd947c87ac70c9f3c84d60fe4b5f5d70a9"
|
||||||
|
}
|
||||||
21
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/LICENSE
generated
vendored
Normal file
21
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright 2010 Christopher Williams. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
deal in the Software without restriction, including without limitation the
|
||||||
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
||||||
3
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/README.md
generated
vendored
Normal file
3
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# @serialport/parser-readline
|
||||||
|
|
||||||
|
See our api docs See our api docs https://serialport.io/docs/api-parser-readline
|
||||||
19
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/dist/index.d.ts
generated
vendored
Normal file
19
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
/// <reference types="node" />
|
||||||
|
import { DelimiterParser } from '@serialport/parser-delimiter';
|
||||||
|
import { TransformOptions } from 'stream';
|
||||||
|
export interface ReadlineOptions extends TransformOptions {
|
||||||
|
/** delimiter to use defaults to \n */
|
||||||
|
delimiter?: string | Buffer | number[];
|
||||||
|
/** include the delimiter at the end of the packet defaults to false */
|
||||||
|
includeDelimiter?: boolean;
|
||||||
|
/** Defaults to utf8 */
|
||||||
|
encoding?: BufferEncoding;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A transform stream that emits data after a newline delimiter is received.
|
||||||
|
* @summary To use the `Readline` parser, provide a delimiter (defaults to `\n`). Data is emitted as string controllable by the `encoding` option (defaults to `utf8`).
|
||||||
|
*/
|
||||||
|
export declare class ReadlineParser extends DelimiterParser {
|
||||||
|
constructor(options?: ReadlineOptions);
|
||||||
|
}
|
||||||
22
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/dist/index.js
generated
vendored
Normal file
22
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.ReadlineParser = void 0;
|
||||||
|
const parser_delimiter_1 = require("@serialport/parser-delimiter");
|
||||||
|
/**
|
||||||
|
* A transform stream that emits data after a newline delimiter is received.
|
||||||
|
* @summary To use the `Readline` parser, provide a delimiter (defaults to `\n`). Data is emitted as string controllable by the `encoding` option (defaults to `utf8`).
|
||||||
|
*/
|
||||||
|
class ReadlineParser extends parser_delimiter_1.DelimiterParser {
|
||||||
|
constructor(options) {
|
||||||
|
const opts = {
|
||||||
|
delimiter: Buffer.from('\n', 'utf8'),
|
||||||
|
encoding: 'utf8',
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
if (typeof opts.delimiter === 'string') {
|
||||||
|
opts.delimiter = Buffer.from(opts.delimiter, opts.encoding);
|
||||||
|
}
|
||||||
|
super(opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ReadlineParser = ReadlineParser;
|
||||||
28
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/package.json
generated
vendored
Normal file
28
node_modules/@serialport/bindings-cpp/node_modules/@serialport/parser-readline/package.json
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "@serialport/parser-readline",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"version": "11.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@serialport/parser-delimiter": "11.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc --build tsconfig-build.json"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/serialport/node-serialport.git"
|
||||||
|
},
|
||||||
|
"funding": "https://opencollective.com/serialport/donate",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "5.0.4"
|
||||||
|
},
|
||||||
|
"gitHead": "6a8202cd947c87ac70c9f3c84d60fe4b5f5d70a9"
|
||||||
|
}
|
||||||
113
node_modules/@serialport/bindings-cpp/package.json
generated
vendored
Normal file
113
node_modules/@serialport/bindings-cpp/package.json
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"name": "@serialport/bindings-cpp",
|
||||||
|
"description": "SerialPort Hardware bindings for node serialport written in c++",
|
||||||
|
"version": "12.0.1",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"keywords": [
|
||||||
|
"serialport-binding",
|
||||||
|
"COM",
|
||||||
|
"com port",
|
||||||
|
"hardware",
|
||||||
|
"iot",
|
||||||
|
"modem",
|
||||||
|
"serial port",
|
||||||
|
"serial",
|
||||||
|
"serialport",
|
||||||
|
"tty",
|
||||||
|
"UART"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@serialport/bindings-interface": "1.2.2",
|
||||||
|
"@serialport/parser-readline": "11.0.0",
|
||||||
|
"debug": "4.3.4",
|
||||||
|
"node-addon-api": "7.0.0",
|
||||||
|
"node-gyp-build": "4.6.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@semantic-release/exec": "6.0.3",
|
||||||
|
"@serialport/binding-mock": "10.2.2",
|
||||||
|
"@types/chai": "4.3.5",
|
||||||
|
"@types/chai-subset": "1.3.3",
|
||||||
|
"@types/debug": "4.1.8",
|
||||||
|
"@types/mocha": "10.0.1",
|
||||||
|
"@types/node": "18.16.20",
|
||||||
|
"@typescript-eslint/eslint-plugin": "6.1.0",
|
||||||
|
"@typescript-eslint/parser": "6.1.0",
|
||||||
|
"cc": "3.0.1",
|
||||||
|
"chai": "4.3.7",
|
||||||
|
"chai-subset": "1.6.0",
|
||||||
|
"esbuild": "0.18.15",
|
||||||
|
"esbuild-register": "3.4.2",
|
||||||
|
"eslint": "8.45.0",
|
||||||
|
"mocha": "10.2.0",
|
||||||
|
"node-abi": "3.45.0",
|
||||||
|
"node-gyp": "9.4.0",
|
||||||
|
"nyc": "15.1.0",
|
||||||
|
"prebuildify": "5.0.1",
|
||||||
|
"prebuildify-cross": "5.0.0",
|
||||||
|
"semantic-release": "21.0.7",
|
||||||
|
"shx": "0.3.4",
|
||||||
|
"sinon": "15.2.0",
|
||||||
|
"typescript": "5.1.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -rf dist && tsc -p tsconfig-build.json",
|
||||||
|
"install": "node-gyp-build",
|
||||||
|
"prebuildify": "prebuildify --napi --target 14.0.0 --force --strip --verbose",
|
||||||
|
"prebuildify-cross": "prebuildify-cross --napi --target 14.0.0 --force --strip --verbose",
|
||||||
|
"rebuild": "node-gyp rebuild",
|
||||||
|
"format": "eslint lib test bin --fix",
|
||||||
|
"lint": "eslint lib test bin && cc --verbose",
|
||||||
|
"test": "nyc --reporter lcov --reporter text mocha",
|
||||||
|
"test:arduino": "TEST_PORT=$(./bin/find-arduino.ts) npm test",
|
||||||
|
"test:watch": "mocha -w",
|
||||||
|
"semantic-release": "semantic-release",
|
||||||
|
"typecheck": "tsc"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"gypfile": true,
|
||||||
|
"cc": {
|
||||||
|
"filter": [
|
||||||
|
"legal/copyright",
|
||||||
|
"build/include"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"src/*.cpp",
|
||||||
|
"src/*.h"
|
||||||
|
],
|
||||||
|
"linelength": "120"
|
||||||
|
},
|
||||||
|
"binary": {
|
||||||
|
"napi_versions": [
|
||||||
|
6
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/serialport/bindings-cpp.git"
|
||||||
|
},
|
||||||
|
"funding": "https://opencollective.com/serialport/donate",
|
||||||
|
"changelog": {
|
||||||
|
"labels": {
|
||||||
|
"breaking": ":boom: BREAKING CHANGES :boom:",
|
||||||
|
"feature-request": "Features",
|
||||||
|
"bug": "Bug Fixes",
|
||||||
|
"docs": "Documentation",
|
||||||
|
"internal": "Chores"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mocha": {
|
||||||
|
"bail": true,
|
||||||
|
"require": [
|
||||||
|
"esbuild-register"
|
||||||
|
],
|
||||||
|
"spec": "lib/**/*.test.*"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
node_modules/@serialport/bindings-cpp/prebuilds/android-arm/node.napi.armv7.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/android-arm/node.napi.armv7.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/android-arm64/node.napi.armv8.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/android-arm64/node.napi.armv8.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/darwin-x64+arm64/node.napi.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/darwin-x64+arm64/node.napi.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-arm/node.napi.armv6.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-arm/node.napi.armv6.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-arm/node.napi.armv7.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-arm/node.napi.armv7.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-arm64/node.napi.armv8.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-arm64/node.napi.armv8.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-x64/node.napi.glibc.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-x64/node.napi.glibc.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-x64/node.napi.musl.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/linux-x64/node.napi.musl.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/win32-ia32/node.napi.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/win32-ia32/node.napi.node
generated
vendored
Normal file
Binary file not shown.
BIN
node_modules/@serialport/bindings-cpp/prebuilds/win32-x64/node.napi.node
generated
vendored
Normal file
BIN
node_modules/@serialport/bindings-cpp/prebuilds/win32-x64/node.napi.node
generated
vendored
Normal file
Binary file not shown.
317
node_modules/@serialport/bindings-cpp/src/darwin_list.cpp
generated
vendored
Normal file
317
node_modules/@serialport/bindings-cpp/src/darwin_list.cpp
generated
vendored
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
#include "./darwin_list.h"
|
||||||
|
|
||||||
|
#include <IOKit/IOKitLib.h>
|
||||||
|
#include <IOKit/IOCFPlugIn.h>
|
||||||
|
#include <IOKit/usb/IOUSBLib.h>
|
||||||
|
#include <IOKit/serial/IOSerialKeys.h>
|
||||||
|
|
||||||
|
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <IOKit/serial/ioss.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
uv_mutex_t list_mutex;
|
||||||
|
Boolean lockInitialised = FALSE;
|
||||||
|
|
||||||
|
Napi::Value List(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// callback
|
||||||
|
if (!info[0].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Function callback = info[0].As<Napi::Function>();
|
||||||
|
ListBaton* baton = new ListBaton(callback);
|
||||||
|
snprintf(baton->errorString, sizeof(baton->errorString), "");
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIfNotEmpty(Napi::Object item, std::string key, const char *value) {
|
||||||
|
Napi::Env env = item.Env();
|
||||||
|
Napi::String v8key = Napi::String::New(env, key);
|
||||||
|
if (strlen(value) > 0) {
|
||||||
|
(item).Set(v8key, Napi::String::New(env, value));
|
||||||
|
} else {
|
||||||
|
(item).Set(v8key, env.Undefined());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Function prototypes
|
||||||
|
static kern_return_t FindModems(io_iterator_t *matchingServices);
|
||||||
|
static io_service_t GetUsbDevice(io_service_t service);
|
||||||
|
static stDeviceListItem* GetSerialDevices();
|
||||||
|
|
||||||
|
|
||||||
|
static kern_return_t FindModems(io_iterator_t *matchingServices) {
|
||||||
|
kern_return_t kernResult;
|
||||||
|
CFMutableDictionaryRef classesToMatch;
|
||||||
|
classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
|
||||||
|
if (classesToMatch != NULL) {
|
||||||
|
CFDictionarySetValue(classesToMatch,
|
||||||
|
CFSTR(kIOSerialBSDTypeKey),
|
||||||
|
CFSTR(kIOSerialBSDAllTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, matchingServices);
|
||||||
|
|
||||||
|
return kernResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
static io_service_t GetUsbDevice(io_service_t service) {
|
||||||
|
IOReturn status;
|
||||||
|
io_iterator_t iterator = 0;
|
||||||
|
io_service_t device = 0;
|
||||||
|
|
||||||
|
if (!service) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = IORegistryEntryCreateIterator(service,
|
||||||
|
kIOServicePlane,
|
||||||
|
(kIORegistryIterateParents | kIORegistryIterateRecursively),
|
||||||
|
&iterator);
|
||||||
|
|
||||||
|
if (status == kIOReturnSuccess) {
|
||||||
|
io_service_t currentService;
|
||||||
|
while ((currentService = IOIteratorNext(iterator)) && device == 0) {
|
||||||
|
io_name_t serviceName;
|
||||||
|
status = IORegistryEntryGetNameInPlane(currentService, kIOServicePlane, serviceName);
|
||||||
|
if (status == kIOReturnSuccess && IOObjectConformsTo(currentService, kIOUSBDeviceClassName)) {
|
||||||
|
device = currentService;
|
||||||
|
} else {
|
||||||
|
// Release the service object which is no longer needed
|
||||||
|
(void) IOObjectRelease(currentService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the iterator
|
||||||
|
(void) IOObjectRelease(iterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ExtractUsbInformation(stSerialDevice *serialDevice, IOUSBDeviceInterface **deviceInterface) {
|
||||||
|
kern_return_t kernResult;
|
||||||
|
UInt32 locationID;
|
||||||
|
kernResult = (*deviceInterface)->GetLocationID(deviceInterface, &locationID);
|
||||||
|
if (KERN_SUCCESS == kernResult) {
|
||||||
|
snprintf(serialDevice->locationId, sizeof(serialDevice->locationId), "%08x", locationID);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt16 vendorID;
|
||||||
|
kernResult = (*deviceInterface)->GetDeviceVendor(deviceInterface, &vendorID);
|
||||||
|
if (KERN_SUCCESS == kernResult) {
|
||||||
|
snprintf(serialDevice->vendorId, sizeof(serialDevice->vendorId), "%04x", vendorID);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt16 productID;
|
||||||
|
kernResult = (*deviceInterface)->GetDeviceProduct(deviceInterface, &productID);
|
||||||
|
if (KERN_SUCCESS == kernResult) {
|
||||||
|
snprintf(serialDevice->productId, sizeof(serialDevice->productId), "%04x", productID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static stDeviceListItem* GetSerialDevices() {
|
||||||
|
char bsdPath[MAXPATHLEN];
|
||||||
|
|
||||||
|
io_iterator_t serialPortIterator;
|
||||||
|
FindModems(&serialPortIterator);
|
||||||
|
|
||||||
|
kern_return_t kernResult = KERN_FAILURE;
|
||||||
|
Boolean modemFound = false;
|
||||||
|
|
||||||
|
// Initialize the returned path
|
||||||
|
*bsdPath = '\0';
|
||||||
|
|
||||||
|
stDeviceListItem* devices = NULL;
|
||||||
|
stDeviceListItem* lastDevice = NULL;
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
io_service_t modemService;
|
||||||
|
while ((modemService = IOIteratorNext(serialPortIterator))) {
|
||||||
|
CFTypeRef bsdPathAsCFString;
|
||||||
|
bsdPathAsCFString = IORegistryEntrySearchCFProperty(
|
||||||
|
modemService,
|
||||||
|
kIOServicePlane,
|
||||||
|
CFSTR(kIODialinDeviceKey),
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
kIORegistryIterateRecursively);
|
||||||
|
|
||||||
|
if (bsdPathAsCFString) {
|
||||||
|
Boolean result;
|
||||||
|
|
||||||
|
// Convert the path from a CFString to a C (NUL-terminated)
|
||||||
|
result = CFStringGetCString((CFStringRef) bsdPathAsCFString,
|
||||||
|
bsdPath,
|
||||||
|
sizeof(bsdPath),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
CFRelease(bsdPathAsCFString);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
stDeviceListItem *deviceListItem = reinterpret_cast<stDeviceListItem*>( malloc(sizeof(stDeviceListItem)));
|
||||||
|
stSerialDevice *serialDevice = &(deviceListItem->value);
|
||||||
|
snprintf(serialDevice->port, sizeof(serialDevice->port), "%s", bsdPath);
|
||||||
|
memset(serialDevice->locationId, 0, sizeof(serialDevice->locationId));
|
||||||
|
memset(serialDevice->vendorId, 0, sizeof(serialDevice->vendorId));
|
||||||
|
memset(serialDevice->productId, 0, sizeof(serialDevice->productId));
|
||||||
|
serialDevice->manufacturer[0] = '\0';
|
||||||
|
serialDevice->serialNumber[0] = '\0';
|
||||||
|
deviceListItem->next = NULL;
|
||||||
|
deviceListItem->length = &length;
|
||||||
|
|
||||||
|
if (devices == NULL) {
|
||||||
|
devices = deviceListItem;
|
||||||
|
} else {
|
||||||
|
lastDevice->next = deviceListItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastDevice = deviceListItem;
|
||||||
|
length++;
|
||||||
|
|
||||||
|
modemFound = true;
|
||||||
|
kernResult = KERN_SUCCESS;
|
||||||
|
|
||||||
|
uv_mutex_lock(&list_mutex);
|
||||||
|
|
||||||
|
io_service_t device = GetUsbDevice(modemService);
|
||||||
|
|
||||||
|
if (device) {
|
||||||
|
CFStringRef manufacturerAsCFString = (CFStringRef) IORegistryEntryCreateCFProperty(device,
|
||||||
|
CFSTR(kUSBVendorString),
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (manufacturerAsCFString) {
|
||||||
|
Boolean result;
|
||||||
|
char manufacturer[MAXPATHLEN];
|
||||||
|
|
||||||
|
// Convert from a CFString to a C (NUL-terminated)
|
||||||
|
result = CFStringGetCString(manufacturerAsCFString,
|
||||||
|
manufacturer,
|
||||||
|
sizeof(manufacturer),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
snprintf(serialDevice->manufacturer, sizeof(serialDevice->manufacturer), "%s", manufacturer);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(manufacturerAsCFString);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef serialNumberAsCFString = (CFStringRef) IORegistryEntrySearchCFProperty(device,
|
||||||
|
kIOServicePlane,
|
||||||
|
CFSTR(kUSBSerialNumberString),
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
kIORegistryIterateRecursively);
|
||||||
|
|
||||||
|
if (serialNumberAsCFString) {
|
||||||
|
Boolean result;
|
||||||
|
char serialNumber[MAXPATHLEN];
|
||||||
|
|
||||||
|
// Convert from a CFString to a C (NUL-terminated)
|
||||||
|
result = CFStringGetCString(serialNumberAsCFString,
|
||||||
|
serialNumber,
|
||||||
|
sizeof(serialNumber),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
snprintf(serialDevice->serialNumber, sizeof(serialDevice->serialNumber), "%s", serialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(serialNumberAsCFString);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOCFPlugInInterface **plugInInterface = NULL;
|
||||||
|
SInt32 score;
|
||||||
|
HRESULT res;
|
||||||
|
|
||||||
|
IOUSBDeviceInterface **deviceInterface = NULL;
|
||||||
|
|
||||||
|
kernResult = IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
|
||||||
|
&plugInInterface, &score);
|
||||||
|
|
||||||
|
if ((kIOReturnSuccess == kernResult) && plugInInterface) {
|
||||||
|
// Use the plugin interface to retrieve the device interface.
|
||||||
|
res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
|
||||||
|
reinterpret_cast<LPVOID*> (&deviceInterface));
|
||||||
|
|
||||||
|
// Now done with the plugin interface.
|
||||||
|
(*plugInInterface)->Release(plugInInterface);
|
||||||
|
|
||||||
|
if (!res && deviceInterface != NULL) {
|
||||||
|
// Extract the desired Information
|
||||||
|
ExtractUsbInformation(serialDevice, deviceInterface);
|
||||||
|
|
||||||
|
// Release the Interface
|
||||||
|
(*deviceInterface)->Release(deviceInterface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the device
|
||||||
|
(void) IOObjectRelease(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_mutex_unlock(&list_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the io_service_t now that we are done with it.
|
||||||
|
(void) IOObjectRelease(modemService);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOObjectRelease(serialPortIterator); // Release the iterator.
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListBaton::Execute() {
|
||||||
|
|
||||||
|
if (!lockInitialised) {
|
||||||
|
uv_mutex_init(&list_mutex);
|
||||||
|
lockInitialised = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
stDeviceListItem* devices = GetSerialDevices();
|
||||||
|
if (devices != NULL && *(devices->length) > 0) {
|
||||||
|
stDeviceListItem* next = devices;
|
||||||
|
|
||||||
|
for (int i = 0, len = *(devices->length); i < len; i++) {
|
||||||
|
stSerialDevice device = (* next).value;
|
||||||
|
|
||||||
|
ListResultItem* resultItem = new ListResultItem();
|
||||||
|
resultItem->path = device.port;
|
||||||
|
|
||||||
|
if (*device.locationId) {
|
||||||
|
resultItem->locationId = device.locationId;
|
||||||
|
}
|
||||||
|
if (*device.vendorId) {
|
||||||
|
resultItem->vendorId = device.vendorId;
|
||||||
|
}
|
||||||
|
if (*device.productId) {
|
||||||
|
resultItem->productId = device.productId;
|
||||||
|
}
|
||||||
|
if (*device.manufacturer) {
|
||||||
|
resultItem->manufacturer = device.manufacturer;
|
||||||
|
}
|
||||||
|
if (*device.serialNumber) {
|
||||||
|
resultItem->serialNumber = device.serialNumber;
|
||||||
|
}
|
||||||
|
results.push_back(resultItem);
|
||||||
|
|
||||||
|
stDeviceListItem* current = next;
|
||||||
|
|
||||||
|
if (next->next != NULL) {
|
||||||
|
next = next->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
node_modules/@serialport/bindings-cpp/src/darwin_list.h
generated
vendored
Normal file
68
node_modules/@serialport/bindings-cpp/src/darwin_list.h
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#ifndef PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
|
||||||
|
#define PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
|
||||||
|
#include <sys/param.h> // For MAXPATHLEN
|
||||||
|
#include <napi.h>
|
||||||
|
#include <uv.h>
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define ERROR_STRING_SIZE 1088
|
||||||
|
|
||||||
|
Napi::Value List(const Napi::CallbackInfo& info);
|
||||||
|
void setIfNotEmpty(Napi::Object item, std::string key, const char *value);
|
||||||
|
|
||||||
|
struct ListResultItem {
|
||||||
|
std::string path;
|
||||||
|
std::string manufacturer;
|
||||||
|
std::string serialNumber;
|
||||||
|
std::string pnpId;
|
||||||
|
std::string locationId;
|
||||||
|
std::string vendorId;
|
||||||
|
std::string productId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ListBaton : public Napi::AsyncWorker {
|
||||||
|
ListBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:ListBaton"),
|
||||||
|
errorString() {}
|
||||||
|
std::list<ListResultItem*> results;
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Napi::Array result = Napi::Array::New(env);
|
||||||
|
int i = 0;
|
||||||
|
for (std::list<ListResultItem*>::iterator it = results.begin(); it != results.end(); ++it, i++) {
|
||||||
|
Napi::Object item = Napi::Object::New(env);
|
||||||
|
|
||||||
|
setIfNotEmpty(item, "path", (*it)->path.c_str());
|
||||||
|
setIfNotEmpty(item, "manufacturer", (*it)->manufacturer.c_str());
|
||||||
|
setIfNotEmpty(item, "serialNumber", (*it)->serialNumber.c_str());
|
||||||
|
setIfNotEmpty(item, "pnpId", (*it)->pnpId.c_str());
|
||||||
|
setIfNotEmpty(item, "locationId", (*it)->locationId.c_str());
|
||||||
|
setIfNotEmpty(item, "vendorId", (*it)->vendorId.c_str());
|
||||||
|
setIfNotEmpty(item, "productId", (*it)->productId.c_str());
|
||||||
|
|
||||||
|
(result).Set(i, item);
|
||||||
|
}
|
||||||
|
Callback().Call({env.Null(), result});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SerialDevice {
|
||||||
|
char port[MAXPATHLEN];
|
||||||
|
char locationId[MAXPATHLEN];
|
||||||
|
char vendorId[MAXPATHLEN];
|
||||||
|
char productId[MAXPATHLEN];
|
||||||
|
char manufacturer[MAXPATHLEN];
|
||||||
|
char serialNumber[MAXPATHLEN];
|
||||||
|
} stSerialDevice;
|
||||||
|
|
||||||
|
typedef struct DeviceListItem {
|
||||||
|
struct SerialDevice value;
|
||||||
|
struct DeviceListItem *next;
|
||||||
|
int* length;
|
||||||
|
} stDeviceListItem;
|
||||||
|
|
||||||
|
#endif // PACKAGES_SERIALPORT_SRC_DARWIN_LIST_H_
|
||||||
166
node_modules/@serialport/bindings-cpp/src/poller.cpp
generated
vendored
Normal file
166
node_modules/@serialport/bindings-cpp/src/poller.cpp
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
#include <napi.h>
|
||||||
|
#include <uv.h>
|
||||||
|
#include "./poller.h"
|
||||||
|
|
||||||
|
Poller::Poller (const Napi::CallbackInfo &info) : Napi::ObjectWrap<Poller>(info)
|
||||||
|
{
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[1].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->callback = Napi::Persistent(info[1].As<Napi::Function>());
|
||||||
|
|
||||||
|
this->poll_handle = new uv_poll_t();
|
||||||
|
memset(this->poll_handle, 0, sizeof(uv_poll_t));
|
||||||
|
poll_handle->data = this;
|
||||||
|
int status = uv_poll_init(uv_default_loop(), poll_handle, fd);
|
||||||
|
if (0 != status) {
|
||||||
|
Napi::Error::New(env, uv_strerror(status)).ThrowAsJavaScriptException();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uv_poll_init_success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Poller::~Poller() {
|
||||||
|
// if we call uv_poll_stop after uv_poll_init failed we segfault
|
||||||
|
if (uv_poll_init_success) {
|
||||||
|
uv_poll_stop(poll_handle);
|
||||||
|
uv_unref(reinterpret_cast<uv_handle_t*> (poll_handle));
|
||||||
|
uv_close(reinterpret_cast<uv_handle_t*> (poll_handle), Poller::onClose);
|
||||||
|
} else {
|
||||||
|
delete poll_handle;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Poller::onClose(uv_handle_t* poll_handle) {
|
||||||
|
// fprintf(stdout, "~Poller is closed\n");
|
||||||
|
delete poll_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events can be UV_READABLE | UV_WRITABLE | UV_DISCONNECT
|
||||||
|
void Poller::poll(Napi::Env env, int events) {
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
// fprintf(stdout, "Poller:poll for %d\n", events);
|
||||||
|
this->events = this->events | events;
|
||||||
|
int status = uv_poll_start(this->poll_handle, events, Poller::onData);
|
||||||
|
if (0 != status) {
|
||||||
|
Napi::Error::New(env, uv_strerror(status)).ThrowAsJavaScriptException();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Poller::stop(Napi::Env env) {
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
int status = uv_poll_stop(this->poll_handle);
|
||||||
|
if (0 != status) {
|
||||||
|
Napi::Error::New(env, uv_strerror(status)).ThrowAsJavaScriptException();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Poller::_stop() {
|
||||||
|
return uv_poll_stop(poll_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Poller::onData(uv_poll_t* handle, int status, int events) {
|
||||||
|
Poller* obj = static_cast<Poller*>(handle->data);
|
||||||
|
Napi::Env env = obj->Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
|
||||||
|
// if Error
|
||||||
|
if (0 != status) {
|
||||||
|
// fprintf(stdout, "OnData Error status=%s events=%d\n", uv_strerror(status), events);
|
||||||
|
obj->_stop(); // doesn't matter if this errors
|
||||||
|
obj->callback.Call({Napi::Error::New(env, uv_strerror(status)).Value(), env.Undefined()});
|
||||||
|
} else {
|
||||||
|
// fprintf(stdout, "OnData status=%d events=%d subscribed=%d\n", status, events, obj->events);
|
||||||
|
// remove triggered events from the poll
|
||||||
|
int newEvents = obj->events & ~events;
|
||||||
|
obj->poll(env, newEvents);
|
||||||
|
obj->callback.Call({env.Null(), Napi::Number::New(env, events)});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Object Poller::Init(Napi::Env env, Napi::Object exports) {
|
||||||
|
Napi::Function func = DefineClass(env, "Poller", {
|
||||||
|
StaticMethod<&Poller::New>("New"),
|
||||||
|
InstanceMethod<&Poller::poll>("poll"),
|
||||||
|
InstanceMethod<&Poller::stop>("stop"),
|
||||||
|
InstanceMethod<&Poller::destroy>("destroy"),
|
||||||
|
});
|
||||||
|
|
||||||
|
Napi::FunctionReference* constructor = new Napi::FunctionReference();
|
||||||
|
|
||||||
|
*constructor = Napi::Persistent(func);
|
||||||
|
exports.Set("Poller", func);
|
||||||
|
|
||||||
|
env.SetInstanceData<Napi::FunctionReference>(constructor);
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Poller::New(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "fd must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Value fd = info[0];
|
||||||
|
if (!info[1].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "cb must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Function callback = info[1].As<Napi::Function>();
|
||||||
|
Napi::FunctionReference* constructor = info.Env().GetInstanceData<Napi::FunctionReference>();
|
||||||
|
return constructor->New({fd, callback});
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Poller::poll(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Poller* obj = this;
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "events must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int events = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
obj->poll(env, events);
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Poller::stop(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
this->stop(env);
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Poller::destroy(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Poller* obj = this;
|
||||||
|
// TODO Fix destruction Segfault
|
||||||
|
obj->Reset();
|
||||||
|
// delete obj;
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Napi::FunctionReference & Poller::constructor() {
|
||||||
|
static Napi::FunctionReference my_constructor;
|
||||||
|
// TODO Check if required
|
||||||
|
// my_constructor.SuppressDestruct();
|
||||||
|
return my_constructor;
|
||||||
|
}
|
||||||
35
node_modules/@serialport/bindings-cpp/src/poller.h
generated
vendored
Normal file
35
node_modules/@serialport/bindings-cpp/src/poller.h
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef PACKAGES_SERIALPORT_SRC_POLLER_H_
|
||||||
|
#define PACKAGES_SERIALPORT_SRC_POLLER_H_
|
||||||
|
|
||||||
|
#include <napi.h>
|
||||||
|
#include <uv.h>
|
||||||
|
|
||||||
|
class Poller : public Napi::ObjectWrap<Poller> {
|
||||||
|
public:
|
||||||
|
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
||||||
|
explicit Poller(const Napi::CallbackInfo &info);
|
||||||
|
static Napi::Value New(const Napi::CallbackInfo& info);
|
||||||
|
static void onData(uv_poll_t* handle, int status, int events);
|
||||||
|
static void onClose(uv_handle_t* poll_handle);
|
||||||
|
~Poller();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fd;
|
||||||
|
uv_poll_t* poll_handle = nullptr;
|
||||||
|
Napi::FunctionReference callback;
|
||||||
|
bool uv_poll_init_success = false;
|
||||||
|
|
||||||
|
// can this be read off of poll_handle?
|
||||||
|
int events = 0;
|
||||||
|
|
||||||
|
void poll(Napi::Env env, int events);
|
||||||
|
void stop(Napi::Env env);
|
||||||
|
int _stop();
|
||||||
|
|
||||||
|
Napi::Value poll(const Napi::CallbackInfo& info);
|
||||||
|
Napi::Value stop(const Napi::CallbackInfo& info);
|
||||||
|
Napi::Value destroy(const Napi::CallbackInfo& info);
|
||||||
|
static inline Napi::FunctionReference & constructor();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PACKAGES_SERIALPORT_SRC_POLLER_H_
|
||||||
342
node_modules/@serialport/bindings-cpp/src/serialport.cpp
generated
vendored
Normal file
342
node_modules/@serialport/bindings-cpp/src/serialport.cpp
generated
vendored
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
#include "./serialport.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "./darwin_list.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define strncasecmp strnicmp
|
||||||
|
#include "./serialport_win.h"
|
||||||
|
#else
|
||||||
|
#include "./poller.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Napi::Value getValueFromObject(Napi::Object options, std::string key) {
|
||||||
|
Napi::String str = Napi::String::New(options.Env(), key);
|
||||||
|
return (options).Get(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getIntFromObject(Napi::Object options, std::string key) {
|
||||||
|
return getValueFromObject(options, key).ToNumber().Int64Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getBoolFromObject(Napi::Object options, std::string key) {
|
||||||
|
return getValueFromObject(options, key).ToBoolean().Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::String getStringFromObj(Napi::Object options, std::string key) {
|
||||||
|
return getValueFromObject(options, key).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
double getDoubleFromObject(Napi::Object options, std::string key) {
|
||||||
|
return getValueFromObject(options, key).ToNumber().DoubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Open(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// path
|
||||||
|
if (!info[0].IsString()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be a string").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
std::string path = info[0].ToString().Utf8Value();
|
||||||
|
|
||||||
|
// options
|
||||||
|
if (!info[1].IsObject()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Object options = info[1].ToObject();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[2].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Function callback = info[2].As<Napi::Function>();
|
||||||
|
OpenBaton* baton = new OpenBaton(callback);
|
||||||
|
snprintf(baton->path, sizeof(baton->path), "%s", path.c_str());
|
||||||
|
baton->baudRate = getIntFromObject(options, "baudRate");
|
||||||
|
baton->dataBits = getIntFromObject(options, "dataBits");
|
||||||
|
baton->parity = ToParityEnum(getStringFromObj(options, "parity"));
|
||||||
|
baton->stopBits = ToStopBitEnum(getDoubleFromObject(options, "stopBits"));
|
||||||
|
baton->rtscts = getBoolFromObject(options, "rtscts");
|
||||||
|
baton->rtsMode = ToRtsModeEnum(getStringFromObj(options, "rtsMode"));
|
||||||
|
baton->xon = getBoolFromObject(options, "xon");
|
||||||
|
baton->xoff = getBoolFromObject(options, "xoff");
|
||||||
|
baton->xany = getBoolFromObject(options, "xany");
|
||||||
|
baton->hupcl = getBoolFromObject(options, "hupcl");
|
||||||
|
baton->lock = getBoolFromObject(options, "lock");
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
baton->vmin = getIntFromObject(options, "vmin");
|
||||||
|
baton->vtime = getIntFromObject(options, "vtime");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Update(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// options
|
||||||
|
if (!info[1].IsObject()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Object options = info[1].ToObject();
|
||||||
|
|
||||||
|
if (!(options).Has("baudRate")) {
|
||||||
|
Napi::TypeError::New(env, "\"baudRate\" must be set on options object").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[2].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Function callback = info[2].As<Napi::Function>();
|
||||||
|
ConnectionOptionsBaton* baton = new ConnectionOptionsBaton(callback);
|
||||||
|
|
||||||
|
baton->fd = fd;
|
||||||
|
baton->baudRate = getIntFromObject(options, "baudRate");
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Close(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[1].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Function callback = info[1].As<Napi::Function>();
|
||||||
|
CloseBaton* baton = new CloseBaton(callback);
|
||||||
|
baton->fd = info[0].ToNumber().Int64Value();;
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Flush(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[1].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Function callback = info[1].As<Napi::Function>();
|
||||||
|
|
||||||
|
FlushBaton* baton = new FlushBaton(callback);
|
||||||
|
baton->fd = fd;
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Set(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// options
|
||||||
|
if (!info[1].IsObject()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be an object").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Object options = info[1].ToObject();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[2].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Function callback = info[2].As<Napi::Function>();
|
||||||
|
|
||||||
|
SetBaton* baton = new SetBaton(callback);
|
||||||
|
baton->fd = fd;
|
||||||
|
baton->brk = getBoolFromObject(options, "brk");
|
||||||
|
baton->rts = getBoolFromObject(options, "rts");
|
||||||
|
baton->cts = getBoolFromObject(options, "cts");
|
||||||
|
baton->dtr = getBoolFromObject(options, "dtr");
|
||||||
|
baton->dsr = getBoolFromObject(options, "dsr");
|
||||||
|
baton->lowLatency = getBoolFromObject(options, "lowLatency");
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Get(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[1].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Function callback = info[1].As<Napi::Function>();
|
||||||
|
|
||||||
|
GetBaton* baton = new GetBaton(callback);
|
||||||
|
baton->fd = fd;
|
||||||
|
baton->cts = false;
|
||||||
|
baton->dsr = false;
|
||||||
|
baton->dcd = false;
|
||||||
|
baton->lowLatency = false;
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value GetBaudRate(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[1].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Function callback = info[1].As<Napi::Function>();
|
||||||
|
GetBaudRateBaton* baton = new GetBaudRateBaton(callback);
|
||||||
|
baton->fd = fd;
|
||||||
|
baton->baudRate = 0;
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Drain(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[1].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Function callback = info[1].As<Napi::Function>();
|
||||||
|
DrainBaton* baton = new DrainBaton(callback);
|
||||||
|
baton->fd = fd;
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SerialPortParity ToParityEnum(const Napi::String& napistr) {
|
||||||
|
auto tmp = napistr.Utf8Value();
|
||||||
|
const char* str = tmp.c_str();
|
||||||
|
|
||||||
|
size_t count = strlen(str);
|
||||||
|
SerialPortParity parity = SERIALPORT_PARITY_NONE;
|
||||||
|
if (!strncasecmp(str, "none", count)) {
|
||||||
|
parity = SERIALPORT_PARITY_NONE;
|
||||||
|
} else if (!strncasecmp(str, "even", count)) {
|
||||||
|
parity = SERIALPORT_PARITY_EVEN;
|
||||||
|
} else if (!strncasecmp(str, "mark", count)) {
|
||||||
|
parity = SERIALPORT_PARITY_MARK;
|
||||||
|
} else if (!strncasecmp(str, "odd", count)) {
|
||||||
|
parity = SERIALPORT_PARITY_ODD;
|
||||||
|
} else if (!strncasecmp(str, "space", count)) {
|
||||||
|
parity = SERIALPORT_PARITY_SPACE;
|
||||||
|
}
|
||||||
|
return parity;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SerialPortStopBits ToStopBitEnum(double stopBits) {
|
||||||
|
if (stopBits > 1.4 && stopBits < 1.6) {
|
||||||
|
return SERIALPORT_STOPBITS_ONE_FIVE;
|
||||||
|
}
|
||||||
|
if (stopBits == 2) {
|
||||||
|
return SERIALPORT_STOPBITS_TWO;
|
||||||
|
}
|
||||||
|
return SERIALPORT_STOPBITS_ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SerialPortRtsMode ToRtsModeEnum(const Napi::String& napistr) {
|
||||||
|
auto tmp = napistr.Utf8Value();
|
||||||
|
const char* str = tmp.c_str();
|
||||||
|
|
||||||
|
size_t count = strlen(str);
|
||||||
|
SerialPortRtsMode mode = SERIALPORT_RTSMODE_HANDSHAKE;
|
||||||
|
if (!strncasecmp(str, "enable", count)) {
|
||||||
|
mode = SERIALPORT_RTSMODE_ENABLE;
|
||||||
|
} else if (!strncasecmp(str, "handshake", count)) {
|
||||||
|
mode = SERIALPORT_RTSMODE_HANDSHAKE;
|
||||||
|
} else if (!strncasecmp(str, "toggle", count)) {
|
||||||
|
mode = SERIALPORT_RTSMODE_TOGGLE;
|
||||||
|
}
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Object init(Napi::Env env, Napi::Object exports) {
|
||||||
|
exports.Set("set", Napi::Function::New(env, Set));
|
||||||
|
exports.Set("get", Napi::Function::New(env, Get));
|
||||||
|
exports.Set("getBaudRate", Napi::Function::New(env, GetBaudRate));
|
||||||
|
exports.Set("open", Napi::Function::New(env, Open));
|
||||||
|
exports.Set("update", Napi::Function::New(env, Update));
|
||||||
|
exports.Set("close", Napi::Function::New(env, Close));
|
||||||
|
exports.Set("flush", Napi::Function::New(env, Flush));
|
||||||
|
exports.Set("drain", Napi::Function::New(env, Drain));
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
exports.Set("list", Napi::Function::New(env, List));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
exports.Set("write", Napi::Function::New(env, Write));
|
||||||
|
exports.Set("read", Napi::Function::New(env, Read));
|
||||||
|
exports.Set("list", Napi::Function::New(env, List));
|
||||||
|
#else
|
||||||
|
Poller::Init(env, exports);
|
||||||
|
#endif
|
||||||
|
return exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_API_MODULE(serialport, init);
|
||||||
202
node_modules/@serialport/bindings-cpp/src/serialport.h
generated
vendored
Normal file
202
node_modules/@serialport/bindings-cpp/src/serialport.h
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
#ifndef PACKAGES_SERIALPORT_SRC_SERIALPORT_H_
|
||||||
|
#define PACKAGES_SERIALPORT_SRC_SERIALPORT_H_
|
||||||
|
|
||||||
|
// Workaround for electron 11 abi issue https://github.com/serialport/node-serialport/issues/2191
|
||||||
|
// TODO Replace with ABI stable runtime check (per https://github.com/serialport/node-serialport/pull/2305#discussion_r697542996)
|
||||||
|
#include <node_version.h>
|
||||||
|
#if CHECK_NODE_API_MODULE_VERSION && NODE_API_MODULE_VERSION == 85
|
||||||
|
#define V8_REVERSE_JSARGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <napi.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define ERROR_STRING_SIZE 1088
|
||||||
|
|
||||||
|
Napi::Value Open(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value Update(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value Close(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value Flush(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value Set(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value Get(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value GetBaudRate(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value Drain(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
enum SerialPortParity {
|
||||||
|
SERIALPORT_PARITY_NONE = 1,
|
||||||
|
SERIALPORT_PARITY_MARK = 2,
|
||||||
|
SERIALPORT_PARITY_EVEN = 3,
|
||||||
|
SERIALPORT_PARITY_ODD = 4,
|
||||||
|
SERIALPORT_PARITY_SPACE = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SerialPortStopBits {
|
||||||
|
SERIALPORT_STOPBITS_ONE = 1,
|
||||||
|
SERIALPORT_STOPBITS_ONE_FIVE = 2,
|
||||||
|
SERIALPORT_STOPBITS_TWO = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SerialPortRtsMode {
|
||||||
|
SERIALPORT_RTSMODE_ENABLE = 1,
|
||||||
|
SERIALPORT_RTSMODE_HANDSHAKE = 2,
|
||||||
|
SERIALPORT_RTSMODE_TOGGLE = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
SerialPortParity ToParityEnum(const Napi::String& str);
|
||||||
|
SerialPortStopBits ToStopBitEnum(double stopBits);
|
||||||
|
SerialPortRtsMode ToRtsModeEnum(const Napi::String& str);
|
||||||
|
|
||||||
|
struct OpenBaton : public Napi::AsyncWorker {
|
||||||
|
OpenBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:OpenBaton"),
|
||||||
|
errorString(), path() {}
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
char path[1024];
|
||||||
|
int fd = 0;
|
||||||
|
int result = 0;
|
||||||
|
int baudRate = 0;
|
||||||
|
int dataBits = 0;
|
||||||
|
bool rtscts = false;
|
||||||
|
bool xon = false;
|
||||||
|
bool xoff = false;
|
||||||
|
bool xany = false;
|
||||||
|
bool hupcl = false;
|
||||||
|
bool lock = false;
|
||||||
|
SerialPortParity parity;
|
||||||
|
SerialPortStopBits stopBits;
|
||||||
|
SerialPortRtsMode rtsMode;
|
||||||
|
#ifndef WIN32
|
||||||
|
uint8_t vmin = 0;
|
||||||
|
uint8_t vtime = 0;
|
||||||
|
#endif
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Callback().Call({env.Null(), Napi::Number::New(env, result)});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConnectionOptions {
|
||||||
|
ConnectionOptions() : errorString() {}
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
int fd = 0;
|
||||||
|
int baudRate = 0;
|
||||||
|
};
|
||||||
|
struct ConnectionOptionsBaton : ConnectionOptions , Napi::AsyncWorker {
|
||||||
|
ConnectionOptionsBaton(Napi::Function& callback) : ConnectionOptions() , Napi::AsyncWorker(callback, "node-serialport:ConnectionOptionsBaton") {}
|
||||||
|
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Callback().Call({env.Null()});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SetBaton : public Napi::AsyncWorker {
|
||||||
|
SetBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:SetBaton"),
|
||||||
|
errorString() {}
|
||||||
|
int fd = 0;
|
||||||
|
int result = 0;
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
bool rts = false;
|
||||||
|
bool cts = false;
|
||||||
|
bool dtr = false;
|
||||||
|
bool dsr = false;
|
||||||
|
bool brk = false;
|
||||||
|
bool lowLatency = false;
|
||||||
|
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Callback().Call({env.Null()});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GetBaton : public Napi::AsyncWorker {
|
||||||
|
GetBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:GetBaton"),
|
||||||
|
errorString() {}
|
||||||
|
int fd = 0;
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
bool cts = false;
|
||||||
|
bool dsr = false;
|
||||||
|
bool dcd = false;
|
||||||
|
bool lowLatency = false;
|
||||||
|
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Napi::Object results = Napi::Object::New(env);
|
||||||
|
results.Set("cts", cts);
|
||||||
|
results.Set("dsr", dsr);
|
||||||
|
results.Set("dcd", dcd);
|
||||||
|
results.Set("lowLatency", lowLatency);
|
||||||
|
Callback().Call({env.Null(), results});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GetBaudRateBaton : public Napi::AsyncWorker {
|
||||||
|
GetBaudRateBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:GetBaudRateBaton"),
|
||||||
|
errorString() {}
|
||||||
|
int fd = 0;
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
int baudRate = 0;
|
||||||
|
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Napi::Object results = Napi::Object::New(env);
|
||||||
|
(results).Set(Napi::String::New(env, "baudRate"), Napi::Number::New(env, baudRate));
|
||||||
|
Callback().Call({env.Null(),results});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VoidBaton : public Napi::AsyncWorker {
|
||||||
|
VoidBaton(Napi::Function& callback, const char *resource_name) : Napi::AsyncWorker(callback, resource_name),
|
||||||
|
errorString() {}
|
||||||
|
int fd = 0;
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Callback().Call({env.Null()});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CloseBaton : VoidBaton {
|
||||||
|
CloseBaton(Napi::Function& callback) : VoidBaton(callback, "node-serialport:CloseBaton") {}
|
||||||
|
void Execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrainBaton : VoidBaton {
|
||||||
|
DrainBaton(Napi::Function& callback) : VoidBaton(callback, "node-serialport:DrainBaton") {}
|
||||||
|
void Execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FlushBaton : VoidBaton {
|
||||||
|
FlushBaton(Napi::Function& callback) : VoidBaton(callback, "node-serialport:FlushBaton") {}
|
||||||
|
void Execute() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
int setup(int fd, OpenBaton *data);
|
||||||
|
int setBaudRate(ConnectionOptions *data);
|
||||||
|
#endif // PACKAGES_SERIALPORT_SRC_SERIALPORT_H_
|
||||||
76
node_modules/@serialport/bindings-cpp/src/serialport_linux.cpp
generated
vendored
Executable file
76
node_modules/@serialport/bindings-cpp/src/serialport_linux.cpp
generated
vendored
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <asm/ioctls.h>
|
||||||
|
#include <asm/termbits.h>
|
||||||
|
#include <linux/serial.h>
|
||||||
|
|
||||||
|
// Uses the termios2 interface to set nonstandard baud rates
|
||||||
|
int linuxSetCustomBaudRate(const int fd, const unsigned int baudrate) {
|
||||||
|
struct termios2 t;
|
||||||
|
|
||||||
|
if (ioctl(fd, TCGETS2, &t) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.c_cflag &= ~CBAUD;
|
||||||
|
t.c_cflag |= BOTHER;
|
||||||
|
t.c_ospeed = t.c_ispeed = baudrate;
|
||||||
|
|
||||||
|
if (ioctl(fd, TCSETS2, &t) == -1) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses termios2 interface to retrieve system reported baud rate
|
||||||
|
int linuxGetSystemBaudRate(const int fd, int* const outbaud) {
|
||||||
|
struct termios2 t;
|
||||||
|
|
||||||
|
if (ioctl(fd, TCGETS2, &t) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outbaud = static_cast<int>(t.c_ospeed);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int linuxSetLowLatencyMode(const int fd, const bool enable) {
|
||||||
|
struct serial_struct ss;
|
||||||
|
|
||||||
|
if (ioctl(fd, TIOCGSERIAL, &ss) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ss.flags & ASYNC_LOW_LATENCY) == enable) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
ss.flags |= ASYNC_LOW_LATENCY;
|
||||||
|
} else {
|
||||||
|
ss.flags &= ~ASYNC_LOW_LATENCY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, TIOCSSERIAL, &ss) == -1) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int linuxGetLowLatencyMode(const int fd, bool* const enabled) {
|
||||||
|
struct serial_struct ss;
|
||||||
|
|
||||||
|
if (ioctl(fd, TIOCGSERIAL, &ss) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*enabled = ss.flags & ASYNC_LOW_LATENCY;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
10
node_modules/@serialport/bindings-cpp/src/serialport_linux.h
generated
vendored
Executable file
10
node_modules/@serialport/bindings-cpp/src/serialport_linux.h
generated
vendored
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef PACKAGES_SERIALPORT_SRC_SERIALPORT_LINUX_H_
|
||||||
|
#define PACKAGES_SERIALPORT_SRC_SERIALPORT_LINUX_H_
|
||||||
|
|
||||||
|
int linuxSetCustomBaudRate(const int fd, const unsigned int baudrate);
|
||||||
|
int linuxGetSystemBaudRate(const int fd, int* const outbaud);
|
||||||
|
int linuxSetLowLatencyMode(const int fd, const bool enable);
|
||||||
|
int linuxGetLowLatencyMode(const int fd, bool* const enabled);
|
||||||
|
|
||||||
|
#endif // PACKAGES_SERIALPORT_SRC_SERIALPORT_LINUX_H_
|
||||||
|
|
||||||
482
node_modules/@serialport/bindings-cpp/src/serialport_unix.cpp
generated
vendored
Normal file
482
node_modules/@serialport/bindings-cpp/src/serialport_unix.cpp
generated
vendored
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
#include "serialport_unix.h"
|
||||||
|
#include "serialport.h"
|
||||||
|
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <IOKit/serial/ioss.h>
|
||||||
|
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/serial.h>
|
||||||
|
#include "serialport_linux.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ToStopBitsConstant(SerialPortStopBits stopBits);
|
||||||
|
|
||||||
|
int ToBaudConstant(int baudRate) {
|
||||||
|
switch (baudRate) {
|
||||||
|
case 0: return B0;
|
||||||
|
case 50: return B50;
|
||||||
|
case 75: return B75;
|
||||||
|
case 110: return B110;
|
||||||
|
case 134: return B134;
|
||||||
|
case 150: return B150;
|
||||||
|
case 200: return B200;
|
||||||
|
case 300: return B300;
|
||||||
|
case 600: return B600;
|
||||||
|
case 1200: return B1200;
|
||||||
|
case 1800: return B1800;
|
||||||
|
case 2400: return B2400;
|
||||||
|
case 4800: return B4800;
|
||||||
|
case 9600: return B9600;
|
||||||
|
case 19200: return B19200;
|
||||||
|
case 38400: return B38400;
|
||||||
|
case 57600: return B57600;
|
||||||
|
case 115200: return B115200;
|
||||||
|
case 230400: return B230400;
|
||||||
|
#if defined(__linux__)
|
||||||
|
case 460800: return B460800;
|
||||||
|
case 500000: return B500000;
|
||||||
|
case 576000: return B576000;
|
||||||
|
case 921600: return B921600;
|
||||||
|
case 1000000: return B1000000;
|
||||||
|
case 1152000: return B1152000;
|
||||||
|
case 1500000: return B1500000;
|
||||||
|
case 2000000: return B2000000;
|
||||||
|
case 2500000: return B2500000;
|
||||||
|
case 3000000: return B3000000;
|
||||||
|
case 3500000: return B3500000;
|
||||||
|
case 4000000: return B4000000;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ToDataBitsConstant(int dataBits) {
|
||||||
|
switch (dataBits) {
|
||||||
|
case 8: default: return CS8;
|
||||||
|
case 7: return CS7;
|
||||||
|
case 6: return CS6;
|
||||||
|
case 5: return CS5;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenBaton::Execute() {
|
||||||
|
|
||||||
|
int flags = (O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC | O_SYNC);
|
||||||
|
int fd = open(path, flags);
|
||||||
|
|
||||||
|
if (-1 == fd) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot open %s", strerror(errno), path);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == setup(fd, this)) {
|
||||||
|
this->SetError(errorString);
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionOptionsBaton::Execute() {
|
||||||
|
// lookup the standard baudrates from the table
|
||||||
|
int baudRate = ToBaudConstant(this->baudRate);
|
||||||
|
|
||||||
|
// get port options
|
||||||
|
struct termios options;
|
||||||
|
if (-1 == tcgetattr(fd, &options)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s setting custom baud rate of %d", strerror(errno), baudRate);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a custom baud rate on linux you can do the following trick with B38400
|
||||||
|
#if defined(__linux__) && defined(ASYNC_SPD_CUST)
|
||||||
|
if (baudRate == -1) {
|
||||||
|
int err = linuxSetCustomBaudRate(fd, baudRate);
|
||||||
|
|
||||||
|
if (err == -1) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s || while retrieving termios2 info", strerror(errno));
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
} else if (err == -2) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s || while setting custom baud rate of %d", strerror(errno), baudRate);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// On OS X, starting with Tiger, we can set a custom baud rate with ioctl
|
||||||
|
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
|
||||||
|
if (-1 == baudRate) {
|
||||||
|
speed_t speed = baudRate;
|
||||||
|
if (-1 == ioctl(fd, IOSSIOSPEED, &speed)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s calling ioctl(.., IOSSIOSPEED, %ld )", strerror(errno), speed);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
tcflush(fd, TCIOFLUSH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (-1 == baudRate) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error baud rate of %d is not supported on your platform", baudRate);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a good baud rate set it and lets go
|
||||||
|
cfsetospeed(&options, baudRate);
|
||||||
|
cfsetispeed(&options, baudRate);
|
||||||
|
// throw away all the buffered data
|
||||||
|
tcflush(fd, TCIOFLUSH);
|
||||||
|
// make the changes now
|
||||||
|
tcsetattr(fd, TCSANOW, &options);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setup(int fd, OpenBaton *data) {
|
||||||
|
int dataBits = ToDataBitsConstant(data->dataBits);
|
||||||
|
if (-1 == dataBits) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString),"Invalid data bits setting %d", data->dataBits);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snow Leopard doesn't have O_CLOEXEC
|
||||||
|
if (-1 == fcntl(fd, F_SETFD, FD_CLOEXEC)) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString), "Error %s Cannot open %s", strerror(errno), data->path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get port configuration for modification
|
||||||
|
struct termios options;
|
||||||
|
tcgetattr(fd, &options);
|
||||||
|
|
||||||
|
// IGNPAR: ignore bytes with parity errors
|
||||||
|
options.c_iflag = IGNPAR;
|
||||||
|
|
||||||
|
// ICRNL: map CR to NL (otherwise a CR input on the other computer will not terminate input)
|
||||||
|
// Future potential option
|
||||||
|
// options.c_iflag = ICRNL;
|
||||||
|
// otherwise make device raw (no other input processing)
|
||||||
|
|
||||||
|
// Specify data bits
|
||||||
|
options.c_cflag &= ~CSIZE;
|
||||||
|
options.c_cflag |= dataBits;
|
||||||
|
|
||||||
|
options.c_cflag &= ~(CRTSCTS);
|
||||||
|
|
||||||
|
if (data->rtscts) {
|
||||||
|
options.c_cflag |= CRTSCTS;
|
||||||
|
// evaluate specific flow control options
|
||||||
|
}
|
||||||
|
|
||||||
|
options.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||||
|
|
||||||
|
if (data->xon) {
|
||||||
|
options.c_iflag |= IXON;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->xoff) {
|
||||||
|
options.c_iflag |= IXOFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->xany) {
|
||||||
|
options.c_iflag |= IXANY;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data->parity) {
|
||||||
|
case SERIALPORT_PARITY_NONE:
|
||||||
|
options.c_cflag &= ~PARENB;
|
||||||
|
// options.c_cflag &= ~CSTOPB;
|
||||||
|
// options.c_cflag &= ~CSIZE;
|
||||||
|
// options.c_cflag |= CS8;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_PARITY_ODD:
|
||||||
|
options.c_cflag |= PARENB;
|
||||||
|
options.c_cflag |= PARODD;
|
||||||
|
// options.c_cflag &= ~CSTOPB;
|
||||||
|
// options.c_cflag &= ~CSIZE;
|
||||||
|
// options.c_cflag |= CS7;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_PARITY_EVEN:
|
||||||
|
options.c_cflag |= PARENB;
|
||||||
|
options.c_cflag &= ~PARODD;
|
||||||
|
// options.c_cflag &= ~CSTOPB;
|
||||||
|
// options.c_cflag &= ~CSIZE;
|
||||||
|
// options.c_cflag |= CS7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString), "Invalid parity setting %d", data->parity);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data->stopBits) {
|
||||||
|
case SERIALPORT_STOPBITS_ONE:
|
||||||
|
options.c_cflag &= ~CSTOPB;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_STOPBITS_TWO:
|
||||||
|
options.c_cflag |= CSTOPB;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString), "Invalid stop bits setting %d", data->stopBits);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.c_cflag |= CLOCAL; // ignore status lines
|
||||||
|
options.c_cflag |= CREAD; // enable receiver
|
||||||
|
if (data->hupcl) {
|
||||||
|
options.c_cflag |= HUPCL; // drop DTR (i.e. hangup) on close
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw output
|
||||||
|
options.c_oflag = 0;
|
||||||
|
|
||||||
|
// ICANON makes partial lines not readable. It should be optional.
|
||||||
|
// It works with ICRNL.
|
||||||
|
options.c_lflag = 0; // ICANON;
|
||||||
|
options.c_cc[VMIN]= data->vmin;
|
||||||
|
options.c_cc[VTIME]= data->vtime;
|
||||||
|
|
||||||
|
// Note that tcsetattr() returns success if any of the requested changes could be successfully carried out.
|
||||||
|
// Therefore, when making multiple changes it may be necessary to follow this call with a further call to
|
||||||
|
// tcgetattr() to check that all changes have been performed successfully.
|
||||||
|
// This also fails on OSX
|
||||||
|
tcsetattr(fd, TCSANOW, &options);
|
||||||
|
|
||||||
|
if (data->lock) {
|
||||||
|
if (-1 == flock(fd, LOCK_EX | LOCK_NB)) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString), "Error %s Cannot lock port", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the connection options into the ConnectionOptionsBaton to set the baud rate
|
||||||
|
ConnectionOptions* connectionOptions = new ConnectionOptions();
|
||||||
|
connectionOptions->fd = fd;
|
||||||
|
connectionOptions->baudRate = data->baudRate;
|
||||||
|
|
||||||
|
if (-1 == setBaudRate(connectionOptions)) {
|
||||||
|
strncpy(data->errorString, connectionOptions->errorString, sizeof(data->errorString));
|
||||||
|
delete(connectionOptions);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
delete(connectionOptions);
|
||||||
|
|
||||||
|
// flush all unread and wrote data up to this point because it could have been received or sent with bad settings
|
||||||
|
// Not needed since setBaudRate does this for us
|
||||||
|
// tcflush(fd, TCIOFLUSH);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setBaudRate(ConnectionOptions *data) {
|
||||||
|
// lookup the standard baudrates from the table
|
||||||
|
int baudRate = ToBaudConstant(data->baudRate);
|
||||||
|
int fd = data->fd;
|
||||||
|
|
||||||
|
// get port options
|
||||||
|
struct termios options;
|
||||||
|
if (-1 == tcgetattr(fd, &options)) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString),
|
||||||
|
"Error: %s setting custom baud rate of %d", strerror(errno), data->baudRate);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a custom baud rate on linux you can do the following trick with B38400
|
||||||
|
#if defined(__linux__) && defined(ASYNC_SPD_CUST)
|
||||||
|
if (baudRate == -1) {
|
||||||
|
int err = linuxSetCustomBaudRate(fd, data->baudRate);
|
||||||
|
|
||||||
|
if (err == -1) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString),
|
||||||
|
"Error: %s || while retrieving termios2 info", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
} else if (err == -2) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString),
|
||||||
|
"Error: %s || while setting custom baud rate of %d", strerror(errno), data->baudRate);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// On OS X, starting with Tiger, we can set a custom baud rate with ioctl
|
||||||
|
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
|
||||||
|
if (-1 == baudRate) {
|
||||||
|
speed_t speed = data->baudRate;
|
||||||
|
if (-1 == ioctl(fd, IOSSIOSPEED, &speed)) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString),
|
||||||
|
"Error: %s calling ioctl(.., IOSSIOSPEED, %ld )", strerror(errno), speed);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
tcflush(fd, TCIOFLUSH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (-1 == baudRate) {
|
||||||
|
snprintf(data->errorString, sizeof(data->errorString), "Error baud rate of %d is not supported on your platform", data->baudRate);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a good baud rate set it and lets go
|
||||||
|
cfsetospeed(&options, baudRate);
|
||||||
|
cfsetispeed(&options, baudRate);
|
||||||
|
// throw away all the buffered data
|
||||||
|
tcflush(fd, TCIOFLUSH);
|
||||||
|
// make the changes now
|
||||||
|
tcsetattr(fd, TCSANOW, &options);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseBaton::Execute() {
|
||||||
|
|
||||||
|
if (-1 == close(fd)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, unable to close fd %d", strerror(errno), fd);
|
||||||
|
this->SetError(errorString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBaton::Execute() {
|
||||||
|
|
||||||
|
int bits;
|
||||||
|
ioctl(fd, TIOCMGET, &bits);
|
||||||
|
|
||||||
|
bits &= ~(TIOCM_RTS | TIOCM_CTS | TIOCM_DTR | TIOCM_DSR);
|
||||||
|
|
||||||
|
if (rts) {
|
||||||
|
bits |= TIOCM_RTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cts) {
|
||||||
|
bits |= TIOCM_CTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dtr) {
|
||||||
|
bits |= TIOCM_DTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dsr) {
|
||||||
|
bits |= TIOCM_DSR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
if (brk) {
|
||||||
|
result = ioctl(fd, TIOCSBRK, NULL);
|
||||||
|
} else {
|
||||||
|
result = ioctl(fd, TIOCCBRK, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == result) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot set", strerror(errno));
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == ioctl(fd, TIOCMSET, &bits)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot set", strerror(errno));
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
int err = linuxSetLowLatencyMode(fd, lowLatency);
|
||||||
|
// Only report errors when the lowLatency is being set to true. Attempting to set as false can error, since the default is false
|
||||||
|
if (lowLatency) {
|
||||||
|
if (err == -1) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot get low latency", strerror(errno));
|
||||||
|
return;
|
||||||
|
} else if(err == -2) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot set low latency", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBaton::Execute() {
|
||||||
|
int bits;
|
||||||
|
if (-1 == ioctl(fd, TIOCMGET, &bits)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot get", strerror(errno));
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cts = bits & TIOCM_CTS;
|
||||||
|
dsr = bits & TIOCM_DSR;
|
||||||
|
dcd = bits & TIOCM_CD;
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(ASYNC_LOW_LATENCY)
|
||||||
|
bool lowlatency = false;
|
||||||
|
// Try to get low latency info, but we don't care if fails (a failure state will still return lowlatency = false)
|
||||||
|
linuxGetLowLatencyMode(fd, &lowlatency);
|
||||||
|
lowLatency = lowlatency;
|
||||||
|
#else
|
||||||
|
lowLatency = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBaudRateBaton::Execute() {
|
||||||
|
int outbaud = -1;
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(ASYNC_SPD_CUST)
|
||||||
|
if (-1 == linuxGetSystemBaudRate(fd, &outbaud)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot get baud rate", strerror(errno));
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: System baud rate check not implemented on this platform");
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
baudRate = outbaud;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushBaton::Execute() {
|
||||||
|
|
||||||
|
if (-1 == tcflush(fd, TCIOFLUSH)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot flush", strerror(errno));
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrainBaton::Execute() {
|
||||||
|
|
||||||
|
if (-1 == tcdrain(fd)) {
|
||||||
|
snprintf(errorString, sizeof(errorString), "Error: %s, cannot drain", strerror(errno));
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
node_modules/@serialport/bindings-cpp/src/serialport_unix.h
generated
vendored
Normal file
7
node_modules/@serialport/bindings-cpp/src/serialport_unix.h
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef PACKAGES_SERIALPORT_SRC_SERIALPORT_UNIX_H_
|
||||||
|
#define PACKAGES_SERIALPORT_SRC_SERIALPORT_UNIX_H_
|
||||||
|
|
||||||
|
int ToBaudConstant(int baudRate);
|
||||||
|
int ToDataBitsConstant(int dataBits);
|
||||||
|
|
||||||
|
#endif // PACKAGES_SERIALPORT_SRC_SERIALPORT_UNIX_H_
|
||||||
958
node_modules/@serialport/bindings-cpp/src/serialport_win.cpp
generated
vendored
Normal file
958
node_modules/@serialport/bindings-cpp/src/serialport_win.cpp
generated
vendored
Normal file
@@ -0,0 +1,958 @@
|
|||||||
|
#include "./serialport.h"
|
||||||
|
#include "./serialport_win.h"
|
||||||
|
#include <napi.h>
|
||||||
|
#include <uv.h>
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <string.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Setupapi.h>
|
||||||
|
#include <initguid.h>
|
||||||
|
#include <devpkey.h>
|
||||||
|
#include <devguid.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#pragma comment(lib, "setupapi.lib")
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
|
||||||
|
|
||||||
|
#define MAX_BUFFER_SIZE 1000
|
||||||
|
|
||||||
|
// As per https://msdn.microsoft.com/en-us/library/windows/desktop/ms724872(v=vs.85).aspx
|
||||||
|
#define MAX_REGISTRY_KEY_SIZE 255
|
||||||
|
|
||||||
|
// Declare type of pointer to CancelIoEx function
|
||||||
|
typedef BOOL (WINAPI *CancelIoExType)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
|
||||||
|
|
||||||
|
|
||||||
|
std::list<int> g_closingHandles;
|
||||||
|
|
||||||
|
void ErrorCodeToString(const wchar_t* prefix, int errorCode, wchar_t *errorStr) {
|
||||||
|
switch (errorCode) {
|
||||||
|
case ERROR_FILE_NOT_FOUND:
|
||||||
|
_snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: File not found", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_HANDLE:
|
||||||
|
_snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Invalid handle", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_ACCESS_DENIED:
|
||||||
|
_snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Access denied", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_OPERATION_ABORTED:
|
||||||
|
_snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Operation aborted", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_PARAMETER:
|
||||||
|
_snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: The parameter is incorrect %d", prefix, errorCode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Unknown error code %d", prefix, errorCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ErrorCodeToString(const char* prefix, int errorCode, char *errorStr) {
|
||||||
|
switch (errorCode) {
|
||||||
|
case ERROR_FILE_NOT_FOUND:
|
||||||
|
_snprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, "%s: File not found", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_HANDLE:
|
||||||
|
_snprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, "%s: Invalid handle", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_ACCESS_DENIED:
|
||||||
|
_snprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, "%s: Access denied", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_OPERATION_ABORTED:
|
||||||
|
_snprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, "%s: Operation aborted", prefix);
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_PARAMETER:
|
||||||
|
_snprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, "%s: The parameter is incorrect", prefix);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_snprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, "%s: Unknown error code %d", prefix, errorCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncCloseCallback(uv_handle_t* handle) {
|
||||||
|
uv_async_t* async = reinterpret_cast<uv_async_t*>(handle);
|
||||||
|
delete async;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenBaton::Execute() {
|
||||||
|
char originalPath[1024];
|
||||||
|
strncpy_s(originalPath, sizeof(originalPath), path, _TRUNCATE);
|
||||||
|
// path is char[1024] but on Windows it has the form "COMx\0" or "COMxx\0"
|
||||||
|
// We want to prepend "\\\\.\\" to it before we call CreateFile
|
||||||
|
strncpy(path + 20, path, 10);
|
||||||
|
strncpy(path, "\\\\.\\", 4);
|
||||||
|
strncpy(path + 4, path + 20, 10);
|
||||||
|
|
||||||
|
int shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||||
|
if (lock) {
|
||||||
|
shareMode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE file = CreateFile(
|
||||||
|
path,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
shareMode, // dwShareMode 0 Prevents other processes from opening if they request delete, read, or write access
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_OVERLAPPED, // allows for reading and writing at the same time and sets the handle for asynchronous I/O
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (file == INVALID_HANDLE_VALUE) {
|
||||||
|
DWORD errorCode = GetLastError();
|
||||||
|
char temp[100];
|
||||||
|
_snprintf_s(temp, sizeof(temp), _TRUNCATE, "Opening %s", originalPath);
|
||||||
|
ErrorCodeToString(temp, errorCode, errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCB dcb = { 0 };
|
||||||
|
SecureZeroMemory(&dcb, sizeof(DCB));
|
||||||
|
dcb.DCBlength = sizeof(DCB);
|
||||||
|
|
||||||
|
if (!GetCommState(file, &dcb)) {
|
||||||
|
ErrorCodeToString("Open (GetCommState)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
CloseHandle(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hupcl) {
|
||||||
|
dcb.fDtrControl = DTR_CONTROL_ENABLE;
|
||||||
|
} else {
|
||||||
|
dcb.fDtrControl = DTR_CONTROL_DISABLE; // disable DTR to avoid reset
|
||||||
|
}
|
||||||
|
|
||||||
|
dcb.Parity = NOPARITY;
|
||||||
|
dcb.StopBits = ONESTOPBIT;
|
||||||
|
|
||||||
|
|
||||||
|
dcb.fOutxDsrFlow = FALSE;
|
||||||
|
dcb.fOutxCtsFlow = FALSE;
|
||||||
|
|
||||||
|
if (xon) {
|
||||||
|
dcb.fOutX = TRUE;
|
||||||
|
} else {
|
||||||
|
dcb.fOutX = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xoff) {
|
||||||
|
dcb.fInX = TRUE;
|
||||||
|
} else {
|
||||||
|
dcb.fInX = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtscts) {
|
||||||
|
switch (rtsMode) {
|
||||||
|
case SERIALPORT_RTSMODE_ENABLE:
|
||||||
|
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_RTSMODE_HANDSHAKE:
|
||||||
|
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_RTSMODE_TOGGLE:
|
||||||
|
dcb.fRtsControl = RTS_CONTROL_TOGGLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dcb.fOutxCtsFlow = TRUE;
|
||||||
|
} else {
|
||||||
|
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcb.fBinary = true;
|
||||||
|
dcb.BaudRate = baudRate;
|
||||||
|
dcb.ByteSize = dataBits;
|
||||||
|
|
||||||
|
switch (parity) {
|
||||||
|
case SERIALPORT_PARITY_NONE:
|
||||||
|
dcb.Parity = NOPARITY;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_PARITY_MARK:
|
||||||
|
dcb.Parity = MARKPARITY;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_PARITY_EVEN:
|
||||||
|
dcb.Parity = EVENPARITY;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_PARITY_ODD:
|
||||||
|
dcb.Parity = ODDPARITY;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_PARITY_SPACE:
|
||||||
|
dcb.Parity = SPACEPARITY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (stopBits) {
|
||||||
|
case SERIALPORT_STOPBITS_ONE:
|
||||||
|
dcb.StopBits = ONESTOPBIT;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_STOPBITS_ONE_FIVE:
|
||||||
|
dcb.StopBits = ONE5STOPBITS;
|
||||||
|
break;
|
||||||
|
case SERIALPORT_STOPBITS_TWO:
|
||||||
|
dcb.StopBits = TWOSTOPBITS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetCommState(file, &dcb)) {
|
||||||
|
ErrorCodeToString("Open (SetCommState)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
CloseHandle(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the timeouts for read and write operations.
|
||||||
|
// Read operation will wait for at least 1 byte to be received.
|
||||||
|
COMMTIMEOUTS commTimeouts = {};
|
||||||
|
commTimeouts.ReadIntervalTimeout = 0; // Never timeout, always wait for data.
|
||||||
|
commTimeouts.ReadTotalTimeoutMultiplier = 0; // Do not allow big read timeout when big read buffer used
|
||||||
|
commTimeouts.ReadTotalTimeoutConstant = 0; // Total read timeout (period of read loop)
|
||||||
|
commTimeouts.WriteTotalTimeoutConstant = 0; // Const part of write timeout
|
||||||
|
commTimeouts.WriteTotalTimeoutMultiplier = 0; // Variable part of write timeout (per byte)
|
||||||
|
|
||||||
|
if (!SetCommTimeouts(file, &commTimeouts)) {
|
||||||
|
ErrorCodeToString("Open (SetCommTimeouts)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
CloseHandle(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove garbage data in RX/TX queues
|
||||||
|
PurgeComm(file, PURGE_RXCLEAR);
|
||||||
|
PurgeComm(file, PURGE_TXCLEAR);
|
||||||
|
|
||||||
|
result = static_cast<int>(reinterpret_cast<uintptr_t>(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionOptionsBaton::Execute() {
|
||||||
|
DCB dcb = { 0 };
|
||||||
|
SecureZeroMemory(&dcb, sizeof(DCB));
|
||||||
|
dcb.DCBlength = sizeof(DCB);
|
||||||
|
|
||||||
|
if (!GetCommState(int2handle(fd), &dcb)) {
|
||||||
|
ErrorCodeToString("Update (GetCommState)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcb.BaudRate = baudRate;
|
||||||
|
|
||||||
|
if (!SetCommState(int2handle(fd), &dcb)) {
|
||||||
|
ErrorCodeToString("Update (SetCommState)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBaton::Execute() {
|
||||||
|
if (rts) {
|
||||||
|
EscapeCommFunction(int2handle(fd), SETRTS);
|
||||||
|
} else {
|
||||||
|
EscapeCommFunction(int2handle(fd), CLRRTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dtr) {
|
||||||
|
EscapeCommFunction(int2handle(fd), SETDTR);
|
||||||
|
} else {
|
||||||
|
EscapeCommFunction(int2handle(fd), CLRDTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brk) {
|
||||||
|
EscapeCommFunction(int2handle(fd), SETBREAK);
|
||||||
|
} else {
|
||||||
|
EscapeCommFunction(int2handle(fd), CLRBREAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD bits = 0;
|
||||||
|
|
||||||
|
GetCommMask(int2handle(fd), &bits);
|
||||||
|
|
||||||
|
bits &= ~(EV_CTS | EV_DSR);
|
||||||
|
|
||||||
|
if (cts) {
|
||||||
|
bits |= EV_CTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dsr) {
|
||||||
|
bits |= EV_DSR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetCommMask(int2handle(fd), bits)) {
|
||||||
|
ErrorCodeToString("Setting options on COM port (SetCommMask)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBaton::Execute() {
|
||||||
|
DWORD bits = 0;
|
||||||
|
if (!GetCommModemStatus(int2handle(fd), &bits)) {
|
||||||
|
ErrorCodeToString("Getting control settings on COM port (GetCommModemStatus)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cts = bits & MS_CTS_ON;
|
||||||
|
dsr = bits & MS_DSR_ON;
|
||||||
|
dcd = bits & MS_RLSD_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetBaudRateBaton::Execute() {
|
||||||
|
|
||||||
|
DCB dcb = { 0 };
|
||||||
|
SecureZeroMemory(&dcb, sizeof(DCB));
|
||||||
|
dcb.DCBlength = sizeof(DCB);
|
||||||
|
|
||||||
|
if (!GetCommState(int2handle(fd), &dcb)) {
|
||||||
|
ErrorCodeToString("Getting baud rate (GetCommState)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
baudRate = static_cast<int>(dcb.BaudRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsClosingHandle(int fd) {
|
||||||
|
for (std::list<int>::iterator it = g_closingHandles.begin(); it != g_closingHandles.end(); ++it) {
|
||||||
|
if (fd == *it) {
|
||||||
|
g_closingHandles.remove(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall WriteIOCompletion(DWORD errorCode, DWORD bytesTransferred, OVERLAPPED* ov) {
|
||||||
|
WriteBaton* baton = static_cast<WriteBaton*>(ov->hEvent);
|
||||||
|
DWORD bytesWritten;
|
||||||
|
if (!GetOverlappedResult(int2handle(baton->fd), ov, &bytesWritten, TRUE)) {
|
||||||
|
errorCode = GetLastError();
|
||||||
|
ErrorCodeToString("Writing to COM port (GetOverlappedResult)", errorCode, baton->errorString);
|
||||||
|
baton->complete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bytesWritten) {
|
||||||
|
baton->offset += bytesWritten;
|
||||||
|
if (baton->offset >= baton->bufferLength) {
|
||||||
|
baton->complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD __stdcall WriteThread(LPVOID param) {
|
||||||
|
uv_async_t* async = static_cast<uv_async_t*>(param);
|
||||||
|
WriteBaton* baton = static_cast<WriteBaton*>(async->data);
|
||||||
|
|
||||||
|
OVERLAPPED* ov = new OVERLAPPED;
|
||||||
|
memset(ov, 0, sizeof(OVERLAPPED));
|
||||||
|
ov->hEvent = static_cast<void*>(baton);
|
||||||
|
|
||||||
|
while (!baton->complete) {
|
||||||
|
char* offsetPtr = baton->bufferData + baton->offset;
|
||||||
|
// WriteFileEx requires calling GetLastError even upon success. Clear the error beforehand.
|
||||||
|
SetLastError(0);
|
||||||
|
WriteFileEx(int2handle(baton->fd), offsetPtr,
|
||||||
|
static_cast<DWORD>(baton->bufferLength - baton->offset), ov, WriteIOCompletion);
|
||||||
|
// Error codes when call is successful, such as ERROR_MORE_DATA.
|
||||||
|
DWORD lastError = GetLastError();
|
||||||
|
if (lastError != ERROR_SUCCESS) {
|
||||||
|
ErrorCodeToString("Writing to COM port (WriteFileEx)", lastError, baton->errorString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// IOCompletion routine is only called once this thread is in an alertable wait state.
|
||||||
|
SleepEx(INFINITE, TRUE);
|
||||||
|
}
|
||||||
|
delete ov;
|
||||||
|
// Signal the main thread to run the callback.
|
||||||
|
uv_async_send(async);
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EIO_AfterWrite(uv_async_t* req) {
|
||||||
|
WriteBaton* baton = static_cast<WriteBaton*>(req->data);
|
||||||
|
Napi::Env env = baton->callback.Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
WaitForSingleObject(baton->hThread, INFINITE);
|
||||||
|
CloseHandle(baton->hThread);
|
||||||
|
uv_close(reinterpret_cast<uv_handle_t*>(req), AsyncCloseCallback);
|
||||||
|
|
||||||
|
v8::Local<v8::Value> argv[1];
|
||||||
|
if (baton->errorString[0]) {
|
||||||
|
baton->callback.Call({Napi::Error::New(env, baton->errorString).Value()});
|
||||||
|
} else {
|
||||||
|
baton->callback.Call({env.Null()});
|
||||||
|
}
|
||||||
|
baton->buffer.Reset();
|
||||||
|
delete baton;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Napi::Value Write(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// buffer
|
||||||
|
if (!info[1].IsObject() || !info[1].IsBuffer()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a buffer").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Buffer<char> buffer = info[1].As<Napi::Buffer<char>>();
|
||||||
|
//getBufferFromObject(info[1].ToObject().ti);
|
||||||
|
char* bufferData = buffer.Data(); //.As<Napi::Buffer<char>>().Data();
|
||||||
|
size_t bufferLength = buffer.Length();//.As<Napi::Buffer<char>>().Length();
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[2].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Third argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteBaton* baton = new WriteBaton();
|
||||||
|
baton->callback = Napi::Persistent(info[2].As<Napi::Function>());
|
||||||
|
baton->fd = fd;
|
||||||
|
baton->buffer.Reset(buffer);
|
||||||
|
baton->bufferData = bufferData;
|
||||||
|
baton->bufferLength = bufferLength;
|
||||||
|
baton->offset = 0;
|
||||||
|
baton->complete = false;
|
||||||
|
|
||||||
|
uv_async_t* async = new uv_async_t;
|
||||||
|
uv_async_init(uv_default_loop(), async, EIO_AfterWrite);
|
||||||
|
async->data = baton;
|
||||||
|
// WriteFileEx requires a thread that can block. Create a new thread to
|
||||||
|
// run the write operation, saving the handle so it can be deallocated later.
|
||||||
|
baton->hThread = CreateThread(NULL, 0, WriteThread, async, 0, NULL);
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall ReadIOCompletion(DWORD errorCode, DWORD bytesTransferred, OVERLAPPED* ov) {
|
||||||
|
ReadBaton* baton = static_cast<ReadBaton*>(ov->hEvent);
|
||||||
|
|
||||||
|
if (errorCode) {
|
||||||
|
ErrorCodeToString("Reading from COM port (ReadIOCompletion)", errorCode, baton->errorString);
|
||||||
|
baton->complete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD lastError;
|
||||||
|
if (!GetOverlappedResult(int2handle(baton->fd), ov, &bytesTransferred, TRUE)) {
|
||||||
|
lastError = GetLastError();
|
||||||
|
ErrorCodeToString("Reading from COM port (GetOverlappedResult)", lastError, baton->errorString);
|
||||||
|
baton->complete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bytesTransferred) {
|
||||||
|
baton->bytesToRead -= bytesTransferred;
|
||||||
|
baton->bytesRead += bytesTransferred;
|
||||||
|
baton->offset += bytesTransferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFileEx and GetOverlappedResult retrieved only 1 byte. Read any additional data in the input
|
||||||
|
// buffer. Set the timeout to MAXDWORD in order to disable timeouts, so the read operation will
|
||||||
|
// return immediately no matter how much data is available.
|
||||||
|
COMMTIMEOUTS commTimeouts = {};
|
||||||
|
commTimeouts.ReadIntervalTimeout = MAXDWORD;
|
||||||
|
if (!SetCommTimeouts(int2handle(baton->fd), &commTimeouts)) {
|
||||||
|
lastError = GetLastError();
|
||||||
|
ErrorCodeToString("Setting COM timeout (SetCommTimeouts)", lastError, baton->errorString);
|
||||||
|
baton->complete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store additional data after whatever data has already been read.
|
||||||
|
char* offsetPtr = baton->bufferData + baton->offset;
|
||||||
|
|
||||||
|
// ReadFile, unlike ReadFileEx, needs an event in the overlapped structure.
|
||||||
|
memset(ov, 0, sizeof(OVERLAPPED));
|
||||||
|
ov->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!ReadFile(int2handle(baton->fd), offsetPtr, baton->bytesToRead, &bytesTransferred, ov)) {
|
||||||
|
errorCode = GetLastError();
|
||||||
|
|
||||||
|
if (errorCode != ERROR_IO_PENDING) {
|
||||||
|
ErrorCodeToString("Reading from COM port (ReadFile)", errorCode, baton->errorString);
|
||||||
|
baton->complete = true;
|
||||||
|
CloseHandle(ov->hEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetOverlappedResult(int2handle(baton->fd), ov, &bytesTransferred, TRUE)) {
|
||||||
|
lastError = GetLastError();
|
||||||
|
ErrorCodeToString("Reading from COM port (GetOverlappedResult)", lastError, baton->errorString);
|
||||||
|
baton->complete = true;
|
||||||
|
CloseHandle(ov->hEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle(ov->hEvent);
|
||||||
|
|
||||||
|
baton->bytesToRead -= bytesTransferred;
|
||||||
|
baton->bytesRead += bytesTransferred;
|
||||||
|
baton->complete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD __stdcall ReadThread(LPVOID param) {
|
||||||
|
uv_async_t* async = static_cast<uv_async_t*>(param);
|
||||||
|
ReadBaton* baton = static_cast<ReadBaton*>(async->data);
|
||||||
|
DWORD lastError;
|
||||||
|
|
||||||
|
OVERLAPPED* ov = new OVERLAPPED;
|
||||||
|
memset(ov, 0, sizeof(OVERLAPPED));
|
||||||
|
ov->hEvent = static_cast<void*>(baton);
|
||||||
|
|
||||||
|
while (!baton->complete) {
|
||||||
|
// Reset the read timeout to 0, so that it will block until more data arrives.
|
||||||
|
COMMTIMEOUTS commTimeouts = {};
|
||||||
|
commTimeouts.ReadIntervalTimeout = 0;
|
||||||
|
if (!SetCommTimeouts(int2handle(baton->fd), &commTimeouts)) {
|
||||||
|
lastError = GetLastError();
|
||||||
|
ErrorCodeToString("Setting COM timeout (SetCommTimeouts)", lastError, baton->errorString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// ReadFileEx doesn't use overlapped's hEvent, so it is reserved for user data.
|
||||||
|
ov->hEvent = static_cast<HANDLE>(baton);
|
||||||
|
char* offsetPtr = baton->bufferData + baton->offset;
|
||||||
|
// ReadFileEx requires calling GetLastError even upon success. Clear the error beforehand.
|
||||||
|
SetLastError(0);
|
||||||
|
// Only read 1 byte, so that the callback will be triggered once any data arrives.
|
||||||
|
ReadFileEx(int2handle(baton->fd), offsetPtr, 1, ov, ReadIOCompletion);
|
||||||
|
// Error codes when call is successful, such as ERROR_MORE_DATA.
|
||||||
|
lastError = GetLastError();
|
||||||
|
if (lastError != ERROR_SUCCESS) {
|
||||||
|
ErrorCodeToString("Reading from COM port (ReadFileEx)", lastError, baton->errorString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// IOCompletion routine is only called once this thread is in an alertable wait state.
|
||||||
|
SleepEx(INFINITE, TRUE);
|
||||||
|
}
|
||||||
|
delete ov;
|
||||||
|
// Signal the main thread to run the callback.
|
||||||
|
uv_async_send(async);
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EIO_AfterRead(uv_async_t* req) {
|
||||||
|
ReadBaton* baton = static_cast<ReadBaton*>(req->data);
|
||||||
|
Napi::Env env = baton->callback.Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
WaitForSingleObject(baton->hThread, INFINITE);
|
||||||
|
CloseHandle(baton->hThread);
|
||||||
|
uv_close(reinterpret_cast<uv_handle_t*>(req), AsyncCloseCallback);
|
||||||
|
|
||||||
|
if (baton->errorString[0]) {
|
||||||
|
baton->callback.Call({Napi::Error::New(env, baton->errorString).Value(), env.Undefined()});
|
||||||
|
} else {
|
||||||
|
baton->callback.Call({env.Null(), Napi::Number::New(env, static_cast<int>(baton->bytesRead))});
|
||||||
|
}
|
||||||
|
delete baton;
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value Read(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// file descriptor
|
||||||
|
if (!info[0].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be a fd").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int fd = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
|
||||||
|
// buffer
|
||||||
|
if (!info[1].IsObject() || !info[1].IsBuffer()) {
|
||||||
|
Napi::TypeError::New(env, "Second argument must be a buffer").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Napi::Object buffer = info[1].ToObject();
|
||||||
|
size_t bufferLength = buffer.As<Napi::Buffer<char>>().Length();
|
||||||
|
|
||||||
|
// offset
|
||||||
|
if (!info[2].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "Third argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
int offset = info[2].ToNumber().Int64Value();
|
||||||
|
|
||||||
|
// bytes to read
|
||||||
|
if (!info[3].IsNumber()) {
|
||||||
|
Napi::TypeError::New(env, "Fourth argument must be an int").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
size_t bytesToRead = info[3].ToNumber().Int64Value();
|
||||||
|
|
||||||
|
if ((bytesToRead + offset) > bufferLength) {
|
||||||
|
Napi::TypeError::New(env, "'bytesToRead' + 'offset' cannot be larger than the buffer's length").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback
|
||||||
|
if (!info[4].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "Fifth argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
ReadBaton* baton = new ReadBaton();
|
||||||
|
baton->callback = Napi::Persistent(info[4].As<Napi::Function>());
|
||||||
|
baton->fd = fd;
|
||||||
|
baton->offset = offset;
|
||||||
|
baton->bytesToRead = bytesToRead;
|
||||||
|
baton->bufferLength = bufferLength;
|
||||||
|
|
||||||
|
baton->bufferData = buffer.As<Napi::Buffer<char>>().Data();
|
||||||
|
baton->complete = false;
|
||||||
|
|
||||||
|
uv_async_t* async = new uv_async_t;
|
||||||
|
uv_async_init(uv_default_loop(), async, EIO_AfterRead);
|
||||||
|
async->data = baton;
|
||||||
|
baton->hThread = CreateThread(NULL, 0, ReadThread, async, 0, NULL);
|
||||||
|
// ReadFileEx requires a thread that can block. Create a new thread to
|
||||||
|
// run the read operation, saving the handle so it can be deallocated later.
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseBaton::Execute() {
|
||||||
|
g_closingHandles.push_back(fd);
|
||||||
|
|
||||||
|
HMODULE hKernel32 = LoadLibrary("kernel32.dll");
|
||||||
|
// Look up function address
|
||||||
|
CancelIoExType pCancelIoEx = (CancelIoExType)GetProcAddress(hKernel32, "CancelIoEx");
|
||||||
|
// Do something with it
|
||||||
|
if (pCancelIoEx) {
|
||||||
|
// Function exists so call it
|
||||||
|
// Cancel all pending IO Requests for the current device
|
||||||
|
pCancelIoEx(int2handle(fd), NULL);
|
||||||
|
}
|
||||||
|
if (!CloseHandle(int2handle(fd))) {
|
||||||
|
ErrorCodeToString("Closing connection (CloseHandle)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *copySubstring(wchar_t *someString, int n) {
|
||||||
|
wchar_t *new_ = reinterpret_cast<wchar_t*>(malloc(sizeof(wchar_t)*n + 1));
|
||||||
|
wcsncpy_s(new_, n + 1, someString, n);
|
||||||
|
new_[n] = '\0';
|
||||||
|
return new_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Value List(const Napi::CallbackInfo& info) {
|
||||||
|
Napi::Env env = info.Env();
|
||||||
|
// callback
|
||||||
|
if (!info[0].IsFunction()) {
|
||||||
|
Napi::TypeError::New(env, "First argument must be a function").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
Napi::Function callback = info[0].As<Napi::Function>();
|
||||||
|
ListBaton* baton = new ListBaton(callback);
|
||||||
|
_snwprintf(baton->errorString, sizeof(baton->errorString), L"");
|
||||||
|
|
||||||
|
baton->Queue();
|
||||||
|
return env.Undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's possible that the s/n is a construct and not the s/n of the parent USB
|
||||||
|
// composite device. This performs some convoluted registry lookups to fetch the USB s/n.
|
||||||
|
void getSerialNumber(const wchar_t *vid,
|
||||||
|
const wchar_t *pid,
|
||||||
|
const HDEVINFO hDevInfo,
|
||||||
|
SP_DEVINFO_DATA deviceInfoData,
|
||||||
|
const unsigned int maxSerialNumberLength,
|
||||||
|
wchar_t* serialNumber) {
|
||||||
|
_snwprintf_s(serialNumber, maxSerialNumberLength, _TRUNCATE, L"");
|
||||||
|
if (vid == NULL || pid == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dwSize;
|
||||||
|
WCHAR szWUuidBuffer[MAX_BUFFER_SIZE];
|
||||||
|
WCHAR wantedUuid[MAX_BUFFER_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch the "Container ID" for this device node. In USB context, this "Container
|
||||||
|
// ID" refers to the composite USB device, i.e. the USB device as a whole, not
|
||||||
|
// just one of its interfaces with a serial port driver attached.
|
||||||
|
|
||||||
|
// From https://stackoverflow.com/questions/3438366/setupdigetdeviceproperty-usage-example:
|
||||||
|
// Because this is not compiled with UNICODE defined, the call to SetupDiGetDevicePropertyW
|
||||||
|
// has to be setup manually.
|
||||||
|
DEVPROPTYPE ulPropertyType;
|
||||||
|
typedef BOOL (WINAPI *FN_SetupDiGetDevicePropertyW)(
|
||||||
|
__in HDEVINFO DeviceInfoSet,
|
||||||
|
__in PSP_DEVINFO_DATA DeviceInfoData,
|
||||||
|
__in const DEVPROPKEY *PropertyKey,
|
||||||
|
__out DEVPROPTYPE *PropertyType,
|
||||||
|
__out_opt PBYTE PropertyBuffer,
|
||||||
|
__in DWORD PropertyBufferSize,
|
||||||
|
__out_opt PDWORD RequiredSize,
|
||||||
|
__in DWORD Flags);
|
||||||
|
|
||||||
|
FN_SetupDiGetDevicePropertyW fn_SetupDiGetDevicePropertyW = (FN_SetupDiGetDevicePropertyW)
|
||||||
|
GetProcAddress(GetModuleHandle(TEXT("Setupapi.dll")), "SetupDiGetDevicePropertyW");
|
||||||
|
|
||||||
|
if (fn_SetupDiGetDevicePropertyW (
|
||||||
|
hDevInfo,
|
||||||
|
&deviceInfoData,
|
||||||
|
&DEVPKEY_Device_ContainerId,
|
||||||
|
&ulPropertyType,
|
||||||
|
reinterpret_cast<BYTE*>(szWUuidBuffer),
|
||||||
|
sizeof(szWUuidBuffer),
|
||||||
|
&dwSize,
|
||||||
|
0)) {
|
||||||
|
szWUuidBuffer[dwSize] = '\0';
|
||||||
|
|
||||||
|
// Given the UUID bytes, build up a (widechar) string from it. There's some mangling
|
||||||
|
// going on.
|
||||||
|
StringFromGUID2((REFGUID)szWUuidBuffer, wantedUuid, ARRAY_SIZE(wantedUuid));
|
||||||
|
} else {
|
||||||
|
// Container UUID could not be fetched, return empty serial number.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Devices might have a containerUuid like {00000000-0000-0000-FFFF-FFFFFFFFFFFF}
|
||||||
|
// This means they're non-removable, and are not handled (yet).
|
||||||
|
// Maybe they should inherit the s/n from somewhere else.
|
||||||
|
|
||||||
|
// Iterate through all the USB devices with the given VendorID/ProductID
|
||||||
|
|
||||||
|
HKEY vendorProductHKey;
|
||||||
|
DWORD retCode;
|
||||||
|
wchar_t hkeyPath[MAX_BUFFER_SIZE];
|
||||||
|
|
||||||
|
_snwprintf_s(hkeyPath, MAX_BUFFER_SIZE, _TRUNCATE, L"SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%s&PID_%s", vid, pid);
|
||||||
|
|
||||||
|
retCode = RegOpenKeyExW(
|
||||||
|
HKEY_LOCAL_MACHINE,
|
||||||
|
hkeyPath,
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&vendorProductHKey);
|
||||||
|
|
||||||
|
if (retCode == ERROR_SUCCESS) {
|
||||||
|
DWORD serialNumbersCount = 0; // number of subkeys
|
||||||
|
|
||||||
|
// Fetch how many subkeys there are for this VendorID/ProductID pair.
|
||||||
|
// That's the number of devices for this VendorID/ProductID known to this machine.
|
||||||
|
|
||||||
|
retCode = RegQueryInfoKey(
|
||||||
|
vendorProductHKey, // hkey handle
|
||||||
|
NULL, // buffer for class name
|
||||||
|
NULL, // size of class string
|
||||||
|
NULL, // reserved
|
||||||
|
&serialNumbersCount, // number of subkeys
|
||||||
|
NULL, // longest subkey size
|
||||||
|
NULL, // longest class string
|
||||||
|
NULL, // number of values for this key
|
||||||
|
NULL, // longest value name
|
||||||
|
NULL, // longest value data
|
||||||
|
NULL, // security descriptor
|
||||||
|
NULL); // last write time
|
||||||
|
|
||||||
|
if (retCode == ERROR_SUCCESS && serialNumbersCount > 0) {
|
||||||
|
for (unsigned int i=0; i < serialNumbersCount; i++) {
|
||||||
|
// Each of the subkeys here is the serial number of a USB device with the
|
||||||
|
// given VendorId/ProductId. Now fetch the string for the S/N.
|
||||||
|
DWORD serialNumberLength = maxSerialNumberLength;
|
||||||
|
retCode = RegEnumKeyExW(vendorProductHKey,
|
||||||
|
i,
|
||||||
|
reinterpret_cast<LPWSTR>(serialNumber),
|
||||||
|
&serialNumberLength,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (retCode == ERROR_SUCCESS) {
|
||||||
|
// Lookup info for VID_(vendorId)&PID_(productId)\(serialnumber)
|
||||||
|
|
||||||
|
_snwprintf_s(hkeyPath, MAX_BUFFER_SIZE, _TRUNCATE,
|
||||||
|
L"SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%ls&PID_%ls\\%ls",
|
||||||
|
vid, pid, serialNumber);
|
||||||
|
|
||||||
|
HKEY deviceHKey;
|
||||||
|
|
||||||
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, hkeyPath, 0, KEY_READ, &deviceHKey) == ERROR_SUCCESS) {
|
||||||
|
wchar_t readUuid[MAX_BUFFER_SIZE];
|
||||||
|
DWORD readSize = sizeof(readUuid);
|
||||||
|
|
||||||
|
// Query VID_(vendorId)&PID_(productId)\(serialnumber)\ContainerID
|
||||||
|
retCode = RegQueryValueExW(deviceHKey, L"ContainerID", NULL, NULL, (LPBYTE)&readUuid, &readSize);
|
||||||
|
if (retCode == ERROR_SUCCESS) {
|
||||||
|
readUuid[readSize] = '\0';
|
||||||
|
if (wcscmp(wantedUuid, readUuid) == 0) {
|
||||||
|
// The ContainerID UUIDs match, return now that serialNumber has
|
||||||
|
// the right value.
|
||||||
|
RegCloseKey(deviceHKey);
|
||||||
|
RegCloseKey(vendorProductHKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RegCloseKey(deviceHKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case we did not obtain the path, for whatever reason, we close the key and return an empty string. */
|
||||||
|
RegCloseKey(vendorProductHKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
_snwprintf_s(serialNumber, maxSerialNumberLength, _TRUNCATE, L"");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListBaton::Execute() {
|
||||||
|
|
||||||
|
GUID *guidDev = (GUID*)& GUID_DEVCLASS_PORTS; // NOLINT
|
||||||
|
HDEVINFO hDevInfo = SetupDiGetClassDevs(guidDev, NULL, NULL, DIGCF_PRESENT | DIGCF_PROFILE);
|
||||||
|
SP_DEVINFO_DATA deviceInfoData;
|
||||||
|
|
||||||
|
int memberIndex = 0;
|
||||||
|
DWORD dwSize, dwPropertyRegDataType;
|
||||||
|
wchar_t szBuffer[MAX_BUFFER_SIZE];
|
||||||
|
wchar_t *pnpId;
|
||||||
|
wchar_t *vendorId;
|
||||||
|
wchar_t *productId;
|
||||||
|
wchar_t *name;
|
||||||
|
wchar_t *manufacturer;
|
||||||
|
wchar_t *locationId;
|
||||||
|
wchar_t *friendlyName;
|
||||||
|
wchar_t serialNumber[MAX_REGISTRY_KEY_SIZE];
|
||||||
|
bool isCom;
|
||||||
|
while (true) {
|
||||||
|
isCom = false;
|
||||||
|
pnpId = NULL;
|
||||||
|
vendorId = NULL;
|
||||||
|
productId = NULL;
|
||||||
|
name = NULL;
|
||||||
|
manufacturer = NULL;
|
||||||
|
locationId = NULL;
|
||||||
|
friendlyName = NULL;
|
||||||
|
|
||||||
|
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
|
||||||
|
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
|
|
||||||
|
if (SetupDiEnumDeviceInfo(hDevInfo, memberIndex, &deviceInfoData) == FALSE) {
|
||||||
|
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dwSize = sizeof(szBuffer);
|
||||||
|
SetupDiGetDeviceInstanceIdW(hDevInfo, &deviceInfoData, reinterpret_cast<PWSTR>(szBuffer), dwSize, &dwSize);
|
||||||
|
szBuffer[dwSize] = '\0';
|
||||||
|
pnpId = wcsdup(szBuffer);
|
||||||
|
|
||||||
|
vendorId = wcsstr(szBuffer, L"VID_");
|
||||||
|
if (vendorId) {
|
||||||
|
vendorId += 4;
|
||||||
|
vendorId = copySubstring(vendorId, 4);
|
||||||
|
}
|
||||||
|
productId = wcsstr(szBuffer, L"PID_");
|
||||||
|
if (productId) {
|
||||||
|
productId += 4;
|
||||||
|
productId = copySubstring(productId, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSerialNumber(vendorId, productId, hDevInfo, deviceInfoData, MAX_REGISTRY_KEY_SIZE, serialNumber);
|
||||||
|
|
||||||
|
if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData,
|
||||||
|
SPDRP_LOCATION_INFORMATION, &dwPropertyRegDataType,
|
||||||
|
reinterpret_cast<PBYTE>(szBuffer), sizeof(szBuffer), &dwSize)) {
|
||||||
|
locationId = wcsdup(szBuffer);
|
||||||
|
}
|
||||||
|
if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData,
|
||||||
|
SPDRP_FRIENDLYNAME, &dwPropertyRegDataType,
|
||||||
|
reinterpret_cast<PBYTE>(szBuffer), sizeof(szBuffer), &dwSize)) {
|
||||||
|
friendlyName = wcsdup(szBuffer);
|
||||||
|
}
|
||||||
|
if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData,
|
||||||
|
SPDRP_MFG, &dwPropertyRegDataType,
|
||||||
|
reinterpret_cast<PBYTE>(szBuffer), sizeof(szBuffer), &dwSize)) {
|
||||||
|
manufacturer = wcsdup(szBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
HKEY hkey = SetupDiOpenDevRegKey(hDevInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
|
||||||
|
if (hkey != INVALID_HANDLE_VALUE) {
|
||||||
|
dwSize = sizeof(szBuffer);
|
||||||
|
if (RegQueryValueExW(hkey, L"PortName", NULL, NULL, (LPBYTE)&szBuffer, &dwSize) == ERROR_SUCCESS) {
|
||||||
|
name = wcsdup(szBuffer);
|
||||||
|
szBuffer[dwSize] = '\0';
|
||||||
|
isCom = wcsstr(szBuffer, L"COM") != NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isCom) {
|
||||||
|
ListResultItem* resultItem = new ListResultItem();
|
||||||
|
resultItem->path = name;
|
||||||
|
resultItem->manufacturer = manufacturer;
|
||||||
|
resultItem->pnpId = pnpId;
|
||||||
|
if (vendorId) {
|
||||||
|
resultItem->vendorId = vendorId;
|
||||||
|
}
|
||||||
|
if (productId) {
|
||||||
|
resultItem->productId = productId;
|
||||||
|
}
|
||||||
|
resultItem->serialNumber = serialNumber;
|
||||||
|
if (locationId) {
|
||||||
|
resultItem->locationId = locationId;
|
||||||
|
}
|
||||||
|
if (friendlyName) {
|
||||||
|
resultItem->friendlyName = friendlyName;
|
||||||
|
}
|
||||||
|
results.push_back(resultItem);
|
||||||
|
}
|
||||||
|
free(pnpId);
|
||||||
|
free(vendorId);
|
||||||
|
free(productId);
|
||||||
|
free(locationId);
|
||||||
|
free(manufacturer);
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
RegCloseKey(hkey);
|
||||||
|
memberIndex++;
|
||||||
|
}
|
||||||
|
if (hDevInfo) {
|
||||||
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIfNotEmpty(Napi::Object item, std::string key, const char *value) {
|
||||||
|
Napi::Env env = item.Env();
|
||||||
|
Napi::String v8key = Napi::String::New(env, key);
|
||||||
|
if (strlen(value) > 0) {
|
||||||
|
(item).Set(v8key, Napi::String::New(env, value));
|
||||||
|
} else {
|
||||||
|
(item).Set(v8key, env.Undefined());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIfNotEmpty(Napi::Object item, std::string key, const wchar_t *value) {
|
||||||
|
Napi::Env env = item.Env();
|
||||||
|
Napi::String v8key = Napi::String::New(env, key);
|
||||||
|
if (wcslen(value) > 0) {
|
||||||
|
(item).Set(v8key, Napi::String::New(env, (const char16_t*) value));
|
||||||
|
} else {
|
||||||
|
(item).Set(v8key, env.Undefined());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushBaton::Execute() {
|
||||||
|
DWORD purge_all = PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR;
|
||||||
|
if (!PurgeComm(int2handle(fd), purge_all)) {
|
||||||
|
ErrorCodeToString("Flushing connection (PurgeComm)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrainBaton::Execute() {
|
||||||
|
if (!FlushFileBuffers(int2handle(fd))) {
|
||||||
|
ErrorCodeToString("Draining connection (FlushFileBuffers)", GetLastError(), errorString);
|
||||||
|
this->SetError(errorString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
93
node_modules/@serialport/bindings-cpp/src/serialport_win.h
generated
vendored
Normal file
93
node_modules/@serialport/bindings-cpp/src/serialport_win.h
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#ifndef PACKAGES_SERIALPORT_SRC_SERIALPORT_WIN_H_
|
||||||
|
#define PACKAGES_SERIALPORT_SRC_SERIALPORT_WIN_H_
|
||||||
|
#include <napi.h>
|
||||||
|
#include <uv.h>
|
||||||
|
#include <node_buffer.h>
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define ERROR_STRING_SIZE 1088
|
||||||
|
|
||||||
|
static inline HANDLE int2handle(int ptr) {
|
||||||
|
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WriteBaton {
|
||||||
|
WriteBaton() : bufferData(), errorString() {}
|
||||||
|
int fd = 0;
|
||||||
|
char* bufferData = nullptr;
|
||||||
|
size_t bufferLength = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t bytesWritten = 0;
|
||||||
|
void* hThread = nullptr;
|
||||||
|
bool complete = false;
|
||||||
|
Napi::ObjectReference buffer;
|
||||||
|
Napi::FunctionReference callback;
|
||||||
|
int result = 0;
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
Napi::Value Write(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
struct ReadBaton {
|
||||||
|
ReadBaton() : errorString() {}
|
||||||
|
int fd = 0;
|
||||||
|
char* bufferData = nullptr;
|
||||||
|
size_t bufferLength = 0;
|
||||||
|
size_t bytesRead = 0;
|
||||||
|
size_t bytesToRead = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
void* hThread = nullptr;
|
||||||
|
Napi::FunctionReference callback;
|
||||||
|
bool complete = false;
|
||||||
|
char errorString[ERROR_STRING_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
Napi::Value Read(const Napi::CallbackInfo& info);
|
||||||
|
|
||||||
|
Napi::Value List(const Napi::CallbackInfo& info);
|
||||||
|
void setIfNotEmpty(Napi::Object item, std::string key, const char *value);
|
||||||
|
void setIfNotEmpty(Napi::Object item, std::string key, const wchar_t *value);
|
||||||
|
|
||||||
|
struct ListResultItem {
|
||||||
|
std::wstring path;
|
||||||
|
std::wstring manufacturer;
|
||||||
|
std::wstring serialNumber;
|
||||||
|
std::wstring pnpId;
|
||||||
|
std::wstring locationId;
|
||||||
|
std::wstring friendlyName;
|
||||||
|
std::wstring vendorId;
|
||||||
|
std::wstring productId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ListBaton : public Napi::AsyncWorker {
|
||||||
|
ListBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:ListBaton"),
|
||||||
|
errorString() {}
|
||||||
|
std::list<ListResultItem*> results;
|
||||||
|
wchar_t errorString[ERROR_STRING_SIZE];
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void OnOK() override {
|
||||||
|
Napi::Env env = Env();
|
||||||
|
Napi::HandleScope scope(env);
|
||||||
|
Napi::Array result = Napi::Array::New(env);
|
||||||
|
int i = 0;
|
||||||
|
for (std::list<ListResultItem*>::iterator it = results.begin(); it != results.end(); ++it, i++) {
|
||||||
|
Napi::Object item = Napi::Object::New(env);
|
||||||
|
|
||||||
|
setIfNotEmpty(item, "path", (*it)->path.c_str());
|
||||||
|
setIfNotEmpty(item, "manufacturer", (*it)->manufacturer.c_str());
|
||||||
|
setIfNotEmpty(item, "serialNumber", (*it)->serialNumber.c_str());
|
||||||
|
setIfNotEmpty(item, "pnpId", (*it)->pnpId.c_str());
|
||||||
|
setIfNotEmpty(item, "locationId", (*it)->locationId.c_str());
|
||||||
|
setIfNotEmpty(item, "friendlyName", (*it)->friendlyName.c_str());
|
||||||
|
setIfNotEmpty(item, "vendorId", (*it)->vendorId.c_str());
|
||||||
|
setIfNotEmpty(item, "productId", (*it)->productId.c_str());
|
||||||
|
|
||||||
|
(result).Set(i, item);
|
||||||
|
}
|
||||||
|
Callback().Call({env.Null(), result});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PACKAGES_SERIALPORT_SRC_SERIALPORT_WIN_H_
|
||||||
10
node_modules/@serialport/bindings-interface/CODE_OF_CONDUCT.md
generated
vendored
Normal file
10
node_modules/@serialport/bindings-interface/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Code of Conduct
|
||||||
|
|
||||||
|
SerialPort follows the Nodebots Code of Conduct. The full text can be found at http://nodebots.io/conduct.html
|
||||||
|
|
||||||
|
## TLDR
|
||||||
|
- Be respectful.
|
||||||
|
- Abusive behavior is never tolerated.
|
||||||
|
- Data published to NodeBots is hosted at the discretion of the service administrators, and may be removed.
|
||||||
|
- Don't build evil robots.
|
||||||
|
- Violations of this code may result in swift and permanent expulsion from the NodeBots community.
|
||||||
21
node_modules/@serialport/bindings-interface/LICENSE
generated
vendored
Normal file
21
node_modules/@serialport/bindings-interface/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Francis Gulotta
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user