初步实现OTA功能

This commit is contained in:
tpu
2025-07-20 18:00:29 +08:00
parent 7b2aa28acc
commit e461c0dca0
8 changed files with 159 additions and 8 deletions

View File

@@ -13,8 +13,10 @@
<div id="current_voltage"></div>
<div id="current_time"></div>
<div id="system_time"></div>
<div id="update_progress"></div>
<script src="log.js"></script>
<script src="https://cdn.sheetjs.com/crc-32-latest/package/crc32.js"></script>
<script>
var connected = false;
@@ -87,6 +89,7 @@
connected = true;
document.getElementById('setime-button').disabled = false;
document.getElementById('upfirm-button').disabled = false;
document.getElementById('connect-button').textContent = "断开";
} catch (error) {
console.log('连接失败:', error);
@@ -94,6 +97,9 @@
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
async function onSetTime() {
document.getElementById('setime-button').disabled = true;
@@ -139,6 +145,130 @@
document.getElementById('setime-button').disabled = false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
function readFileAsArrayBuffer(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
}
function find_patten(target, patten) {
tlen = target.length;
plen = patten.length;
for(i=0; i<tlen-plen; i++){
for(j=0; j<plen; j++){
if(target[i+j] !== patten[j]){
break;
}
}
if(j==plen)
return i;
}
return -1;
}
async function onUpdate() {
document.getElementById('upfirm-button').disabled = true;
var firm_size;
var firm_buf;
try{
console.log('准备打开文件');
const file_handle = await window.showOpenFilePicker({
types: [{
description: 'Firm files',
accept: {
'text/plain': ['.bin'],
},
}]
});
console.log('选择文件: ', file_handle);
const file = await file_handle[0].getFile();
console.log('file: ', file);
abuf = await readFileAsArrayBuffer(file);
firm_buf = new Uint8Array(abuf);
firm_size = file.size;
}catch(err){
console.log('文件读取失败: ', err);
document.getElementById('upfirm-button').disabled = false;
return;
}
firm_magic = new Uint8Array([0x79, 0x13, 0xa5, 0xf9, 0x86, 0xec, 0x5a, 0x06]);
pos = find_patten(firm_buf, firm_magic);
if(pos == -1) {
console.log('无效固件: 未找到版本号!');
document.getElementById('upfirm-button').disabled = false;
return;
}
firm_ver = firm_buf[pos+9]*256+firm_buf[pos+8];
console.log('固件版本:', firm_ver);
console.log('固件大小:', firm_size);
firm_crc = CRC32.buf(firm_buf);
console.log('固件CRC:', (firm_crc >>> 0).toString(16));
var buf = new Uint8Array(136);
dataView = new DataView(buf.buffer);
console.log('开始升级');
buf[0] = 0xa0;
buf[1] = 0x00;
dataView.setUint16(2, firm_size, true);
await longValue.writeValue(buf);
var pos = 0;
for(i=0; i<firm_size+64; i+=256){
console.log('发送', i);
buf.fill(0xff);
if(i==0){
dataView.setUint32(8+0, 0x00aa5170, true);
dataView.setUint32(8+4, firm_size, true);
dataView.setUint32(8+8, firm_crc, true);
dataView.setUint32(8+28, (0xa50f0000+firm_ver), true);
buf[8+32] = 0;
buf[0] = 0xa2;
buf.set(firm_buf.subarray(pos, pos+64), 8+64);
await longValue.writeValue(buf);
pos += 64;
}else{
buf[0] = 0xa2;
buf.set(firm_buf.subarray(pos, pos+128), 8);
await longValue.writeValue(buf);
pos += 128;
}
buf[0] = 0xa3;
buf.set(firm_buf.subarray(pos, pos+128), 8);
await longValue.writeValue(buf);
pos += 128;
document.getElementById('update_progress').textContent =
'升级进度: '+((100*pos/(firm_size+64))>>0)+'%';
}
console.log('发送完毕');
buf[0] = 0xa4;
buf[1] = 0x00;
buf[2] = 0x00;
buf[3] = 0x00;
await longValue.writeValue(buf);
console.log('升级结束');
document.getElementById('upfirm-button').disabled = false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
function disconnect() {
document.getElementById('setime-button').disabled = true;
if(!device)
@@ -159,6 +289,7 @@
document.getElementById('connect-button').addEventListener('click', onClick);
document.getElementById('setime-button').addEventListener('click', onSetTime);
document.getElementById('upfirm-button').addEventListener('click', onUpdate);
</script>
</body>
</html>