Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not quite working: Posix TZ hotswap #110

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 55 additions & 9 deletions stores/firmwareStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { saveAs } from 'file-saver';
import { mande } from 'mande';
import { defineStore } from 'pinia';
import type { Terminal } from 'xterm';
import { timezones } from '~/types/resources';

import { track } from '@vercel/analytics';
import { useSessionStorage } from '@vueuse/core';
Expand All @@ -26,8 +27,8 @@ import {
import { createUrl } from './store';

const previews = new Array<FirmwareResource>()// new Array<FirmwareResource>(currentPrerelease)

const firmwareApi = mande(createUrl('api/github/firmware/list'))
const TZ_PLACEHOLDER = 'tzplaceholder '

export const useFirmwareStore = defineStore('firmware', {
state: () => {
Expand Down Expand Up @@ -124,7 +125,28 @@ export const useFirmwareStore = defineStore('firmware', {
};
const transport = new Transport(this.port, true);
const espLoader = await this.connectEsp32(transport, terminal);
const content = await this.fetchBinaryContent(fileName);
let content = await this.fetchBinaryContent(fileName, true);
let originalAppContent = await this.fetchBinaryContent(fileName);

const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
// get posix timezone string based on browser locale
const posixTz = timezones[tz as keyof typeof timezones] + "\0";
if (posixTz)
content = content.replace(TZ_PLACEHOLDER, posixTz.padEnd(TZ_PLACEHOLDER.length, ' '));

// The file is padded with zeros until its size is one byte less than a multiple of 16 bytes. A last byte (thus making the file size a multiple of 16) is the checksum of the data of all segments. The checksum is defined as the xor-sum of all bytes and the byte 0xEF.
// Do all of our devices have 8 segments? Can get that from the 2nd byte of the header
const calculateChecksum = calcChecksum(convertToUint8Array(content), 8);
const appDataWithChecksum = new Uint8Array([...convertToUint8Array(content), ...new Uint8Array([calculateChecksum])]);
console.log(appDataWithChecksum.length)
// esp32 checksum
const sha256sum = await crypto.subtle.digest('SHA-256', appDataWithChecksum);
console.log(appDataWithChecksum.length)
content = convertToBinaryString(new Uint8Array([...appDataWithChecksum, ...new Uint8Array(sha256sum)]));
console.log(originalAppContent === content);
console.log('Length:', content.length);
console.log('Original length:', originalAppContent.length);

this.isFlashing = true;
const flashOptions: FlashOptions = {
fileArray: [{ data: content, address: 0x10000 }],
Expand Down Expand Up @@ -178,7 +200,24 @@ export const useFirmwareStore = defineStore('firmware', {
};
const transport = new Transport(this.port, true);
const espLoader = await this.connectEsp32(transport, terminal);
const appContent = await this.fetchBinaryContent(fileName);
let appContent = await this.fetchBinaryContent(fileName, true);
const originalAppContent = await this.fetchBinaryContent(fileName);
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
// get posix timezone string based on browser locale
const posixTz = timezones[tz as keyof typeof timezones] + "\0";
if (posixTz)
appContent = appContent.replace(TZ_PLACEHOLDER, posixTz.padEnd(TZ_PLACEHOLDER.length, ' '));

// The file is padded with zeros until its size is one byte less than a multiple of 16 bytes. A last byte (thus making the file size a multiple of 16) is the checksum of the data of all segments. The checksum is defined as the xor-sum of all bytes and the byte 0xEF.
// Do all of our devices have 8 segments? Can get that from the 2nd byte of the header
const calculateChecksum = calcChecksum(convertToUint8Array(appContent).slice(65536), 8);
const appDataWithChecksum = new Uint8Array([...convertToUint8Array(appContent), ...new Uint8Array([calculateChecksum])]);
// esp32 checksum
const sha256sum = await crypto.subtle.digest('SHA-256', appDataWithChecksum.slice(65536));
appContent = convertToBinaryString(new Uint8Array([...appDataWithChecksum, ...new Uint8Array(sha256sum)]));
console.log(originalAppContent === appContent);
console.log('Length:', appContent.length);
console.log('Original length:', originalAppContent.length);
const otaContent = await this.fetchBinaryContent(otaFileName);
const littleFsContent = await this.fetchBinaryContent(littleFsFileName);
this.isFlashing = true;
Expand All @@ -201,12 +240,15 @@ export const useFirmwareStore = defineStore('firmware', {
};
await this.startWrite(terminal, espLoader, transport, flashOptions);
},
async fetchBinaryContent(fileName: string): Promise<string> {
async fetchBinaryContent(fileName: string, truncateChecksum = false): Promise<string> {
if (this.selectedFirmware?.zip_url) {
const baseUrl = getCorsFriendyReleaseUrl(this.selectedFirmware.zip_url);
const response = await fetch(`${baseUrl}/${fileName}`);
const blob = await response.blob();
const data = await blob.arrayBuffer();
let data = await blob.arrayBuffer();
if (truncateChecksum)
data = data.slice(0, data.byteLength - 33);

return convertToBinaryString(new Uint8Array(data));
}
if (this.selectedFile && this.isZipFile) {
Expand All @@ -225,13 +267,17 @@ export const useFirmwareStore = defineStore('firmware', {
console.log('Found file:', file.filename);
if (file?.getData) {
const blob = await file.getData(new BlobWriter());
const arrayBuffer = await blob.arrayBuffer();
let arrayBuffer = await blob.arrayBuffer();
if (truncateChecksum)
arrayBuffer = arrayBuffer.slice(0, arrayBuffer.byteLength - 33);
return convertToBinaryString(new Uint8Array(arrayBuffer));
}
throw new Error(`Could not find file with pattern ${fileName} in zip`);
}
} else if (this.selectedFile && !this.isZipFile) {
const buffer = await this.selectedFile.arrayBuffer();
let buffer = await this.selectedFile.arrayBuffer();
if (truncateChecksum)
buffer = buffer.slice(0, buffer.byteLength - 33);
return convertToBinaryString(new Uint8Array(buffer));
}
throw new Error('Cannot fetch binary content without a file or firmware selected');
Expand Down Expand Up @@ -269,12 +315,12 @@ export const useFirmwareStore = defineStore('firmware', {
const reader = inputStream.getReader();

while (true) {
const{ value } = await reader.read();
const { value } = await reader.read();
if (value) {
terminal.write(value);
}
await new Promise(resolve => setTimeout(resolve, 5));
}
},
},
})
})
Loading