Commit 4c0b613a authored by Skye Yu's avatar Skye Yu

Merge branch 'useWorker'

parents 587cd7ac a0cab8d1
...@@ -103,6 +103,7 @@ declare class Jensen { ...@@ -103,6 +103,7 @@ declare class Jensen {
getDeviceInfo: (time?: number) => Promise<DeviceInfo>; getDeviceInfo: (time?: number) => Promise<DeviceInfo>;
listFiles: (time?: number) => Promise<FileInfo[]>; listFiles: (time?: number) => Promise<FileInfo[]>;
fileStreaming: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void, onprogress?: (size: number) => void) => void;
getFile: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void, onprogress?: (size: number) => void) => void; getFile: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void, onprogress?: (size: number) => void) => void;
getFilePart: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void, onprogress?: (size: number) => void) => void; getFilePart: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void, onprogress?: (size: number) => void) => void;
getFileBlock: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void) => Promise<ReturnStruct['common']>; getFileBlock: (fileName: string, length: number, on?: (msg: Uint8Array | 'fail') => void) => Promise<ReturnStruct['common']>;
......
...@@ -7,7 +7,7 @@ const jensen = new Jensen(); ...@@ -7,7 +7,7 @@ const jensen = new Jensen();
export function Home() { export function Home() {
const [files, setFiles] = useState<Jensen.FileInfo[]>([]); const [files, setFiles] = useState<Jensen.FileInfo[]>([]);
const [devices, setDevices] = useState<Jensen.BluetoothDevice[]>([]); const [devices, setDevices] = useState<Jensen.BluetoothDevice[]>([]);
const [greeting, setGreeting] = useState<string|null>(null); const [greeting, setGreeting] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
jensen.connect(); jensen.connect();
...@@ -31,97 +31,113 @@ export function Home() { ...@@ -31,97 +31,113 @@ export function Home() {
}; };
let bluetoothDevices: BluetoothDevice[] = []; let bluetoothDevices: BluetoothDevice[] = [];
const bluetoothScan = async () => { const bluetoothScan = async () => {
setDevices([]); setDevices([]);
setGreeting('scan started at: ' + new Date().toLocaleString()); setGreeting('scan started at: ' + new Date().toLocaleString());
let devices = await jensen.scanDevices(); let devices = await jensen.scanDevices();
// console.log(devices); // console.log(devices);
setDevices(devices); setDevices(devices);
setGreeting(null) setGreeting(null);
} };
const disconnectBTDevice = async () => { const disconnectBTDevice = async () => {
let r = await jensen.disconnectBTDevice(); let r = await jensen.disconnectBTDevice();
console.log(r); console.log(r);
} };
const clsBtnConnect = { const clsBtnConnect = {
height: '30px', height: '30px',
padding: '0px 20px', padding: '0px 20px',
position: 'absolute', position: 'absolute' as const,
right: '0px', right: '0px',
top: '3px', top: '3px',
cursor: 'pointer' cursor: 'pointer'
} };
const clsBleDevice = { const clsBleDevice = {
height: '40px', height: '40px',
lineHeight: '40px', lineHeight: '40px',
minWidth: '500px', minWidth: '500px',
position: 'relative', position: 'relative' as const,
display: 'inline-block' display: 'inline-block'
} };
const clsBleName = { const clsBleName = {
fontSize: '16px', fontSize: '16px',
fontFamily: 'consolas' fontFamily: 'consolas'
} };
const doConnectBluetooth = async (mac:string) => { const doConnectBluetooth = async (mac: string) => {
// alert(mac); // alert(mac);
let rst = await jensen.connectBTDevice(mac, 10); let rst = await jensen.connectBTDevice(mac, 10);
alert('connect: ' + rst.result); alert('connect: ' + rst.result);
} };
const getTime = async () => { const getTime = async () => {
let time = await jensen.getTime(); let time = await jensen.getTime();
alert(JSON.stringify(time)); alert(JSON.stringify(time));
} };
const listFiles = async () => { const listFiles = async () => {
let files = await jensen.listFiles(); let files = await jensen.listFiles();
console.log(files); console.log(files);
} };
const getBluetoothStatus = async () => { const getBluetoothStatus = async () => {
let info = await jensen.getBluetoothStatus(); let info = await jensen.getBluetoothStatus();
alert(JSON.stringify(info)); alert(JSON.stringify(info));
} };
return ( return (
<> <>
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px', padding: '16px', alignItems: 'center' }}> <div style={{ display: 'flex', flexDirection: 'row', gap: '16px', padding: '16px', alignItems: 'center' }}>
<button style={{ width: '200px', height: '50px' }} onClick={() => jensen.connect()}> <button style={{ width: '200px', height: '50px' }} onClick={() => jensen.connect()}>
Connect Connect
</button> </button>
<button style={{ width: '200px', height: '50px' }} onClick={getFilePart}> <button style={{ width: '200px', height: '50px' }} onClick={getFilePart}>
get File Part get File Part
</button> </button>
<button style={{ width: '200px', height: '50px' }} onClick={getTime}> <button style={{ width: '200px', height: '50px' }} onClick={getTime}>
Get Time Get Time
</button> </button>
<button style={{ width: '200px', height: '50px' }} onClick={listFiles}>List Files</button> <button style={{ width: '200px', height: '50px' }} onClick={listFiles}>
<button style={{ width: '200px', height: '50px' }} onClick={getBluetoothStatus}>Bluetooth Status</button> List Files
<button style={{ width : '200px', height : '50px' }} onClick={bluetoothScan}>Bluetooth Scan</button> </button>
<button style={{ width : '200px', height : '50px' }} onClick={disconnectBTDevice}>Bluetooth Disconnect</button> <button style={{ width: '200px', height: '50px' }} onClick={getBluetoothStatus}>
</div> Bluetooth Status
<div style={{ padding: '0px 0px 0px 30px', width: '500px' }}> </button>
<h3>Bluetooth Device List: </h3> <button style={{ width: '200px', height: '50px' }} onClick={bluetoothScan}>
{ Bluetooth Scan
greeting ? <div>{greeting}</div> : <></> </button>
} <button style={{ width: '200px', height: '50px' }} onClick={disconnectBTDevice}>
{ Bluetooth Disconnect
devices && devices.length ? ( </button>
</div>
<div style={{ padding: '0px 0px 0px 30px', width: '500px' }}>
<h3>Bluetooth Device List: </h3>
{greeting ? <div>{greeting}</div> : <></>}
{devices && devices.length ? (
devices.map((item, index) => { devices.map((item, index) => {
return ( return (
<div style={clsBleDevice}><span style={clsBleName}>({item.mac}) {item.name}</span><button style={clsBtnConnect} onClick={() => { doConnectBluetooth(item.mac) }}>Connect</button></div> <div style={clsBleDevice}>
<span style={clsBleName}>
({item.mac}) {item.name}
</span>
<button
style={clsBtnConnect}
onClick={() => {
doConnectBluetooth(item.mac);
}}
>
Connect
</button>
</div>
); );
}) })
) : ( ) : (
<div>no devices...</div> <div>no devices...</div>
) )}
} </div>
</div>
</> </>
); );
} }
import { Logger as internalLogger, formatTime, shortcutKeys, sliceTime } from './utils'; import { Logger as internalLogger, formatTime, shortcutKeys, sliceTime, TaskQueue } from './utils';
const INVAILD = 0x00; const INVAILD = 0x00;
const QUERY_DEVICE_INFO = 0x01; const QUERY_DEVICE_INFO = 0x01;
...@@ -66,6 +66,8 @@ const COMMAND_NAMES = { ...@@ -66,6 +66,8 @@ const COMMAND_NAMES = {
let Logger = null; let Logger = null;
const taskQueue = new TaskQueue();
function Jensen(log) { function Jensen(log) {
Logger = log || internalLogger; Logger = log || internalLogger;
let device = null; let device = null;
...@@ -92,8 +94,14 @@ function Jensen(log) { ...@@ -92,8 +94,14 @@ function Jensen(log) {
this.onconnect = null; this.onconnect = null;
this.onreceive = null; this.onreceive = null;
this.streamingBegin = false;
const RECV_BUFF_SIZE = 51200; const RECV_BUFF_SIZE = 51200;
let worker = null;
let streamingByteView = new Uint8Array(new ArrayBuffer(RECV_BUFF_SIZE * 2));
let streamingBuffLength = 0;
const _check_conn_status = () => { const _check_conn_status = () => {
if (device?.opened === false) { if (device?.opened === false) {
try { try {
...@@ -148,6 +156,15 @@ function Jensen(log) { ...@@ -148,6 +156,15 @@ function Jensen(log) {
}; };
this.connect = async function () { this.connect = async function () {
if (window.Worker) {
worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
worker.onmessage = (data) => {
if (this.streamingBegin) {
taskQueue.addTask(() => continueDecode(data.data));
tryReceive();
}
};
}
Logger.debug('jensen', 'connect', 'connect'); Logger.debug('jensen', 'connect', 'connect');
let r = await self.tryconnect(); let r = await self.tryconnect();
if (r) return; if (r) return;
...@@ -319,7 +336,12 @@ function Jensen(log) { ...@@ -319,7 +336,12 @@ function Jensen(log) {
if (device) if (device)
device.transferIn(2, RECV_BUFF_SIZE).then((r) => { device.transferIn(2, RECV_BUFF_SIZE).then((r) => {
Logger.save?.('jensen', 'tryReceive', r?.data); Logger.save?.('jensen', 'tryReceive', r?.data);
receive(r); console.log('tryReceive', self.streamingBegin);
if (self.streamingBegin) {
worker.postMessage(r.data);
} else {
receive(r);
}
}); });
}; };
...@@ -347,6 +369,44 @@ function Jensen(log) { ...@@ -347,6 +369,44 @@ function Jensen(log) {
} }
}; };
this.resetStreamingData = () => {
streamingByteView = new ArrayBuffer(RECV_BUFF_SIZE * 2);
streamingBuffLength = 0;
this.streamingBegin = false;
};
const continueDecode = (block) => {
for (let k = 0; k < block.byteLength; k++) {
streamingByteView[k + streamingBuffLength] = block.getInt8(k);
}
streamingBuffLength += block.byteLength;
let rst = null;
let _startIndex = 0;
while (true) {
try {
rst = decodeMessage(streamingByteView, _startIndex, streamingBuffLength);
} catch (e) {
let msgid = parseInt(current.replace(/^cmd-(\d+)-(\d+)$/gi, '$1'));
let handler = Jensen.handlers[msgid];
handler(null, self);
trigger(null, msgid);
break;
}
if (rst == null) {
break;
}
const handler = Jensen.handlers[rst.message.id];
const r = handler(rst.message, self);
r && trigger(r, rst.message.id);
_startIndex += rst.length;
}
for (let k = 0, bs = streamingBuffLength - _startIndex; k < bs; k++) {
streamingByteView[k] = streamingByteView[k + _startIndex];
}
streamingBuffLength = streamingBuffLength - _startIndex;
return 'finished';
};
const tryDecode = function () { const tryDecode = function () {
// 一个容器,比单独任意一个小包要大一点儿,好像还差一点儿 // 一个容器,比单独任意一个小包要大一点儿,好像还差一点儿
let stime = new Date(); let stime = new Date();
...@@ -430,7 +490,10 @@ function Jensen(log) { ...@@ -430,7 +490,10 @@ function Jensen(log) {
const decodeMessage = function (dataView, startIndex, buffLength) { const decodeMessage = function (dataView, startIndex, buffLength) {
let dataLen = buffLength - startIndex; let dataLen = buffLength - startIndex;
if (dataLen < 12) return null; if (dataLen < 12) return null;
if (dataView[startIndex + 0] !== 0x12 || dataView[startIndex + 1] !== 0x34) throw new Error('invalid header'); if (dataView[startIndex + 0] !== 0x12 || dataView[startIndex + 1] !== 0x34) {
console.log('0000000000000000000000', dataView);
throw new Error('invalid header');
}
// 2 字节的指令id // 2 字节的指令id
let idx = 2; let idx = 2;
// let cmdid = this.nextShort(idx); // let cmdid = this.nextShort(idx);
...@@ -455,7 +518,10 @@ function Jensen(log) { ...@@ -455,7 +518,10 @@ function Jensen(log) {
// 需要去除的字节数 // 需要去除的字节数
var cutLen = 0; var cutLen = 0;
// 数据还没有完全准备好 // 数据还没有完全准备好
if (dataLen < 12 + len + padding) return null; if (dataLen < 12 + len + padding) {
console.log(dataLen, len, padding);
return null;
}
// 去掉header部分 // 去掉header部分
// 下面这一行做什么用的? // 下面这一行做什么用的?
// for (let i = 0; i < 12; i++) this.buffer[i + cutLen]; // for (let i = 0; i < 12; i++) this.buffer[i + cutLen];
...@@ -738,7 +804,7 @@ Jensen.prototype.setTime = async function (time, seconds) { ...@@ -738,7 +804,7 @@ Jensen.prototype.setTime = async function (time, seconds) {
return this.send(new Command(SET_DEVICE_TIME).body(this.to_bcd(str)), seconds); return this.send(new Command(SET_DEVICE_TIME).body(this.to_bcd(str)), seconds);
}; };
Jensen.prototype.streaming = async function (filename, length, ondata, onprogress) { Jensen.prototype.fileStreaming = async function (filename, length, ondata, onprogress) {
if (typeof length != 'number') throw new Error('parameter `length` required'); if (typeof length != 'number') throw new Error('parameter `length` required');
if (length <= 0) throw new Error('parameter `length` must greater than zero'); if (length <= 0) throw new Error('parameter `length` must greater than zero');
...@@ -754,14 +820,17 @@ Jensen.prototype.streaming = async function (filename, length, ondata, onprogres ...@@ -754,14 +820,17 @@ Jensen.prototype.streaming = async function (filename, length, ondata, onprogres
ondata(msg.body); ondata(msg.body);
Logger.info('jensen', 'streaming length', `${length} ${flen}`); Logger.info('jensen', 'streaming length', `${length} ${flen}`);
if (flen >= length) { if (flen >= length) {
this.resetStreamingData();
Logger.info('jensen', 'streaming', 'file download finish.'); Logger.info('jensen', 'streaming', 'file download finish.');
return 'OK'; return 'OK';
} }
} else { } else {
this.resetStreamingData();
Logger.info('jensen', 'streaming', 'file download fail.'); Logger.info('jensen', 'streaming', 'file download fail.');
ondata('fail'); ondata('fail');
} }
}; };
this.streamingBegin = true;
this.onreceive = onprogress; this.onreceive = onprogress;
Jensen.registerHandler(TRANSFER_FILE, handler); Jensen.registerHandler(TRANSFER_FILE, handler);
this.send(new Command(TRANSFER_FILE).body(fname)); this.send(new Command(TRANSFER_FILE).body(fname));
...@@ -953,6 +1022,7 @@ Jensen.prototype.getRecordingFile = function (seconds) { ...@@ -953,6 +1022,7 @@ Jensen.prototype.getRecordingFile = function (seconds) {
Jensen.prototype.recordTestStart = async function (type, seconds) { Jensen.prototype.recordTestStart = async function (type, seconds) {
return this.send(new Command(0xf008).body([type]), seconds); return this.send(new Command(0xf008).body([type]), seconds);
}; };
Jensen.prototype.recordTestEnd = async function (type, seconds) { Jensen.prototype.recordTestEnd = async function (type, seconds) {
return this.send(new Command(0xf009).body([type]), seconds); return this.send(new Command(0xf009).body([type]), seconds);
}; };
......
...@@ -326,3 +326,13 @@ export const shortcutKeys = { ...@@ -326,3 +326,13 @@ export const shortcutKeys = {
Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes] Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
} }
}; };
export class TaskQueue {
constructor() {
this.queue = Promise.resolve();
}
addTask(task) {
this.queue = this.queue.then(() => task());
}
}
// worker.js
self.onmessage = function (event) {
self.postMessage(event.data);
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment