mirror of
https://github.com/silenty4ng/k5web
synced 2025-01-09 13:24:38 +00:00
update
This commit is contained in:
parent
3f1e49cc28
commit
b854d309bf
3 changed files with 289 additions and 7 deletions
BIN
public/L_BL001.bin
Normal file
BIN
public/L_BL001.bin
Normal file
Binary file not shown.
|
@ -19,6 +19,9 @@ import VueMatomo from 'vue-matomo';
|
||||||
const AutoUpdate = new Updater()
|
const AutoUpdate = new Updater()
|
||||||
AutoUpdate.on('update',()=>{
|
AutoUpdate.on('update',()=>{
|
||||||
setTimeout(async()=>{
|
setTimeout(async()=>{
|
||||||
|
if(process.env.NODE_ENV == 'development'){
|
||||||
|
return
|
||||||
|
}
|
||||||
const result = confirm('当前网站有更新,请点击确定刷新页面体验');
|
const result = confirm('当前网站有更新,请点击确定刷新页面体验');
|
||||||
if(result){
|
if(result){
|
||||||
location.reload();
|
location.reload();
|
||||||
|
|
|
@ -1,17 +1,296 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<Breadcrumb :items="[$t('menu.list'), $t('bl')]" />
|
<Breadcrumb :items="[$t('menu.list'), $t('bl')]" />
|
||||||
<a-card class="general-card">
|
<a-card class="general-card" :loading="loading">
|
||||||
<template #title>
|
<template #title>
|
||||||
|
<div style="color: red; font-weight: bold;">⚠:实验性功能 使用可能会损坏手台</div>
|
||||||
{{ $t('bl') }} {{ $t('global.onStart') }}
|
{{ $t('bl') }} {{ $t('global.onStart') }}
|
||||||
</template>
|
</template>
|
||||||
<t-divider>{{ $t('cs') }}</t-divider>
|
<a-row style="margin-bottom: 16px">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-space style="width: 130%">
|
||||||
|
<!-- <a-button type="primary" @click="readConfig">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
{{ $t('cps.onDeviceRead') }}(仅用于检视已用区块)
|
||||||
|
</a-button> -->
|
||||||
|
<a-button @click="writeConfig">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
{{ $t('cps.onDeviceWrite') }}
|
||||||
|
</a-button> (固件名称仅支持英文)
|
||||||
|
</a-space>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<div style="display: flex; justify-content: space-between; margin-left: 10px; margin-right: 10px; align-items: flex-end; margin-bottom: 3px;">
|
||||||
|
<div>EEPROM:</div>
|
||||||
|
<div>
|
||||||
|
{{ state.showAdd }}
|
||||||
|
<t-button size="small" variant="outline" @click="clearAll(256)">清空</t-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="width: 100%; overflow: scroll; user-select: none;">
|
||||||
|
<div style="height: 328px; display: flex; flex-direction: column; margin: 0; padding: 0; flex-wrap: wrap">
|
||||||
|
<div
|
||||||
|
@click="clearEp2(index)"
|
||||||
|
:ondragover="(event: any)=>{showAdd(index);event.preventDefault()}"
|
||||||
|
:ondrop="()=>{targetOver(item, index)}"
|
||||||
|
:title="
|
||||||
|
item == -2 ? '引导程序占用区' : (item != -1 ? state.rom[item].binaryName :
|
||||||
|
(index * 64 + 0x40000).toString(16).toUpperCase() + ' - ' + (index * 64 + 0x40000 + 63).toString(16).toUpperCase()
|
||||||
|
)"
|
||||||
|
:style="item == -1 ? 'background-color: white; border: 1px solid #ddd; height: 10px;' : (
|
||||||
|
item == -2 ? 'background-color: #373737; border: 1px solid #ddd; height: 10px;' : 'background-color: ' + state.rom[item].color + '; border: 1px solid #ddd; height: 10px;'
|
||||||
|
)"
|
||||||
|
:key="index" v-for="(item, index) in state.calendar">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-button style="margin-bottom: 10px;" @click="selectFile">{{ state.binaryFile ? state.binaryName : $t('tool.selectFirmware') }}</a-button>(选择固件后将固件卡片拖拽到上方 EEPROM)
|
||||||
|
<br>
|
||||||
|
<t-space break-line>
|
||||||
|
<t-card draggable="true" :ondragstart="()=>{state.nowDrag = index}" v-for="(item, index) in state.rom" :title="item.binaryName" :bordered="true" hover-shadow :style="{ width: '400px' }">
|
||||||
|
<template #actions>
|
||||||
|
<div :style="'width: 10px; height: 10px; background-color: ' + item.color + ';'"></div>
|
||||||
|
</template>
|
||||||
|
<t-input v-model="item.binaryName" @change="changeName(index)" show-limit-number :maxlength="13" />
|
||||||
|
</t-card>
|
||||||
|
</t-space>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
<div id="statusArea" style="height: 20em; background-color: azure; color: silver; overflow: auto; padding: 20px; margin-top: 10px;"
|
||||||
|
v-html="state.status"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import useLoading from '@/hooks/loading';
|
||||||
|
import { useAppStore } from '@/store';
|
||||||
|
import { eeprom_write, eeprom_reboot, eeprom_init, eeprom_read, uint8ArrayToString, stringToUint8Array, check_eeprom, hexReverseStringToUint8Array, unpack } from '@/utils/serial.js';
|
||||||
|
import { onMounted, reactive, nextTick } from 'vue';
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const { loading, setLoading } = useLoading(true);
|
||||||
|
|
||||||
|
const state : any = reactive({
|
||||||
|
calendar: [],
|
||||||
|
rom: [],
|
||||||
|
bl: undefined,
|
||||||
|
nowDrag: -1,
|
||||||
|
showAdd: '',
|
||||||
|
status: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const readRange = async (start: any, end: any) =>{
|
||||||
|
await eeprom_init(appStore.connectPort);
|
||||||
|
let rawEEPROM = new Uint8Array(end - start);
|
||||||
|
for (let i = start; i < end; i += 0x40) {
|
||||||
|
const data = await eeprom_read(appStore.connectPort, i, 0x40, appStore.configuration?.uart);
|
||||||
|
rawEEPROM.set(data, i - start);
|
||||||
|
}
|
||||||
|
return rawEEPROM;
|
||||||
|
}
|
||||||
|
|
||||||
|
const writeRange = async (start: any = 0, uint8Array: any, remark: string = '') => {
|
||||||
|
for (let i = start; i < uint8Array.length + start; i += 0x40) {
|
||||||
|
await eeprom_write(appStore.connectPort, i, uint8Array.slice(i - start, i - start + 0x40), uint8Array.slice(i - start, i - start + 0x40).length, appStore.configuration?.uart);
|
||||||
|
state.status = state.status + remark + "写入进度:" + (((i - start) / uint8Array.length) * 100).toFixed(1) + "%<br/>";
|
||||||
|
nextTick(()=>{
|
||||||
|
const textarea = document?.getElementById('statusArea');
|
||||||
|
if(textarea)textarea.scrollTop = textarea?.scrollHeight;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const showAdd = async (index: any) => {
|
||||||
|
state.showAdd = (index * 64 + 0x40000).toString(16).toUpperCase()
|
||||||
|
setTimeout(() => {
|
||||||
|
state.showAdd = ''
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
loadBL()
|
||||||
|
const calendar = []
|
||||||
|
for(let i=0; i < 262144 / 64; i++){
|
||||||
|
if(i < 0x44000 / 64 / 16 - 16){
|
||||||
|
calendar.push(-2);
|
||||||
|
}else{
|
||||||
|
calendar.push(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.calendar = calendar
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadBL = async() => {
|
||||||
|
const fontPacket = await fetch('/L_BL001.bin')
|
||||||
|
if(fontPacket.body){
|
||||||
|
const reader = fontPacket.body.getReader();
|
||||||
|
const chunks = [];
|
||||||
|
while(true) {
|
||||||
|
const {done, value} = await reader.read();
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chunks.push(...value)
|
||||||
|
}
|
||||||
|
let bl = new Uint8Array(0x3000);
|
||||||
|
bl.set(chunks, 0);
|
||||||
|
state.bl = bl;
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const readConfig = () =>{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const writeConfig = async () => {
|
||||||
|
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
|
||||||
|
const eepromSize = await check_eeprom(appStore.connectPort, appStore.configuration?.uart);
|
||||||
|
setLoading(true);
|
||||||
|
if(eepromSize < 0x80000){
|
||||||
|
alert("只支持 4Mbit 以上 EEPROM 写入");
|
||||||
|
setLoading(false);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await eeprom_init(appStore.connectPort);
|
||||||
|
await writeRange(0x41000, state.bl, '引导程序');
|
||||||
|
|
||||||
|
const firmware = [];
|
||||||
|
for(let i = 256; i < 4096; i++){
|
||||||
|
if(state.calendar[i] >= 0){
|
||||||
|
console.log(i);
|
||||||
|
firmware.push({
|
||||||
|
...state.rom[state.calendar[i]],
|
||||||
|
start: 0x40000 + i * 0x40,
|
||||||
|
end: 0x40000 + (i + Math.ceil(state.rom[state.calendar[i]].binaryFile.length / 0x40)) * 0x40 - 1,
|
||||||
|
})
|
||||||
|
i += Math.ceil(state.rom[state.calendar[i]].binaryFile.length / 0x40) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await writeRange(0x40000, new Uint8Array([firmware.length]), '固件数量');
|
||||||
|
|
||||||
|
const _name_bl_array = new Uint8Array(8);
|
||||||
|
_name_bl_array.set(stringToUint8Array("L_BL001"))
|
||||||
|
await writeRange(0X40008, _name_bl_array, '引导程序版本')
|
||||||
|
|
||||||
|
const writeMeta: any = [];
|
||||||
|
firmware.map((item: any)=>{
|
||||||
|
const _meta_name = new Uint8Array(16)
|
||||||
|
const _meta_address_start = new Uint8Array(4)
|
||||||
|
const _meta_address_end = new Uint8Array(4)
|
||||||
|
_meta_name.set(stringToUint8Array(item.binaryName))
|
||||||
|
_meta_address_start.set(hexReverseStringToUint8Array((item.start).toString(16)));
|
||||||
|
_meta_address_end.set(hexReverseStringToUint8Array((item.end).toString(16)));
|
||||||
|
writeMeta.push(..._meta_name, ..._meta_address_start, ..._meta_address_end, ...new Uint8Array(8))
|
||||||
|
})
|
||||||
|
await writeRange(0x40020, writeMeta, '固件元数据')
|
||||||
|
|
||||||
|
for(let i = 0; i < firmware.length; i++){
|
||||||
|
await writeRange(firmware[i].start, firmware[i].binaryFile, firmware[i].binaryName + ' 固件文件')
|
||||||
|
}
|
||||||
|
|
||||||
|
await eeprom_reboot(appStore.connectPort);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectFile = () => {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.onchange = async () => {
|
||||||
|
if(input.files){
|
||||||
|
const blob = new Blob([input.files[0]], { type: 'application/octet-stream' });
|
||||||
|
const rawEEPROM = new Uint8Array(await blob.arrayBuffer());
|
||||||
|
const firmware = {
|
||||||
|
binaryFile: unpack(rawEEPROM),
|
||||||
|
binaryName: input.files[0].name,
|
||||||
|
color: getColor()
|
||||||
|
}
|
||||||
|
state.rom.push(firmware)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetOver = (can: number, slot: any) => {
|
||||||
|
if(slot < 256){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(slot + Math.ceil(state.rom[state.nowDrag].binaryFile.length / 0x40) > 4096){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(can == 2){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for(let i = slot; i < slot + Math.ceil(state.rom[state.nowDrag].binaryFile.length / 0x40); i += 1){
|
||||||
|
clearEp(i);
|
||||||
|
}
|
||||||
|
for(let i = slot; i < slot + Math.ceil(state.rom[state.nowDrag].binaryFile.length / 0x40); i += 1){
|
||||||
|
state.calendar[i] = state.nowDrag
|
||||||
|
}
|
||||||
|
console.log((slot * 64 + 0x40000).toString(16))
|
||||||
|
console.log((Math.ceil(state.rom[state.nowDrag].binaryFile.length / 0x40) * 0x40 + (slot * 64 + 0x40000) - 1).toString(16))
|
||||||
|
}
|
||||||
|
|
||||||
|
const getColor = () => {
|
||||||
|
var letters = '0123456789ABCDEF';
|
||||||
|
var color = '#';
|
||||||
|
for (var i = 0; i < 6; i++) {
|
||||||
|
color += letters[Math.floor(Math.random() * 16)];
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearEp = (i: number) => {
|
||||||
|
if(i > 4095 || i < 256){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let flag = 0
|
||||||
|
if(state.calendar[i] != -1){
|
||||||
|
flag = 1
|
||||||
|
state.calendar[i] = -1
|
||||||
|
}
|
||||||
|
if(flag){
|
||||||
|
if(state.calendar[i - 1] != -1){
|
||||||
|
clearEp(i - 1)
|
||||||
|
}
|
||||||
|
if(state.calendar[i + 1] != -1){
|
||||||
|
clearEp(i + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearEp2 = (i: number) => {
|
||||||
|
if(i > 4095 || i < 256){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let flag = -99
|
||||||
|
if(state.calendar[i] != -1){
|
||||||
|
flag = state.calendar[i]
|
||||||
|
state.calendar[i] = -1
|
||||||
|
}
|
||||||
|
if(state.calendar[i - 1] === flag){
|
||||||
|
clearEp2(i - 1)
|
||||||
|
}
|
||||||
|
if(state.calendar[i + 1] === flag){
|
||||||
|
clearEp2(i + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearAll = (i: number) => {
|
||||||
|
if(i > 4095 || i < 256){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.calendar[i] = -1
|
||||||
|
clearAll(i + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeName = (val: any) => {
|
||||||
|
state.rom[val].binaryName = state.rom[val].binaryName.replace(/[^\a-\z\A-\Z0-9.]/g, '')
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
Loading…
Reference in a new issue