feat: send data to and from serial port
This commit is contained in:
parent
ae68c4dc6e
commit
7594474189
3 changed files with 184 additions and 79 deletions
|
|
@ -33,6 +33,16 @@ new Vue({
|
|||
show: false
|
||||
},
|
||||
|
||||
serial: {
|
||||
selectedPort: null,
|
||||
writableStreamClosed: null,
|
||||
writer: null,
|
||||
readableStreamClosed: null,
|
||||
reader: null,
|
||||
showAdvancedConfig: false,
|
||||
config: {}
|
||||
},
|
||||
|
||||
formDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
|
|
@ -500,8 +510,7 @@ new Vue({
|
|||
LNbits.utils.notifyApiError(err)
|
||||
}
|
||||
},
|
||||
sharePsbtOnSerialPort: async function () {
|
||||
console.log('### sharePsbtOnSerialPort', navigator.serial, navigator)
|
||||
checkSerialPortSupported: function () {
|
||||
if (!navigator.serial) {
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
|
|
@ -510,8 +519,14 @@ new Vue({
|
|||
'Make sure your browser supports Serial Port and that you are using HTTPS.',
|
||||
timeout: 10000
|
||||
})
|
||||
return
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
openSerialPort: async function () {
|
||||
if (!this.checkSerialPortSupported()) return
|
||||
console.log('### openSerialPort', this.serial.selectedPort)
|
||||
try {
|
||||
navigator.serial.addEventListener('connect', event => {
|
||||
console.log('### navigator.serial event: connected!', event)
|
||||
})
|
||||
|
|
@ -519,37 +534,104 @@ new Vue({
|
|||
navigator.serial.addEventListener('disconnect', event => {
|
||||
console.log('### navigator.serial event: disconnected!', event)
|
||||
})
|
||||
try {
|
||||
// const ports = await navigator.serial.getPorts();
|
||||
const port = await navigator.serial.requestPort()
|
||||
console.log('### port', port)
|
||||
|
||||
this.serial.selectedPort = await navigator.serial.requestPort()
|
||||
// Wait for the serial port to open.
|
||||
await port.open({baudRate: 9600})
|
||||
await this.serial.selectedPort.open({baudRate: 9600})
|
||||
this.startSerialPortReading()
|
||||
|
||||
const writer = port.writable.getWriter()
|
||||
|
||||
const psbtByteArray = Uint8Array.from(
|
||||
atob(this.payment.psbtBase64),
|
||||
c => c.charCodeAt(0)
|
||||
const textEncoder = new TextEncoderStream()
|
||||
this.serial.writableStreamClosed = textEncoder.readable.pipeTo(
|
||||
this.serial.selectedPort.writable
|
||||
)
|
||||
await writer.write(psbtByteArray)
|
||||
|
||||
// Allow the serial port to be closed later.
|
||||
writer.releaseLock()
|
||||
|
||||
await port.close()
|
||||
console.log('### sharePsbtOnSerialPort done')
|
||||
this.serial.writer = textEncoder.writable.getWriter()
|
||||
} catch (error) {
|
||||
console.log('### error', error)
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Serial port communication failed!',
|
||||
message: 'Cannot open serial port!',
|
||||
caption: `${error}`,
|
||||
timeout: 10000
|
||||
})
|
||||
}
|
||||
},
|
||||
closeSerialPort: async function () {
|
||||
try {
|
||||
console.log('### closeSerialPort', this.serial.selectedPort)
|
||||
if (this.serial.writer) this.serial.writer.close()
|
||||
if (this.serial.writableStreamClosed)
|
||||
await this.serial.writableStreamClosed
|
||||
if (this.serial.reader) this.reader.writer.close()
|
||||
if (this.serial.readableStreamClosed)
|
||||
await this.serial.readableStreamClosed
|
||||
if (this.serial.selectedPort) await this.serial.selectedPort.close()
|
||||
this.serial.selectedPort = null
|
||||
} catch (error) {
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Cannot close serial port!',
|
||||
caption: `${error}`,
|
||||
timeout: 10000
|
||||
})
|
||||
}
|
||||
},
|
||||
sendPsbtToSerialPort: async function () {
|
||||
try {
|
||||
await this.serial.writer.write(this.payment.psbtBase64 + '\n')
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'Data sent to serial port!',
|
||||
timeout: 5000
|
||||
})
|
||||
} catch (error) {
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Failed to send data to serial port!',
|
||||
caption: `${error}`,
|
||||
timeout: 10000
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
startSerialPortReading: async function () {
|
||||
const port = this.serial.selectedPort
|
||||
|
||||
while (port && port.readable) {
|
||||
const textDecoder = new TextDecoderStream()
|
||||
this.serial.readableStreamClosed = port.readable.pipeTo(
|
||||
textDecoder.writable
|
||||
)
|
||||
this.serial.reader = textDecoder.readable.getReader()
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
console.log('### reader.read()')
|
||||
const {value, done} = await this.serial.reader.read()
|
||||
if (value) {
|
||||
console.log(value)
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Received data from serial port (not psbt)',
|
||||
caption: value.slice(0, 80) + '...',
|
||||
timeout: 5000
|
||||
})
|
||||
}
|
||||
if (done) {
|
||||
this.serial.reader.close()
|
||||
this.serial.readereadableStreamClosed()
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Serial port communication error!',
|
||||
caption: `${error}`,
|
||||
timeout: 10000
|
||||
})
|
||||
}
|
||||
}
|
||||
console.log('### startSerialPortReading DONE')
|
||||
},
|
||||
sharePsbtWithAnimatedQRCode: async function () {
|
||||
console.log('### sharePsbtWithAnimatedQRCode')
|
||||
},
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ const tableData = {
|
|||
fee: 0,
|
||||
txSize: 0,
|
||||
psbtBase64: '',
|
||||
psbtBase64Signed: '',
|
||||
utxoSelectionModes: [
|
||||
'Manual',
|
||||
'Random',
|
||||
|
|
@ -268,6 +269,18 @@ const tableData = {
|
|||
'Larger Inputs First'
|
||||
],
|
||||
utxoSelectionMode: 'Manual',
|
||||
signModes: [
|
||||
{
|
||||
label: 'Serial Port',
|
||||
value: 'serial-port'
|
||||
},
|
||||
{
|
||||
label: 'Animated QR',
|
||||
value: 'animated-qr',
|
||||
disable: true
|
||||
}
|
||||
],
|
||||
signMode: '',
|
||||
show: false,
|
||||
showAdvanced: false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1009,72 +1009,82 @@
|
|||
</div>
|
||||
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-4 q-pr-lg">
|
||||
<div class="col-3 q-pr-lg">
|
||||
<q-btn unelevated color="secondary" type="submit"
|
||||
>Create PSBT</q-btn
|
||||
>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<q-btn-dropdown
|
||||
<div class="col-9">
|
||||
<q-input
|
||||
v-if="payment.psbtBase64"
|
||||
split
|
||||
class="float-right"
|
||||
color="secondary"
|
||||
label="Share PSBT"
|
||||
@click="sharePsbtOnSerialPort"
|
||||
>
|
||||
<q-list>
|
||||
<q-item
|
||||
@click="sharePsbtOnSerialPort"
|
||||
clickable
|
||||
v-close-popup
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
icon="usb"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
v-model="payment.psbtBase64"
|
||||
filled
|
||||
readonly
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>Serial Port</q-item-label>
|
||||
<q-item-label caption
|
||||
>Send the PSBT using an USB port
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item
|
||||
@click="sharePsbtWithAnimatedQRCode"
|
||||
disabled
|
||||
v-close-popup
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar
|
||||
icon="qr_code"
|
||||
color="secondary"
|
||||
text-color="white"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>Animated QR Code</q-item-label>
|
||||
<q-item-label caption>Comming Soon</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="payment.psbtBase64"
|
||||
class="row items-center no-wrap q-mb-md"
|
||||
>
|
||||
<div class="col-12">
|
||||
<div class="col-3">Sign With</div>
|
||||
<div class="col-9">
|
||||
<q-option-group
|
||||
v-model="payment.signMode"
|
||||
:options="payment.signModes"
|
||||
color="primary"
|
||||
label="Sign Mode"
|
||||
inline
|
||||
></q-option-group>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator></q-separator>
|
||||
<div
|
||||
v-if="payment.psbtBase64 && payment.signMode === 'serial-port'"
|
||||
class="row items-center no-wrap q-mb-md q-mt-lg"
|
||||
>
|
||||
<div class="col-3"></div>
|
||||
<div class="col-3">
|
||||
<q-btn
|
||||
v-if="!serial.selectedPort"
|
||||
@click="openSerialPort()"
|
||||
unelevated
|
||||
color="secondary"
|
||||
>Connect</q-btn
|
||||
>
|
||||
<q-btn
|
||||
v-if="serial.selectedPort"
|
||||
@click="closeSerialPort()"
|
||||
outline
|
||||
color="gray"
|
||||
>Disconnect</q-btn
|
||||
>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<q-btn
|
||||
v-if="serial.selectedPort"
|
||||
@click="sendPsbtToSerialPort()"
|
||||
unelevated
|
||||
color="secondary float-right"
|
||||
>Send PSBT</q-btn
|
||||
>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<q-toggle
|
||||
label="Advanced Config"
|
||||
color="secodary float-right"
|
||||
v-model="serial.showAdvancedConfig"
|
||||
></q-toggle>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row items-center no-wrap q-mb-md">
|
||||
<div class="col-4 q-pr-lg"></div>
|
||||
<div class="col-8">
|
||||
<q-input
|
||||
v-model="payment.psbtBase64"
|
||||
v-if="payment.psbtBase64Signed"
|
||||
v-model="payment.psbtBase64Signed"
|
||||
filled
|
||||
readonly
|
||||
type="textarea"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue