22// Copyright (c) 2020-2021 The Pybricks Authors
33
44import JSZip , { JSZipObject } from 'jszip' ;
5- import { PACKAGE_VERSION } from './version' ;
5+ import { PACKAGE_VERSION } from './version' ;
6+
7+ const encoder = new TextEncoder ( ) ;
68
79/**
810 * String containing the firmware version.
911 */
10- export const firmwareVersion = PACKAGE_VERSION . substring ( PACKAGE_VERSION . lastIndexOf ( 'v' ) + 1 ) ;
12+ export const firmwareVersion = PACKAGE_VERSION . substring (
13+ PACKAGE_VERSION . lastIndexOf ( 'v' ) + 1
14+ ) ;
1115
1216/**
1317 * LEGO Powered Up Hub IDs
@@ -58,6 +62,12 @@ export interface FirmwareMetadata {
5862 'user-mpy-offset' : number ;
5963 /** The maximum firmware size allowed on the hub. */
6064 'max-firmware-size' : number ;
65+ /** The offset to where the hub name is stored in the firmware. (since v1.1.0) */
66+ 'hub-name-offset' : number | undefined ;
67+ /** The maximum size of the firmware name in bytes, including the zero-termination. (since v1.1.0) */
68+ 'max-hub-name-size' : number | undefined ;
69+ /** The SHA256 hash of the firmware. (since v1.1.0) */
70+ 'firmware-sha256' : string | undefined ;
6171}
6272
6373/** Types of errors that can be raised by FirmwareReader. */
@@ -75,22 +85,20 @@ export enum FirmwareReaderErrorCode {
7585}
7686
7787/** Maps error codes to error messages. */
78- const firmwareReaderErrorMessage : ReadonlyMap <
79- FirmwareReaderErrorCode ,
80- string
81- > = new Map ( [
82- [ FirmwareReaderErrorCode . ZipError , 'bad zip data' ] ,
83- [
84- FirmwareReaderErrorCode . MissingFirmwareBaseBin ,
85- 'missing firmware-base.bin' ,
86- ] ,
87- [
88- FirmwareReaderErrorCode . MissingMetadataJson ,
89- 'missing firmware.metadata.json' ,
90- ] ,
91- [ FirmwareReaderErrorCode . MissingMainPy , 'missing main.py' ] ,
92- [ FirmwareReaderErrorCode . MissingReadmeOssTxt , 'ReadMe_OSS.txt' ] ,
93- ] ) ;
88+ const firmwareReaderErrorMessage : ReadonlyMap < FirmwareReaderErrorCode , string > =
89+ new Map ( [
90+ [ FirmwareReaderErrorCode . ZipError , 'bad zip data' ] ,
91+ [
92+ FirmwareReaderErrorCode . MissingFirmwareBaseBin ,
93+ 'missing firmware-base.bin' ,
94+ ] ,
95+ [
96+ FirmwareReaderErrorCode . MissingMetadataJson ,
97+ 'missing firmware.metadata.json' ,
98+ ] ,
99+ [ FirmwareReaderErrorCode . MissingMainPy , 'missing main.py' ] ,
100+ [ FirmwareReaderErrorCode . MissingReadmeOssTxt , 'ReadMe_OSS.txt' ] ,
101+ ] ) ;
94102
95103/** Errors throw by FirmwareReader */
96104export class FirmwareReaderError extends Error {
@@ -159,7 +167,9 @@ export class FirmwareReader {
159167 * Loads data from a firmware.zip file and does a few sanity checks.
160168 * @param zipData The firmware.zip file binary data.
161169 */
162- public static async load ( zipData : Uint8Array | ArrayBuffer | Blob ) : Promise < FirmwareReader > {
170+ public static async load (
171+ zipData : Uint8Array | ArrayBuffer | Blob
172+ ) : Promise < FirmwareReader > {
163173 const reader = new FirmwareReader ( ) ;
164174 const zip = await wrapError (
165175 ( ) => JSZip . loadAsync ( zipData ) ,
@@ -217,3 +227,34 @@ export class FirmwareReader {
217227 return this . readMeOss ! . async ( 'text' ) ;
218228 }
219229}
230+
231+ /**
232+ * Encodes a firmware name as UTF-8 bytes with zero-termination.
233+ *
234+ * If the name is too long to fit in the size specified by the metadata, the
235+ * name will be truncated. The resulting value can be written to the firmware
236+ * image at 'hub-name-offset'.
237+ *
238+ * @param name The hub name.
239+ * @param metadata The firmware metadata.
240+ */
241+ export function encodeHubName (
242+ name : string ,
243+ metadata : FirmwareMetadata
244+ ) : Uint8Array {
245+ if ( metadata [ 'max-hub-name-size' ] === undefined ) {
246+ throw new Error ( 'firmware image does not support firmware name' ) ;
247+ }
248+
249+ // fall back to default on empty name
250+ if ( ! name ) {
251+ name = 'Pybricks Hub' ;
252+ }
253+
254+ const bytes = new Uint8Array ( metadata [ 'max-hub-name-size' ] ) ;
255+
256+ // subarray ensures zero termination if encoded length is >= 'max-hub-name-size'.
257+ encoder . encodeInto ( name , bytes . subarray ( 0 , bytes . length - 1 ) ) ;
258+
259+ return bytes ;
260+ }
0 commit comments