144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
import { SerialPort } from 'serialport'
|
|
import { PortInfo } from '@serialport/bindings-interface'
|
|
import { EventEmitter } from 'events'
|
|
|
|
// JTAG interface, TODO: change me!
|
|
const NANO_PRODUCT_ID = '1001'
|
|
const NANO_VENDOR_ID = '303A'
|
|
const NANO_BAUD_RATE = 115200
|
|
|
|
class NanoSerialApi extends EventEmitter {
|
|
all_nano_devices: { [key: string]: PortInfo } = {}
|
|
connected_nano_devices: { [key: string]: { port: SerialPort } } = {}
|
|
|
|
_list() {
|
|
return new Promise((resolve, reject) => {
|
|
SerialPort.list()
|
|
.then((ports: PortInfo[]) => {
|
|
const found_nano_devices: string[] = []
|
|
for (const port of ports) {
|
|
if (
|
|
port.productId?.toUpperCase() === NANO_PRODUCT_ID &&
|
|
port.vendorId?.toUpperCase() === NANO_VENDOR_ID &&
|
|
port.serialNumber
|
|
) {
|
|
found_nano_devices.push(port.serialNumber)
|
|
if (this.all_nano_devices[port.serialNumber] === undefined) {
|
|
this.all_nano_devices[port.serialNumber] = port
|
|
this.emit('nanoSerialApi:device-attached', port.serialNumber)
|
|
console.log('attached', port.serialNumber)
|
|
}
|
|
}
|
|
}
|
|
resolve(found_nano_devices)
|
|
for (const serialNumber in this.all_nano_devices) {
|
|
if (found_nano_devices.indexOf(serialNumber) === -1) {
|
|
delete this.all_nano_devices[serialNumber]
|
|
this.emit('nanoSerialApi:device-detached', serialNumber)
|
|
console.log('detached', serialNumber)
|
|
}
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
reject(error)
|
|
})
|
|
})
|
|
}
|
|
|
|
_handle_data(connected_port, data, serialNumber) {
|
|
connected_port.data += data
|
|
const lines = connected_port.data.split('\n')
|
|
if (lines.length > 1) {
|
|
for (let i = 0; i < lines.length - 1; i++) {
|
|
if (lines[i].length > 0) {
|
|
if (lines[i].startsWith('{'))
|
|
// if its a json object
|
|
this.emit('nanoSerialApi:update', serialNumber, lines[i])
|
|
else console.log('Device: ' + lines[i]) // otherwise just log it
|
|
}
|
|
}
|
|
connected_port.data = lines[lines.length - 1]
|
|
}
|
|
}
|
|
|
|
list_devices() {
|
|
const result: string[] = []
|
|
for (const [key, value] of Object.entries(this.all_nano_devices)) {
|
|
if (value.serialNumber) result.push(key)
|
|
}
|
|
console.log('list_devices', result)
|
|
return result
|
|
}
|
|
|
|
async send(deviceid, jsonstr) {
|
|
const connected_port = this.connected_nano_devices[deviceid]
|
|
if (connected_port === undefined) {
|
|
return Promise.reject('Device not connected')
|
|
} else {
|
|
connected_port.port.write(jsonstr + '\n')
|
|
return Promise.resolve()
|
|
}
|
|
}
|
|
|
|
async connect(deviceid) {
|
|
return new Promise((resolve, reject) => {
|
|
const nano_device = this.all_nano_devices[deviceid]
|
|
if (nano_device === undefined) {
|
|
reject('Device not attached')
|
|
} else {
|
|
console.log('nano_device', nano_device)
|
|
const port = new SerialPort({
|
|
path: nano_device.path,
|
|
baudRate: NANO_BAUD_RATE,
|
|
autoOpen: false
|
|
})
|
|
port.on('error', (err) => {
|
|
// forward error to FE
|
|
this.emit('nanoSerialApi:error', nano_device.serialNumber, err)
|
|
})
|
|
port.on('close', (err) => {
|
|
if (err && err.disconnected) {
|
|
// forward close to FE
|
|
this.emit('nanoSerialApi:disconnected', nano_device.serialNumber)
|
|
}
|
|
delete this.connected_nano_devices[nano_device.serialNumber!]
|
|
})
|
|
port.on('open', () => {
|
|
this.connected_nano_devices[nano_device.serialNumber!] = { port: port }
|
|
this.emit('nanoSerialApi:connected', nano_device.serialNumber)
|
|
resolve(nano_device.serialNumber)
|
|
})
|
|
port.on('data', (data) => {
|
|
const connected_port = this.connected_nano_devices[nano_device.serialNumber!]
|
|
this._handle_data(connected_port, data, nano_device.serialNumber)
|
|
})
|
|
port.open((err) => {
|
|
if (err) {
|
|
reject(err)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
disconnect(deviceid) {
|
|
return new Promise((resolve, reject) => {
|
|
const nano_device = this.all_nano_devices[deviceid]
|
|
if (nano_device === undefined) {
|
|
reject('Device not attached')
|
|
} else {
|
|
if (this.connected_nano_devices[nano_device.serialNumber!] === undefined) {
|
|
reject('Device not connected')
|
|
} else {
|
|
nano_device.close()
|
|
resolve(nano_device.serialNumber)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const nanoSerialApi = new NanoSerialApi()
|
|
|
|
export default nanoSerialApi
|