996 lines
No EOL
26 KiB
JavaScript
996 lines
No EOL
26 KiB
JavaScript
"use strict";
|
|
|
|
// copy entire configkeys.h from https://github.com/microsoft/pxt-common-packages/blob/master/libs/base/configkeys.h
|
|
const CONFIG_KEYS_H =
|
|
`
|
|
#ifndef __PXT_CONFIGKEYS_H
|
|
#define __PXT_CONFIGKEYS_H
|
|
|
|
// used by pins.cpp to mask off the pin name from any config
|
|
// lower 16 pins of value are the pin name
|
|
#define CFG_PIN_NAME_MSK 0x0000ffff
|
|
// upper 16 bits of value is any configuration of the pin.
|
|
#define CFG_PIN_CONFIG_MSK 0xffff0000
|
|
|
|
// begin optional pin configurations
|
|
#define CFG_PIN_CONFIG_ACTIVE_LO 0x10000
|
|
|
|
|
|
#define CFG_MAGIC0 0x1e9e10f1
|
|
#define CFG_MAGIC1 0x20227a79
|
|
|
|
// these define keys for getConfig() function
|
|
#define CFG_PIN_ACCELEROMETER_INT 1
|
|
#define CFG_PIN_ACCELEROMETER_SCL 2
|
|
#define CFG_PIN_ACCELEROMETER_SDA 3
|
|
#define CFG_PIN_BTN_A 4
|
|
#define CFG_PIN_BTN_B 5
|
|
#define CFG_PIN_BTN_SLIDE 6
|
|
#define CFG_PIN_DOTSTAR_CLOCK 7
|
|
#define CFG_PIN_DOTSTAR_DATA 8
|
|
#define CFG_PIN_FLASH_CS 9
|
|
#define CFG_PIN_FLASH_MISO 10
|
|
#define CFG_PIN_FLASH_MOSI 11
|
|
#define CFG_PIN_FLASH_SCK 12
|
|
#define CFG_PIN_LED 13
|
|
#define CFG_PIN_LIGHT 14
|
|
#define CFG_PIN_MICROPHONE 15
|
|
#define CFG_PIN_MIC_CLOCK 16
|
|
#define CFG_PIN_MIC_DATA 17
|
|
#define CFG_PIN_MISO 18
|
|
#define CFG_PIN_MOSI 19
|
|
#define CFG_PIN_NEOPIXEL 20
|
|
#define CFG_PIN_RX 21
|
|
#define CFG_PIN_RXLED 22
|
|
#define CFG_PIN_SCK 23
|
|
#define CFG_PIN_SCL 24
|
|
#define CFG_PIN_SDA 25
|
|
#define CFG_PIN_SPEAKER_AMP 26
|
|
#define CFG_PIN_TEMPERATURE 27
|
|
#define CFG_PIN_TX 28
|
|
#define CFG_PIN_TXLED 29
|
|
#define CFG_PIN_IR_OUT 30
|
|
#define CFG_PIN_IR_IN 31
|
|
#define CFG_PIN_DISPLAY_SCK 32
|
|
#define CFG_PIN_DISPLAY_MISO 33
|
|
#define CFG_PIN_DISPLAY_MOSI 34
|
|
#define CFG_PIN_DISPLAY_CS 35
|
|
#define CFG_PIN_DISPLAY_DC 36
|
|
#define CFG_DISPLAY_WIDTH 37
|
|
#define CFG_DISPLAY_HEIGHT 38
|
|
#define CFG_DISPLAY_CFG0 39
|
|
#define CFG_DISPLAY_CFG1 40
|
|
#define CFG_DISPLAY_CFG2 41
|
|
#define CFG_DISPLAY_CFG3 42
|
|
#define CFG_PIN_DISPLAY_RST 43
|
|
#define CFG_PIN_DISPLAY_BL 44
|
|
#define CFG_PIN_SERVO_1 45
|
|
#define CFG_PIN_SERVO_2 46
|
|
#define CFG_PIN_BTN_LEFT 47
|
|
#define CFG_PIN_BTN_RIGHT 48
|
|
#define CFG_PIN_BTN_UP 49
|
|
#define CFG_PIN_BTN_DOWN 50
|
|
#define CFG_PIN_BTN_MENU 51
|
|
#define CFG_PIN_LED_R 52
|
|
#define CFG_PIN_LED_G 53
|
|
#define CFG_PIN_LED_B 54
|
|
#define CFG_PIN_LED1 55
|
|
#define CFG_PIN_LED2 56
|
|
#define CFG_PIN_LED3 57
|
|
#define CFG_PIN_LED4 58
|
|
#define CFG_SPEAKER_VOLUME 59
|
|
|
|
#define CFG_PIN_JACK_TX 60
|
|
#define CFG_PIN_JACK_SENSE 61
|
|
#define CFG_PIN_JACK_HPEN 62
|
|
#define CFG_PIN_JACK_BZEN 63
|
|
#define CFG_PIN_JACK_PWREN 64
|
|
#define CFG_PIN_JACK_SND 65
|
|
#define CFG_PIN_JACK_BUSLED 66
|
|
#define CFG_PIN_JACK_COMMLED 67
|
|
|
|
#define CFG_PIN_BTN_SOFT_RESET 69
|
|
#define CFG_ACCELEROMETER_TYPE 70
|
|
#define CFG_PIN_BTNMX_LATCH 71
|
|
#define CFG_PIN_BTNMX_CLOCK 72
|
|
#define CFG_PIN_BTNMX_DATA 73
|
|
#define CFG_PIN_BTN_MENU2 74
|
|
#define CFG_PIN_BATTSENSE 75
|
|
#define CFG_PIN_VIBRATION 76
|
|
#define CFG_PIN_PWREN 77
|
|
#define CFG_DISPLAY_TYPE 78
|
|
|
|
#define CFG_PIN_ROTARY_ENCODER_A 79
|
|
#define CFG_PIN_ROTARY_ENCODER_B 80
|
|
|
|
#define CFG_ACCELEROMETER_SPACE 81
|
|
|
|
#define CFG_PIN_WIFI_MOSI 82
|
|
#define CFG_PIN_WIFI_MISO 83
|
|
#define CFG_PIN_WIFI_SCK 84
|
|
#define CFG_PIN_WIFI_TX 85
|
|
#define CFG_PIN_WIFI_RX 86
|
|
#define CFG_PIN_WIFI_CS 87
|
|
#define CFG_PIN_WIFI_BUSY 88
|
|
#define CFG_PIN_WIFI_RESET 89
|
|
#define CFG_PIN_WIFI_GPIO0 90
|
|
|
|
// default I2C address
|
|
#define ACCELEROMETER_TYPE_LIS3DH 0x32
|
|
#define ACCELEROMETER_TYPE_LIS3DH_ALT 0x30
|
|
#define ACCELEROMETER_TYPE_MMA8453 0x38
|
|
#define ACCELEROMETER_TYPE_FXOS8700 0x3C
|
|
#define ACCELEROMETER_TYPE_MMA8653 0x3A
|
|
#define ACCELEROMETER_TYPE_MSA300 0x4C
|
|
#define ACCELEROMETER_TYPE_MPU6050 0x68
|
|
|
|
#define DISPLAY_TYPE_ST7735 7735
|
|
#define DISPLAY_TYPE_ILI9341 9341
|
|
|
|
#define CFG_PIN_A0 100
|
|
#define CFG_PIN_A1 101
|
|
#define CFG_PIN_A2 102
|
|
#define CFG_PIN_A3 103
|
|
#define CFG_PIN_A4 104
|
|
#define CFG_PIN_A5 105
|
|
#define CFG_PIN_A6 106
|
|
#define CFG_PIN_A7 107
|
|
#define CFG_PIN_A8 108
|
|
#define CFG_PIN_A9 109
|
|
#define CFG_PIN_A10 110
|
|
#define CFG_PIN_A11 111
|
|
#define CFG_PIN_A12 112
|
|
#define CFG_PIN_A13 113
|
|
#define CFG_PIN_A14 114
|
|
#define CFG_PIN_A15 115
|
|
#define CFG_PIN_A16 116
|
|
#define CFG_PIN_A17 117
|
|
#define CFG_PIN_A18 118
|
|
#define CFG_PIN_A19 119
|
|
#define CFG_PIN_A20 120
|
|
#define CFG_PIN_A21 121
|
|
#define CFG_PIN_A22 122
|
|
#define CFG_PIN_A23 123
|
|
#define CFG_PIN_A24 124
|
|
#define CFG_PIN_A25 125
|
|
#define CFG_PIN_A26 126
|
|
#define CFG_PIN_A27 127
|
|
#define CFG_PIN_A28 128
|
|
#define CFG_PIN_A29 129
|
|
#define CFG_PIN_A30 130
|
|
#define CFG_PIN_A31 131
|
|
|
|
#define CFG_PIN_D0 150
|
|
#define CFG_PIN_D1 151
|
|
#define CFG_PIN_D2 152
|
|
#define CFG_PIN_D3 153
|
|
#define CFG_PIN_D4 154
|
|
#define CFG_PIN_D5 155
|
|
#define CFG_PIN_D6 156
|
|
#define CFG_PIN_D7 157
|
|
#define CFG_PIN_D8 158
|
|
#define CFG_PIN_D9 159
|
|
#define CFG_PIN_D10 160
|
|
#define CFG_PIN_D11 161
|
|
#define CFG_PIN_D12 162
|
|
#define CFG_PIN_D13 163
|
|
#define CFG_PIN_D14 164
|
|
#define CFG_PIN_D15 165
|
|
#define CFG_PIN_D16 166
|
|
#define CFG_PIN_D17 167
|
|
#define CFG_PIN_D18 168
|
|
#define CFG_PIN_D19 169
|
|
#define CFG_PIN_D20 170
|
|
#define CFG_PIN_D21 171
|
|
#define CFG_PIN_D22 172
|
|
#define CFG_PIN_D23 173
|
|
#define CFG_PIN_D24 174
|
|
#define CFG_PIN_D25 175
|
|
#define CFG_PIN_D26 176
|
|
#define CFG_PIN_D27 177
|
|
#define CFG_PIN_D28 178
|
|
#define CFG_PIN_D29 179
|
|
#define CFG_PIN_D30 180
|
|
#define CFG_PIN_D31 181
|
|
|
|
#define CFG_NUM_NEOPIXELS 200
|
|
#define CFG_NUM_DOTSTARS 201
|
|
#define CFG_DEFAULT_BUTTON_MODE 202
|
|
#define CFG_SWD_ENABLED 203
|
|
#define CFG_FLASH_BYTES 204
|
|
#define CFG_RAM_BYTES 205
|
|
#define CFG_SYSTEM_HEAP_BYTES 206
|
|
#define CFG_LOW_MEM_SIMULATION_KB 207
|
|
#define CFG_BOOTLOADER_BOARD_ID 208
|
|
#define CFG_UF2_FAMILY 209
|
|
#define CFG_PINS_PORT_SIZE 210
|
|
#define CFG_BOOTLOADER_PROTECTION 211
|
|
#define CFG_POWER_DEEPSLEEP_TIMEOUT 212
|
|
#define CFG_ANALOG_BUTTON_THRESHOLD 213
|
|
#define CFG_CPU_MHZ 214
|
|
#define CFG_CONTROLLER_LIGHT_MAX_BRIGHTNESS 215
|
|
|
|
#define CFG_PIN_B0 300
|
|
#define CFG_PIN_B1 301
|
|
#define CFG_PIN_B2 302
|
|
#define CFG_PIN_B3 303
|
|
#define CFG_PIN_B4 304
|
|
#define CFG_PIN_B5 305
|
|
#define CFG_PIN_B6 306
|
|
#define CFG_PIN_B7 307
|
|
#define CFG_PIN_B8 308
|
|
#define CFG_PIN_B9 309
|
|
#define CFG_PIN_B10 310
|
|
#define CFG_PIN_B11 311
|
|
#define CFG_PIN_B12 312
|
|
#define CFG_PIN_B13 313
|
|
#define CFG_PIN_B14 314
|
|
#define CFG_PIN_B15 315
|
|
#define CFG_PIN_B16 316
|
|
#define CFG_PIN_B17 317
|
|
#define CFG_PIN_B18 318
|
|
#define CFG_PIN_B19 319
|
|
#define CFG_PIN_B20 320
|
|
#define CFG_PIN_B21 321
|
|
#define CFG_PIN_B22 322
|
|
#define CFG_PIN_B23 323
|
|
#define CFG_PIN_B24 324
|
|
#define CFG_PIN_B25 325
|
|
#define CFG_PIN_B26 326
|
|
#define CFG_PIN_B27 327
|
|
#define CFG_PIN_B28 328
|
|
#define CFG_PIN_B29 329
|
|
#define CFG_PIN_B30 330
|
|
#define CFG_PIN_B31 331
|
|
|
|
#define CFG_PIN_C0 350
|
|
#define CFG_PIN_C1 351
|
|
#define CFG_PIN_C2 352
|
|
#define CFG_PIN_C3 353
|
|
#define CFG_PIN_C4 354
|
|
#define CFG_PIN_C5 355
|
|
#define CFG_PIN_C6 356
|
|
#define CFG_PIN_C7 357
|
|
#define CFG_PIN_C8 358
|
|
#define CFG_PIN_C9 359
|
|
#define CFG_PIN_C10 360
|
|
#define CFG_PIN_C11 361
|
|
#define CFG_PIN_C12 362
|
|
#define CFG_PIN_C13 363
|
|
#define CFG_PIN_C14 364
|
|
#define CFG_PIN_C15 365
|
|
#define CFG_PIN_C16 366
|
|
#define CFG_PIN_C17 367
|
|
#define CFG_PIN_C18 368
|
|
#define CFG_PIN_C19 369
|
|
#define CFG_PIN_C20 370
|
|
#define CFG_PIN_C21 371
|
|
#define CFG_PIN_C22 372
|
|
#define CFG_PIN_C23 373
|
|
#define CFG_PIN_C24 374
|
|
#define CFG_PIN_C25 375
|
|
#define CFG_PIN_C26 376
|
|
#define CFG_PIN_C27 377
|
|
#define CFG_PIN_C28 378
|
|
#define CFG_PIN_C29 379
|
|
#define CFG_PIN_C30 380
|
|
#define CFG_PIN_C31 381
|
|
|
|
#define CFG_PIN_P0 400
|
|
#define CFG_PIN_P1 401
|
|
#define CFG_PIN_P2 402
|
|
#define CFG_PIN_P3 403
|
|
#define CFG_PIN_P4 404
|
|
#define CFG_PIN_P5 405
|
|
#define CFG_PIN_P6 406
|
|
#define CFG_PIN_P7 407
|
|
#define CFG_PIN_P8 408
|
|
#define CFG_PIN_P9 409
|
|
#define CFG_PIN_P10 410
|
|
#define CFG_PIN_P11 411
|
|
#define CFG_PIN_P12 412
|
|
#define CFG_PIN_P13 413
|
|
#define CFG_PIN_P14 414
|
|
#define CFG_PIN_P15 415
|
|
#define CFG_PIN_P16 416
|
|
#define CFG_PIN_P17 417
|
|
#define CFG_PIN_P18 418
|
|
#define CFG_PIN_P19 419
|
|
#define CFG_PIN_P20 420
|
|
#define CFG_PIN_P21 421
|
|
#define CFG_PIN_P22 422
|
|
#define CFG_PIN_P23 423
|
|
#define CFG_PIN_P24 424
|
|
#define CFG_PIN_P25 425
|
|
#define CFG_PIN_P26 426
|
|
#define CFG_PIN_P27 427
|
|
#define CFG_PIN_P28 428
|
|
#define CFG_PIN_P29 429
|
|
#define CFG_PIN_P30 430
|
|
#define CFG_PIN_P31 431
|
|
|
|
#define CFG_PIN_LORA_MISO 1001
|
|
#define CFG_PIN_LORA_MOSI 1002
|
|
#define CFG_PIN_LORA_SCK 1003
|
|
#define CFG_PIN_LORA_CS 1004
|
|
#define CFG_PIN_LORA_BOOT 1005
|
|
#define CFG_PIN_LORA_RESET 1006
|
|
#define CFG_PIN_IRRXLED 1007
|
|
#define CFG_PIN_IRTXLED 1008
|
|
#define CFG_PIN_LCD_RESET 1009
|
|
#define CFG_PIN_LCD_ENABLE 1010
|
|
#define CFG_PIN_LCD_DATALINE4 1011
|
|
#define CFG_PIN_LCD_DATALINE5 1012
|
|
#define CFG_PIN_LCD_DATALINE6 1013
|
|
#define CFG_PIN_LCD_DATALINE7 1014
|
|
#define CFG_NUM_LCD_COLUMNS 1015
|
|
#define CFG_NUM_LCD_ROWS 1016
|
|
|
|
#endif
|
|
`
|
|
|
|
const configKeys = {}
|
|
CONFIG_KEYS_H.replace(/#define\s+CFG_(\w+)\s+(\w+)/g, function(m, name, value) {
|
|
configKeys[name] = parseInt(value);
|
|
return "";
|
|
})
|
|
|
|
const enums = {
|
|
// these are the same as the default I2C ID
|
|
ACCELEROMETER_TYPE: {
|
|
LIS3DH: 0x32,
|
|
LIS3DH_ALT: 0x30,
|
|
MMA8453: 0x38,
|
|
FXOS8700: 0x3C,
|
|
MMA8653: 0x3A,
|
|
MSA300: 0x4C,
|
|
MPU6050: 0x68,
|
|
},
|
|
UF2_FAMILY: {
|
|
ATSAMD21: 0x68ed2b88,
|
|
ATSAMD51: 0x55114460,
|
|
NRF52840: 0x1b57745f,
|
|
STM32F103: 0x5ee21072,
|
|
STM32F401: 0x57755a57,
|
|
ATMEGA32: 0x16573617,
|
|
CYPRESS_FX2: 0x5a18069b,
|
|
},
|
|
PINS_PORT_SIZE: {
|
|
PA_16: 0x10, // PA00-PA15, PB00-PB15, ... - STM32
|
|
PA_32: 0x20, // PA00-PA31, ... - ATSAMD
|
|
P0_16: 0x1010, // P0_0-P0_15, P1_0-P1_15, ...
|
|
P0_32: 0x1020, // P0_0-P0_32, ... - NRF
|
|
},
|
|
DEFAULT_BUTTON_MODE: {
|
|
ACTIVE_HIGH_PULL_DOWN: 0x11,
|
|
ACTIVE_HIGH_PULL_UP: 0x21,
|
|
ACTIVE_HIGH_PULL_NONE: 0x31,
|
|
ACTIVE_LOW_PULL_DOWN: 0x10,
|
|
ACTIVE_LOW_PULL_UP: 0x20,
|
|
ACTIVE_LOW_PULL_NONE: 0x30,
|
|
},
|
|
DISPLAY_TYPE: {
|
|
ST7735: 7735,
|
|
ILI9341: 9341,
|
|
},
|
|
".": {
|
|
BTN_FLAG_ACTIVE_HIGH: 0x110000,
|
|
BTN_FLAG_ACTIVE_LOW: 0x200000,
|
|
BTN_OFFSET_ANALOG_PLUS: 1100,
|
|
BTN_OFFSET_ANALOG_MINUS: 1200,
|
|
}
|
|
}
|
|
|
|
|
|
let infoMsg = ""
|
|
|
|
function log(msg) {
|
|
msg = "# " + msg
|
|
infoMsg += msg + "\n"
|
|
console.log(msg)
|
|
}
|
|
|
|
function help() {
|
|
console.log(`
|
|
USAGE: node patch-cfg.js file.uf2 [patch.cf2]
|
|
|
|
Without .cf2 file, it will parse config in the UF2 file and print it out
|
|
(in .cf2 format).
|
|
|
|
With .cf2 file, it will patch in-place the UF2 file with specified config.
|
|
`)
|
|
process.exit(1)
|
|
}
|
|
|
|
function readBin(fn) {
|
|
const fs = require("fs")
|
|
|
|
if (!fn) {
|
|
console.log("Required argument missing.")
|
|
help()
|
|
}
|
|
|
|
try {
|
|
return fs.readFileSync(fn)
|
|
} catch (e) {
|
|
console.log("Cannot read file '" + fn + "': " + e.message)
|
|
help()
|
|
}
|
|
}
|
|
const configInvKeys = {}
|
|
|
|
const UF2_MAGIC_START0 = 0x0A324655 // "UF2\n"
|
|
const UF2_MAGIC_START1 = 0x9E5D5157 // Randomly selected
|
|
const UF2_MAGIC_END = 0x0AB16F30 // Ditto
|
|
|
|
const CFG_MAGIC0 = 0x1e9e10f1
|
|
const CFG_MAGIC1 = 0x20227a79
|
|
|
|
let all_defines = {}
|
|
|
|
function configkeysH() {
|
|
let r = "#ifndef __CONFIGKEYS_H\n#define __CONFIGKEYS_H 1\n\n"
|
|
|
|
const add = (k, v) => {
|
|
all_defines[k] = v
|
|
if (v > 1000 || !/^CFG_/.test(k))
|
|
v = "0x" + v.toString(16)
|
|
else
|
|
v += ""
|
|
r += "#define " + k + " " + v + "\n"
|
|
}
|
|
|
|
add("CFG_MAGIC0", CFG_MAGIC0)
|
|
add("CFG_MAGIC1", CFG_MAGIC1)
|
|
r += "\n"
|
|
|
|
for (let k of Object.keys(configKeys)) {
|
|
add("CFG_" + k, configKeys[k])
|
|
}
|
|
for (let k of Object.keys(enums)) {
|
|
r += "\n"
|
|
for (let kk of Object.keys(enums[k])) {
|
|
let n = k == "." ? kk : `${k}_${kk}`
|
|
add(n, enums[k][kk])
|
|
}
|
|
}
|
|
r += "\n#endif // __CONFIGKEYS_H\n"
|
|
return r
|
|
}
|
|
|
|
function err(msg) {
|
|
log("Fatal error: " + msg)
|
|
if (typeof window == "undefined") {
|
|
process.exit(1)
|
|
} else {
|
|
throw new Error(msg)
|
|
}
|
|
}
|
|
|
|
function read32(buf, off) {
|
|
return (buf[off + 0] | (buf[off + 1] << 8) | (buf[off + 2] << 16) | (buf[off + 3] << 24)) >>> 0
|
|
}
|
|
|
|
function write32(buf, off, v) {
|
|
buf[off + 0] = v & 0xff
|
|
buf[off + 1] = (v >> 8) & 0xff
|
|
buf[off + 2] = (v >> 16) & 0xff
|
|
buf[off + 3] = (v >> 24) & 0xff
|
|
}
|
|
|
|
function patchHFile(file, patch) {
|
|
configkeysH()
|
|
let resFile = ""
|
|
let inZone = false
|
|
let flags = {}
|
|
let lineNo = 0
|
|
let nums = []
|
|
for (let line0 of file.split(/\n/)) {
|
|
lineNo++
|
|
let append = line0 + "\n"
|
|
let line = line0.trim().replace(/\/\/.*/, "")
|
|
if (inZone) {
|
|
if (line.indexOf("/* CF2 END */") >= 0) {
|
|
inZone = false
|
|
if (patch) {
|
|
let portSize = lookupCfg(patch, configKeys.PINS_PORT_SIZE)
|
|
let s = ""
|
|
let size = flags["size"] || 100
|
|
let numentries = patch.length >> 1
|
|
size = Math.max(size, numentries + 4)
|
|
s += ` ${CFG_MAGIC0}, ${CFG_MAGIC1}, // magic\n`
|
|
s += ` ${numentries}, ${size}, // used entries, total entries\n`
|
|
for (let i = 0; i < numentries; ++i) {
|
|
let k = patch[i * 2]
|
|
let v = patch[i * 2 + 1]
|
|
s += ` ${k}, 0x${v.toString(16)}, // ${showKV(k, v, portSize, patch)}\n`
|
|
}
|
|
s += " "
|
|
for (let i = 0; i < size - numentries; ++i) {
|
|
if (i && i % 16 == 0)
|
|
s += "\n "
|
|
s += " 0, 0,"
|
|
}
|
|
s += "\n"
|
|
append = s + line0 + "\n"
|
|
}
|
|
} else {
|
|
append = ""
|
|
let toks = line.split(/,\s*/).map(s => s.trim()).filter(s => !!s)
|
|
for (let tok of toks) {
|
|
let n = parseInt(tok)
|
|
if (isNaN(n)) {
|
|
n = all_defines[tok]
|
|
if (n === undefined) {
|
|
let portSize = lookupCfg(nums, configKeys.PINS_PORT_SIZE)
|
|
if (portSize) portSize &= 0xfff;
|
|
let pp = parsePinName(tok.replace(/^PIN_/, ""), portSize)
|
|
if (pp !== undefined) {
|
|
n = pp
|
|
} else {
|
|
err(`unknown value ${tok} at line ${lineNo}`)
|
|
}
|
|
}
|
|
}
|
|
nums.push(n)
|
|
}
|
|
}
|
|
} else {
|
|
let m = /\/\* CF2 START (.*)/.exec(line)
|
|
if (m) {
|
|
inZone = true
|
|
for (let k of m[1].split(/\s+/)) {
|
|
let mm = /^(\w+)=(\d+)$/.exec(k)
|
|
if (mm)
|
|
flags[mm[1]] = parseInt(mm[2])
|
|
else
|
|
flags[k] = true
|
|
}
|
|
}
|
|
}
|
|
resFile += append
|
|
}
|
|
|
|
if (nums.length) {
|
|
if (nums[0] != CFG_MAGIC0 || nums[1] != CFG_MAGIC1)
|
|
err("no magic in H file")
|
|
nums = nums.slice(4)
|
|
for (let i = 0; i < nums.length; i += 2) {
|
|
if (nums[i] == 0) {
|
|
if (nums.slice(i).some(x => x != 0))
|
|
err("config keys follow zero terminator")
|
|
else
|
|
nums = nums.slice(0, i)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
patched: resFile,
|
|
data: nums
|
|
}
|
|
}
|
|
|
|
function bufToString(buf) {
|
|
let s = ""
|
|
for (let i = 0; i < buf.length; ++i)
|
|
s += String.fromCharCode(buf[i])
|
|
return s
|
|
}
|
|
|
|
function stringToBuf(str) {
|
|
let buf = new Uint8Array(str.length)
|
|
for (let i = 0; i < buf.length; ++i)
|
|
buf[i] = str.charCodeAt(i)
|
|
return buf
|
|
}
|
|
|
|
function readWriteConfig(buf, patch) {
|
|
let patchPtr = null
|
|
let origData = []
|
|
let cfgLen = 0
|
|
let isUF2 = false
|
|
if (read32(buf, 0) == UF2_MAGIC_START0) {
|
|
isUF2 = true
|
|
log("detected UF2 file")
|
|
} else {
|
|
let stackBase = read32(buf, 0)
|
|
if ((stackBase & 0xff000003) == 0x20000000 &&
|
|
(read32(buf, 4) & 1) == 1) {
|
|
log("detected BIN file")
|
|
} else {
|
|
let str = bufToString(buf)
|
|
if (str.indexOf("/* CF2 START") >= 0) {
|
|
log("detected CF2 header file")
|
|
let rr = patchHFile(str, patch)
|
|
console.log(rr.data)
|
|
return patch ? stringToBuf(rr.patched) : rr.data
|
|
} else {
|
|
err("unknown file format")
|
|
}
|
|
}
|
|
}
|
|
if (patch)
|
|
patch.push(0, 0)
|
|
for (let off = 0; off < buf.length; off += 512) {
|
|
let start = 0
|
|
let payloadLen = 512
|
|
let addr = off
|
|
|
|
if (isUF2) {
|
|
start = 32
|
|
if (read32(buf, off) != UF2_MAGIC_START0 ||
|
|
read32(buf, off + 4) != UF2_MAGIC_START1) {
|
|
err("invalid data at " + off)
|
|
}
|
|
payloadLen = read32(buf, off + 16)
|
|
addr = read32(buf, off + 12) - 32
|
|
}
|
|
|
|
for (let i = start; i < start + payloadLen; i += 4) {
|
|
if (read32(buf, off + i) == CFG_MAGIC0 &&
|
|
read32(buf, off + i + 4) == CFG_MAGIC1) {
|
|
let addrS = "0x" + (addr + i).toString(16)
|
|
if (patchPtr === null) {
|
|
log(`Found CFG DATA at ${addrS}`)
|
|
patchPtr = -4
|
|
} else {
|
|
log(`Skipping second CFG DATA at ${addrS}`)
|
|
}
|
|
}
|
|
|
|
if (patchPtr !== null) {
|
|
if (patchPtr == -2) {
|
|
cfgLen = read32(buf, off + i)
|
|
if (patch)
|
|
write32(buf, off + i, (patch.length >> 1) - 1)
|
|
}
|
|
|
|
if (patchPtr >= 0) {
|
|
if (origData.length < cfgLen * 2 + 40)
|
|
origData.push(read32(buf, off + i))
|
|
if (patch) {
|
|
if (patchPtr < patch.length) {
|
|
write32(buf, off + i, patch[patchPtr])
|
|
}
|
|
}
|
|
}
|
|
patchPtr++
|
|
}
|
|
}
|
|
}
|
|
|
|
let len0 = cfgLen * 2
|
|
origData.push(0, 0)
|
|
while (origData[len0])
|
|
len0 += 2
|
|
origData = origData.slice(0, len0 + 2)
|
|
if (len0 != cfgLen * 2)
|
|
log("size information incorrect; continuing anyway")
|
|
|
|
if (origData.length == 0)
|
|
err("config data not found")
|
|
if (patch && patchPtr < patch.length)
|
|
err("no space for config data")
|
|
let tail = origData.slice(origData.length - 2)
|
|
if (tail.some(x => x != 0))
|
|
err("config data not zero terminated: " + tail.join(","))
|
|
origData = origData.slice(0, origData.length - 2)
|
|
return patch ? buf : origData
|
|
}
|
|
|
|
function lookupCfg(cfgdata, key) {
|
|
for (let i = 0; i < cfgdata.length; i += 2)
|
|
if (cfgdata[i] == key)
|
|
return cfgdata[i + 1]
|
|
return null
|
|
}
|
|
|
|
function pinToString(pinNo, portSize) {
|
|
if (!portSize || pinNo >= 1000)
|
|
return "P_" + pinNo
|
|
|
|
let useLetters = true
|
|
let theSize = portSize & 0xfff
|
|
if (portSize & 0x1000) {
|
|
useLetters = true
|
|
}
|
|
let port = (pinNo / theSize) | 0
|
|
let pin = pinNo % theSize
|
|
if (useLetters) {
|
|
return "P" + String.fromCharCode(65 + port) + ("0" + pin.toString()).slice(-2)
|
|
} else {
|
|
return "P" + port + "_" + pin
|
|
}
|
|
}
|
|
|
|
function isHeaderPin(n) {
|
|
return /^PIN_(MOSI|MISO|SCK|SDA|SCL|RX|TX|[AD]\d+)$/.test(n)
|
|
}
|
|
|
|
function keyWeight(k) {
|
|
if (k == "PINS_PORT_SIZE")
|
|
return 10
|
|
if (isHeaderPin(k))
|
|
return 20
|
|
if (/^PIN_/.test(k))
|
|
return 30
|
|
return 40
|
|
}
|
|
|
|
function expandNum(k) {
|
|
return k.replace(/\d+/g, f => {
|
|
if (f.length > 4)
|
|
return f
|
|
return ("0000" + f).slice(-4)
|
|
})
|
|
}
|
|
|
|
function cmpKeys(a, b) {
|
|
a = a.replace(/ =.*/, "")
|
|
b = b.replace(/ =.*/, "")
|
|
if (a == b)
|
|
return 0
|
|
let d = keyWeight(a) - keyWeight(b)
|
|
if (d) return d
|
|
let aa = expandNum(a)
|
|
let bb = expandNum(b)
|
|
if (aa < bb) return -1
|
|
else if (bb < aa) return 1
|
|
else if (a < b) return -1
|
|
else return 1
|
|
}
|
|
|
|
function showKV(k, v, portSize, data) {
|
|
let vn = ""
|
|
|
|
let kn = configInvKeys[k + ""] || ""
|
|
|
|
if (enums[kn]) {
|
|
for (let en of Object.keys(enums[kn])) {
|
|
if (enums[kn][en] == v) {
|
|
vn = en
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if (vn == "") {
|
|
if (/_CFG/.test(kn) || v > 10000)
|
|
vn = "0x" + v.toString(16)
|
|
else if (/^PIN_/.test(kn)) {
|
|
if (data && !isHeaderPin(kn)) {
|
|
for (let pn of Object.keys(configKeys)) {
|
|
if (isHeaderPin(pn) && lookupCfg(data, configKeys[pn]) === v) {
|
|
vn = pn
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (!vn)
|
|
vn = pinToString(v, portSize)
|
|
} else
|
|
vn = v + ""
|
|
}
|
|
|
|
if (kn == "")
|
|
kn = "_" + k
|
|
|
|
return `${kn} = ${vn}`
|
|
}
|
|
|
|
function readConfig(buf) {
|
|
init()
|
|
let cfgdata = readWriteConfig(buf, null)
|
|
let portSize = lookupCfg(cfgdata, configKeys.PINS_PORT_SIZE)
|
|
let numentries = cfgdata.length >> 1
|
|
let lines = []
|
|
for (let i = 0; i < numentries; ++i) {
|
|
lines.push(showKV(cfgdata[i * 2], cfgdata[i * 2 + 1], portSize, cfgdata))
|
|
}
|
|
lines.sort(cmpKeys)
|
|
return lines.length ? lines.join("\n") : "Empty config."
|
|
}
|
|
|
|
function parsePinName(v, portSize) {
|
|
let thePort = -1
|
|
let pin = -1
|
|
|
|
v = v.trim()
|
|
|
|
const env = enums["."][v]
|
|
if (env !== undefined)
|
|
return env
|
|
|
|
let m = /(.*)([\|+])(.*)/.exec(v)
|
|
if (m) {
|
|
let v0 = parsePinName(m[1], portSize)
|
|
let v1 = parsePinName(m[3], portSize)
|
|
if (v0 === undefined || v1 === undefined)
|
|
return undefined
|
|
v0 = parseInt(v0)
|
|
v1 = parseInt(v1)
|
|
return "" + (m[2] == "|" ? v0 | v1 : v0 + v1)
|
|
}
|
|
|
|
m = /^P([A-Z])_?(\d+)$/.exec(v)
|
|
if (m) {
|
|
pin = parseInt(m[2])
|
|
thePort = m[1].charCodeAt(0) - 65
|
|
}
|
|
|
|
m = /^P(\d+)_(\d+)$/.exec(v)
|
|
if (m) {
|
|
pin = parseInt(m[2])
|
|
thePort = parseInt(m[1])
|
|
}
|
|
|
|
if (thePort >= 0) {
|
|
if (!portSize) err("PINS_PORT_SIZE not specified, while trying to parse PIN " + v)
|
|
if (pin >= portSize) err("Pin name invalid: " + v)
|
|
return (thePort * portSize + pin) + ""
|
|
}
|
|
|
|
m = /^P_?(\d+)$/.exec(v)
|
|
if (m)
|
|
return m[1]
|
|
|
|
return undefined
|
|
}
|
|
|
|
function patchConfig(buf, cfg) {
|
|
init()
|
|
const cfgMap = {}
|
|
let lineNo = 0
|
|
for (let line of cfg.split(/\n/)) {
|
|
lineNo++
|
|
line = line.replace(/(#|\/\/).*/, "")
|
|
line = line.trim()
|
|
if (!line)
|
|
continue
|
|
let m = /(\w+)\s*=\s*([^#]+)/.exec(line)
|
|
if (!m)
|
|
err("syntax error at config line " + lineNo)
|
|
let kn = m[1].toUpperCase()
|
|
let k = configKeys[kn]
|
|
if (!k && /^_\d+$/.test(kn))
|
|
k = parseInt(kn.slice(1))
|
|
if (!k)
|
|
err("Unrecognized key name: " + kn)
|
|
cfgMap[k + ""] = m[2]
|
|
}
|
|
|
|
let cfgdata = readWriteConfig(buf, null)
|
|
|
|
for (let i = 0; i < cfgdata.length; i += 2) {
|
|
let k = cfgdata[i] + ""
|
|
if (!cfgMap.hasOwnProperty(k))
|
|
cfgMap[k] = cfgdata[i + 1] + ""
|
|
}
|
|
|
|
const forAll = f => {
|
|
for (let k of Object.keys(cfgMap)) {
|
|
let kn = configInvKeys[k]
|
|
f(kn, k, cfgMap[k])
|
|
}
|
|
}
|
|
|
|
// expand enums
|
|
forAll((kn, k, v) => {
|
|
let e = enums[kn]
|
|
if (e && e[v.toUpperCase()])
|
|
cfgMap[k] = e[v] + ""
|
|
})
|
|
|
|
let portSize = cfgMap[configKeys.PINS_PORT_SIZE]
|
|
if (portSize) portSize = parseInt(portSize)
|
|
let portSize0 = portSize
|
|
if (portSize)
|
|
portSize &= 0xfff;
|
|
|
|
// expand pin names
|
|
forAll((kn, k, v) => {
|
|
let p = parsePinName(v, portSize)
|
|
if (p)
|
|
cfgMap[k] = p
|
|
})
|
|
|
|
// expand existing keys
|
|
for (let i = 0; i < 10; ++i)
|
|
forAll((kn, k, v) => {
|
|
if (configKeys[v]) {
|
|
let curr = cfgMap[configKeys[v] + ""]
|
|
if (curr == null)
|
|
err("Value not specified, but referenced: " + v)
|
|
cfgMap[k] = curr
|
|
}
|
|
})
|
|
|
|
let changes = ""
|
|
forAll((kn, k, v) => {
|
|
v = v.toUpperCase()
|
|
if (v == "NULL" || v == "UNDEFINED") {
|
|
let old = lookupCfg(cfgdata, k)
|
|
changes += "remove " + showKV(k, old, portSize0) + "\n"
|
|
delete cfgMap[k]
|
|
}
|
|
})
|
|
|
|
forAll((kn, k, v) => {
|
|
if (isNaN(parseInt(v)))
|
|
err("Value not understood: " + v)
|
|
})
|
|
|
|
let sorted = Object.keys(cfgMap)
|
|
sorted.sort((a, b) => parseInt(a) - parseInt(b))
|
|
let patch = []
|
|
for (let k of sorted) {
|
|
patch.push(parseInt(k))
|
|
patch.push(parseInt(cfgMap[k]))
|
|
}
|
|
|
|
for (let i = 0; i < patch.length; i += 2) {
|
|
let k = patch[i]
|
|
let v = patch[i + 1]
|
|
let old = lookupCfg(cfgdata, k)
|
|
if (old != v) {
|
|
let newOne = showKV(k, v, portSize0)
|
|
if (old !== null) {
|
|
let oldOne = showKV(k, old, portSize0)
|
|
newOne += " (was: " + oldOne.replace(/.* = /, "") + ")"
|
|
}
|
|
changes += newOne + "\n"
|
|
}
|
|
}
|
|
|
|
let patched = readWriteConfig(buf, patch)
|
|
|
|
return {
|
|
changes,
|
|
patched
|
|
}
|
|
}
|
|
|
|
function parseHFile(hFile) {
|
|
if (!hFile) return
|
|
for (let line of hFile.split(/\n/)) {
|
|
line = line.trim()
|
|
let m = /#define\s+CFG_(\w+)\s+(\d+)/.exec(line)
|
|
if (m) {
|
|
let k = m[1]
|
|
let v = parseInt(m[2])
|
|
configKeys[k] = parseInt(v)
|
|
configInvKeys[v + ""] = k
|
|
console.log(` ${k}: ${v},`)
|
|
}
|
|
}
|
|
}
|
|
|
|
function init() {
|
|
for (let k of Object.keys(configKeys)) {
|
|
let v = configKeys[k]
|
|
configInvKeys[v + ""] = k
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
let uf2 = readBin(process.argv[2])
|
|
|
|
if (process.argv[3]) {
|
|
let cfg = readBin(process.argv[3]).toString("utf8")
|
|
let r = patchConfig(uf2, cfg)
|
|
if (!r.changes)
|
|
console.log("No changes.")
|
|
else
|
|
console.log("\nChanges:\n" + r.changes)
|
|
console.log("# Writing config...")
|
|
fs.writeFileSync(process.argv[2], r.patched)
|
|
} else {
|
|
console.log(readConfig(uf2))
|
|
}
|
|
}
|
|
|
|
|
|
if (typeof window == "undefined")
|
|
main() |