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

Merge branch 'useWorker'

parents 587cd7ac a0cab8d1
......@@ -103,6 +103,7 @@ declare class Jensen {
getDeviceInfo: (time?: number) => Promise<DeviceInfo>;
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;
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']>;
......
......@@ -7,7 +7,7 @@ const jensen = new Jensen();
export function Home() {
const [files, setFiles] = useState<Jensen.FileInfo[]>([]);
const [devices, setDevices] = useState<Jensen.BluetoothDevice[]>([]);
const [greeting, setGreeting] = useState<string|null>(null);
const [greeting, setGreeting] = useState<string | null>(null);
useEffect(() => {
jensen.connect();
......@@ -31,97 +31,113 @@ export function Home() {
};
let bluetoothDevices: BluetoothDevice[] = [];
const bluetoothScan = async () => {
const bluetoothScan = async () => {
setDevices([]);
setGreeting('scan started at: ' + new Date().toLocaleString());
let devices = await jensen.scanDevices();
// console.log(devices);
setDevices(devices);
setGreeting(null)
}
setGreeting(null);
};
const disconnectBTDevice = async () => {
let r = await jensen.disconnectBTDevice();
console.log(r);
}
};
const clsBtnConnect = {
height: '30px',
padding: '0px 20px',
position: 'absolute',
position: 'absolute' as const,
right: '0px',
top: '3px',
cursor: 'pointer'
}
};
const clsBleDevice = {
height: '40px',
lineHeight: '40px',
lineHeight: '40px',
minWidth: '500px',
position: 'relative',
position: 'relative' as const,
display: 'inline-block'
}
};
const clsBleName = {
fontSize: '16px',
fontFamily: 'consolas'
}
};
const doConnectBluetooth = async (mac:string) => {
const doConnectBluetooth = async (mac: string) => {
// alert(mac);
let rst = await jensen.connectBTDevice(mac, 10);
alert('connect: ' + rst.result);
}
};
const getTime = async () => {
let time = await jensen.getTime();
alert(JSON.stringify(time));
}
};
const listFiles = async () => {
let files = await jensen.listFiles();
console.log(files);
}
};
const getBluetoothStatus = async () => {
let info = await jensen.getBluetoothStatus();
alert(JSON.stringify(info));
}
};
return (
<>
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px', padding: '16px', alignItems: 'center' }}>
<button style={{ width: '200px', height: '50px' }} onClick={() => jensen.connect()}>
Connect
</button>
<button style={{ width: '200px', height: '50px' }} onClick={getFilePart}>
get File Part
</button>
<button style={{ width: '200px', height: '50px' }} onClick={getTime}>
Get Time
</button>
<button style={{ width: '200px', height: '50px' }} onClick={listFiles}>List Files</button>
<button style={{ width: '200px', height: '50px' }} onClick={getBluetoothStatus}>Bluetooth Status</button>
<button style={{ width : '200px', height : '50px' }} onClick={bluetoothScan}>Bluetooth Scan</button>
<button style={{ width : '200px', height : '50px' }} onClick={disconnectBTDevice}>Bluetooth Disconnect</button>
</div>
<div style={{ padding: '0px 0px 0px 30px', width: '500px' }}>
<h3>Bluetooth Device List: </h3>
{
greeting ? <div>{greeting}</div> : <></>
}
{
devices && devices.length ? (
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px', padding: '16px', alignItems: 'center' }}>
<button style={{ width: '200px', height: '50px' }} onClick={() => jensen.connect()}>
Connect
</button>
<button style={{ width: '200px', height: '50px' }} onClick={getFilePart}>
get File Part
</button>
<button style={{ width: '200px', height: '50px' }} onClick={getTime}>
Get Time
</button>
<button style={{ width: '200px', height: '50px' }} onClick={listFiles}>
List Files
</button>
<button style={{ width: '200px', height: '50px' }} onClick={getBluetoothStatus}>
Bluetooth Status
</button>
<button style={{ width: '200px', height: '50px' }} onClick={bluetoothScan}>
Bluetooth Scan
</button>
<button style={{ width: '200px', height: '50px' }} onClick={disconnectBTDevice}>
Bluetooth Disconnect
</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) => {
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>
)}
</div>
</>
);
}
import { Logger as internalLogger, formatTime, shortcutKeys, sliceTime } from './utils';
import { Logger as internalLogger, formatTime, shortcutKeys, sliceTime, TaskQueue } from './utils';
const INVAILD = 0x00;
const QUERY_DEVICE_INFO = 0x01;
......@@ -66,6 +66,8 @@ const COMMAND_NAMES = {
let Logger = null;
const taskQueue = new TaskQueue();
function Jensen(log) {
Logger = log || internalLogger;
let device = null;
......@@ -92,8 +94,14 @@ function Jensen(log) {
this.onconnect = null;
this.onreceive = null;
this.streamingBegin = false;
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 = () => {
if (device?.opened === false) {
try {
......@@ -148,6 +156,15 @@ function Jensen(log) {
};
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');
let r = await self.tryconnect();
if (r) return;
......@@ -319,7 +336,12 @@ function Jensen(log) {
if (device)
device.transferIn(2, RECV_BUFF_SIZE).then((r) => {
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) {
}
};
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 () {
// 一个容器,比单独任意一个小包要大一点儿,好像还差一点儿
let stime = new Date();
......@@ -430,7 +490,10 @@ function Jensen(log) {
const decodeMessage = function (dataView, startIndex, buffLength) {
let dataLen = buffLength - startIndex;
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
let idx = 2;
// let cmdid = this.nextShort(idx);
......@@ -455,7 +518,10 @@ function Jensen(log) {
// 需要去除的字节数
var cutLen = 0;
// 数据还没有完全准备好
if (dataLen < 12 + len + padding) return null;
if (dataLen < 12 + len + padding) {
console.log(dataLen, len, padding);
return null;
}
// 去掉header部分
// 下面这一行做什么用的?
// for (let i = 0; i < 12; i++) this.buffer[i + cutLen];
......@@ -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);
};
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 (length <= 0) throw new Error('parameter `length` must greater than zero');
......@@ -754,14 +820,17 @@ Jensen.prototype.streaming = async function (filename, length, ondata, onprogres
ondata(msg.body);
Logger.info('jensen', 'streaming length', `${length} ${flen}`);
if (flen >= length) {
this.resetStreamingData();
Logger.info('jensen', 'streaming', 'file download finish.');
return 'OK';
}
} else {
this.resetStreamingData();
Logger.info('jensen', 'streaming', 'file download fail.');
ondata('fail');
}
};
this.streamingBegin = true;
this.onreceive = onprogress;
Jensen.registerHandler(TRANSFER_FILE, handler);
this.send(new Command(TRANSFER_FILE).body(fname));
......@@ -953,6 +1022,7 @@ Jensen.prototype.getRecordingFile = function (seconds) {
Jensen.prototype.recordTestStart = async function (type, seconds) {
return this.send(new Command(0xf008).body([type]), seconds);
};
Jensen.prototype.recordTestEnd = async function (type, seconds) {
return this.send(new Command(0xf009).body([type]), seconds);
};
......
......@@ -326,3 +326,13 @@ export const shortcutKeys = {
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