mirror of
https://github.com/silenty4ng/k5web
synced 2025-01-06 20:02: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.
11
src/main.ts
11
src/main.ts
|
@ -19,10 +19,13 @@ import VueMatomo from 'vue-matomo';
|
|||
const AutoUpdate = new Updater()
|
||||
AutoUpdate.on('update',()=>{
|
||||
setTimeout(async()=>{
|
||||
const result = confirm('当前网站有更新,请点击确定刷新页面体验');
|
||||
if(result){
|
||||
location.reload();
|
||||
}
|
||||
if(process.env.NODE_ENV == 'development'){
|
||||
return
|
||||
}
|
||||
const result = confirm('当前网站有更新,请点击确定刷新页面体验');
|
||||
if(result){
|
||||
location.reload();
|
||||
}
|
||||
},500)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,17 +1,296 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="[$t('menu.list'), $t('bl')]" />
|
||||
<a-card class="general-card">
|
||||
<a-card class="general-card" :loading="loading">
|
||||
<template #title>
|
||||
<div style="color: red; font-weight: bold;">⚠:实验性功能 使用可能会损坏手台</div>
|
||||
{{ $t('bl') }} {{ $t('global.onStart') }}
|
||||
</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>
|
||||
<div id="statusArea" style="height: 20em; background-color: azure; color: silver; overflow: auto; padding: 20px; margin-top: 10px;"
|
||||
v-html="state.status"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<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 lang="ts">
|
||||
|
|
Loading…
Reference in a new issue