Compare commits

...

62 commits
py3 ... master

Author SHA1 Message Date
Michał Moskal
89839723d8
Merge pull request #22 from arturo182/master
Add the MIMXRT10XX family
2020-01-05 13:34:06 +01:00
arturo182
84da66ce62 Add the MIMXRT10XX family 2020-01-05 13:15:38 +01:00
Michał Moskal
b23250077a
Merge pull request #21 from ElectronicCats/saml21
New family saml21
2019-11-11 16:04:55 -08:00
sabas1080
2a8c0e4984 new family saml21 2019-11-11 17:29:57 -06:00
Michal Moskal
5ec3ddbd28 Add -D option; python3 fixes
Also don't MSD-deploy bin files
2019-10-08 16:47:49 -07:00
Michal Moskal
df9920a8e9 Update configkeys.h 2019-09-25 14:07:18 +02:00
Peli de Halleux
a307533182
Merge pull request #20 from microsoft/configupdate
add a few more keys to patcher
2019-09-12 11:13:25 -07:00
Peli de Halleux
9409e62d43 parse keys from configkeys.h 2019-09-12 11:09:31 -07:00
Peli de Halleux
5a0f284ce3 renamed keys 2019-09-11 14:37:44 -07:00
Peli de Halleux
a4c3164f5c add a few more keys 2019-09-11 14:00:18 -07:00
Michał Moskal
b0fdc475c6
Merge pull request #18 from jrahlf/new_ids_stm32f4
added new ids for stm32f4 series
2019-08-22 15:48:02 -07:00
Jonas Rahlf
3e6f8d6d40 added new ids for stm32f4 series 2019-08-21 10:20:54 +02:00
Michał Moskal
84490705bc
Add arcade 2019-08-12 18:33:02 -07:00
Michal Moskal
c5488ec20b Fix typo 2019-07-09 13:37:17 -07:00
Michal Moskal
ad50c9a828 Add ESP32 and MD5 checksum mode 2019-07-09 13:36:15 -07:00
Michal Moskal
e038180158 Add P21-P31 2019-07-05 17:59:45 -07:00
Michal Moskal
0a6e597ce6 Add DISPLAY_TYPE config 2019-07-05 17:58:04 -07:00
Michal Moskal
31117082f0 Improve UX of gen-random; add note to readme 2019-06-22 20:38:56 -07:00
Michal Moskal
6e8bab5245 Add "Generate random number" on bottom of patcher 2019-06-22 20:32:43 -07:00
Michal Moskal
1961540772 Support for |, + in config values; add some enums 2019-04-29 13:26:20 +02:00
Michal Moskal
9acf6a0fbd Add new config constants 2019-04-25 12:26:52 -07:00
Michał Moskal
956b6e1386
Merge pull request #15 from henrygab/patch-1
Fix typos in README.md
2019-04-15 09:25:57 -07:00
Henry Gabryjelski
7b2590b9d8
Fix typos in README.md 2019-03-01 14:41:11 -08:00
Michal Moskal
e24284da0a Patchers bugfixes; add deepsleep cfg key 2019-02-25 13:55:05 -08:00
Michal Moskal
ad8bd69fd7 Allow for mal-formed config data in patcher 2019-02-20 11:36:45 -08:00
Michal Moskal
2b398d08f3 Add BOOTLOADER_PROTECTION 2019-01-29 09:43:43 +00:00
Michal Moskal
0d0317634c Add =null syntax to remove entries 2019-01-28 10:37:52 +00:00
Michal Moskal
b31f82edf6 Merge branch 'master' of github.com:Microsoft/uf2 2019-01-28 10:20:03 +00:00
Michal Moskal
37e28ddf8e Add more config keys 2019-01-28 10:19:58 +00:00
Michał Moskal
4b3a349d90
update family id for 52840 2019-01-17 20:44:36 +00:00
Michal Moskal
9de0d3a5ca Fix BTNMX keys 2019-01-07 22:13:11 +00:00
Michal Moskal
7e6306cf08 Add legal links 2019-01-07 17:34:38 +00:00
Michal Moskal
4a97cb50d2 Pin printout fix 2019-01-07 17:23:15 +00:00
Michal Moskal
62967d8fe8 Allow patching of .h files 2019-01-07 15:20:48 +00:00
Michal Moskal
d76c4f93a7 Better display of config 2019-01-07 14:16:09 +00:00
Michal Moskal
839623d9ec Info about command line 2019-01-06 21:01:09 +00:00
Michal Moskal
e77baf9e62 More info on syntax 2019-01-06 20:58:21 +00:00
Michal Moskal
489638255a Describe file format 2019-01-06 20:51:52 +00:00
Michal Moskal
86e101e3a2 Add CF2 docs and support BIN files in patcher 2019-01-06 20:32:34 +00:00
Michal Moskal
197180bb25 Cleanup port size setting 2019-01-06 19:47:42 +00:00
Michal Moskal
f2217cd8ff Add configkeys.h download option 2019-01-06 19:35:51 +00:00
Michal Moskal
881bc93ca6 Minor patcher improvements 2019-01-06 19:19:11 +00:00
Michal Moskal
cc0e31aa20 Fix initial text 2019-01-06 19:14:11 +00:00
Michal Moskal
206825a0ef Website for binary patching bootloaders 2019-01-06 19:12:06 +00:00
Michał Moskal
6b57b35d16 Set theme jekyll-theme-cayman 2019-01-06 17:54:07 +00:00
Michal Moskal
f294980449 Add --carray option to uf2conv 2018-12-13 20:14:49 -08:00
Michał Moskal
79e82bed56
Add family_id in BININFO 2018-12-11 23:30:10 -08:00
Michał Moskal
b0562d349f
Fix typo 2018-12-11 23:28:00 -08:00
Michał Moskal
ffaf0779d5
Be more explicit about MCU in family definition 2018-12-11 23:27:16 -08:00
Michal Moskal
4a32ffc6a5 More info on familyID 2018-11-30 19:42:27 -08:00
Michal Moskal
f78c13c3be Add one more bootloader and fixup names 2018-11-30 18:51:08 -08:00
Michal Moskal
f7bdf490af No msc branch in codal anymore 2018-11-07 21:51:26 -08:00
Michal Moskal
86cb62be3a Implementation list is at the bottom 2018-11-07 21:50:14 -08:00
Michał Moskal
73afad0a4b
Merge pull request #9 from whitequark/patch-1
Add family ID for Cypress FX2
2018-11-07 21:48:36 -08:00
whitequark
0985f37d40
Add link to UF2 for FX2 to list of implementations 2018-11-08 04:13:58 +00:00
whitequark
80e72b9640
Add vendor names to family list. 2018-11-08 04:11:55 +00:00
Michał Moskal
6a68ca700b
Merge pull request #10 from whitequark/patch-2
Fix automatic flashing of NEW.UF2
2018-10-31 15:34:04 -07:00
whitequark
961e06ac5c
Fix automatic flashing of NEW.UF2 2018-10-30 07:36:01 +00:00
whitequark
88a34269ea
Add family ID for Cypress FX2 2018-10-30 06:10:18 +00:00
Michał Moskal
968716efd3
Merge pull request #8 from tannewt/py3
Move to python3
2018-07-23 13:42:39 -07:00
Scott Shawcroft
59876b233c
Fix hex conversion in python3. 2018-07-06 05:25:18 -07:00
Nicholas H.Tollervey
68090735cd
Convert to Python3. Use PEP8 naming conventions and formatting. 2018-07-06 04:48:35 -07:00
8 changed files with 1477 additions and 85 deletions

View file

@ -5,8 +5,7 @@ UF2 is a file format, developed by Microsoft for [PXT](https://github.com/Micros
flashing microcontrollers over MSC (Mass Storage Class; aka removable flash drive).
For a more friendly explanation, check out [this blog post](https://makecode.com/blog/one-chip-to-flash-them-all).
For source code, see the implementation of [UF2 in a SAMD21 bootloader](https://github.com/Microsoft/uf2-samd21)
Also, take a look at the list of implementations at the bottom of this document.
## Overview
@ -67,7 +66,7 @@ struct UF2_Block {
### Flags
Currently, there are two flags is defined:
Currently, there are three flags defined:
* `0x00000001` - **not main flash** - this block should be skipped when writing the
device flash; it can be used to store "comments" in the file, typically
@ -75,6 +74,7 @@ Currently, there are two flags is defined:
* `0x00001000` - **file container** - see below
* `0x00002000` - **familyID present** - when set, the `fileSize/familyID` holds a value
identifying the board family (usually corresponds to an MCU)
* `0x00004000` - **MD5 checksum present** - see below
### Family ID
@ -85,21 +85,37 @@ If you're developing your own bootloader, and your
board family isn't listed here, pick a new family ID at random. It's good
to also send a PR here, so your family can be listed.
If the `familyID` doesn't match, the bootloader should disregard the
entire block, including `blockNo` and `numBlocks` fields.
In particular, writing a full UF2 file with non-matching `familyID`
should not reset the board.
This also allows for several files with different `familyID` to be
simply concatenated together, and the whole resulting file to be copied
to the device with only one actually being written to flash.
#### Picking numbers at random
The reason to pick numbers at random is to minimize risk of collisions
in the wild. Do not pick random numbers by banging on keyboard, or by using
`0xdeadf00d`, `0x42424242` etc. A good way is to use the following
shell command: `printf "0x%04x%04x\n" $RANDOM $RANDOM`
Another good way is the link at the bottom of https://microsoft.github.io/uf2/patcher/
This procedure was unfortunately not used for the SAMD51 and NRF52840 below.
#### Family list
* SAMD21 - 0x68ed2b88
* SAMD51 - 0x55114460
* NRF52 - 0x1b57745f
* STM32F1 - 0x5ee21072
* STM32F4 - 0x57755a57
* ATmega32 - 0x16573617
* Microchip (Atmel) SAMD21 - 0x68ed2b88
* Microchip (Atmel) SAML21 - 0x1851780a
* Microchip (Atmel) SAMD51 - 0x55114460
* Nordic NRF52840 - 0xada52840
* ST STM32F103 - 0x5ee21072
* ST STM32F401 - 0x57755a57
* ST STM32F407 - 0x6d0922fa
* ST STM32F407VG - 0x8fb060fe
* Microchip (Atmel) ATmega32 - 0x16573617
* Cypress FX2 - 0x5a18069b
* ESP32 - 0x1c5f21b0
* NXP i.MX RT10XX - 0x4fb2d5bd
### Rationale
@ -249,20 +265,44 @@ Typical writing procedure is as follows:
The fields `blockNo` and `numBlocks` refer to the entire UF2 file, not the current
file.
## MD5 checksum
When the `0x4000` flag is set, the last 24 bytes of `data[]` hold the following structure:
| Offset | Size | Value |
|--------|------|---------------------------------------------------|
| 0 | 4 | Start address of region |
| 4 | 4 | Length of region in bytes |
| 8 | 16 | MD5 checksum in binary format |
The flashing program should compute the MD5 sum of the specified region.
If the region checksum matches, flashing of the current block can be skipped.
Typically, many blocks in sequence will have the same region specified,
and can all be skipped, if the matching succeeded.
The position of the current block will typically be inside of the region.
The position and size of the region should be multiple of page erase size
(4k or 64k on typical SPI flash).
This is currently only used on ESP32, which is also why MD5 checksum is used.
## Implementations
### Bootloaders
* [SAMD21](https://github.com/Microsoft/uf2-samd21)
* [Microchip ATSAMD21 and ATSAMD51](https://github.com/Microsoft/uf2-samdx1)
* [Arduino UNO](https://github.com/mmoskal/uf2-uno)
* [STM32](https://github.com/mmoskal/uf2-stm32f)
* [NRF52840](https://github.com/adafruit/Adafruit_nRF52840_Bootloader)
* [STM32F103](https://github.com/mmoskal/uf2-stm32)
* [STM32F4](https://github.com/mmoskal/uf2-stm32f)
* [Nordic NRF52840](https://github.com/adafruit/Adafruit_nRF52840_Bootloader)
* [Linux (RPi Zero)](https://github.com/microsoft/uf2-linux)
* [Cypress FX2](https://github.com/whitequark/libfx2/tree/master/firmware/boot-uf2)
There's an ongoing effort to implement UF2 in [Codal](https://github.com/lancaster-university/codal-core), see `msc` branch.
There's an ongoing effort to implement UF2 in [Codal](https://github.com/lancaster-university/codal-core).
### Editors
* https://arcade.makecode.com
* https://makecode.adafruit.com
* https://makecode.seeedstudio.com
* https://maker.makecode.com

1
_config.yml Normal file
View file

@ -0,0 +1 @@
theme: jekyll-theme-cayman

126
cf2.md Normal file
View file

@ -0,0 +1,126 @@
# Binary Bootloader-embedded Config (CF2)
## Motivation
The goal of CF2 is to run the same binary on a number of devices with different
peripheral configuration, but the same MCU.
Typically, this has been achieved by embedding identification components in hardware
(eg. connecting certain MCU pins to GND or 3V) and having the firmware dynamically
detect these.
While simple, this only allows a few bits of configuration data to be stored on device.
Instead, we use the bootloader area for storing device specific configuration data.
Such data is not altered when the device is programmed with new firmware,
and the said firmware can refer to the configuration data in the bootloader area to
alter its behavior.
For example, MakeCode Arcade requires a device with 7 buttons (directions, A, B, and MENU),
a screen from a specific family, and one of the few supported accelerometers.
The exact configuration depends on the manufacturer, but the binary produced by MakeCode
will work on any device with the right MCU, provided it has the right configuration
data in the bootloader area.
Thus, the user only needs to select the type of MCU (which is color coded,
and is assigned a simple user-facing name), and the resulting binary will work
on their device.
Moreover, they can drag the UF2 file between devices, provided they run the same MCU.
Once bootloaders are updated with networking support (wired or wireless), one device with
a given MCU will be able to flash another.
## Configuration data format
Data comes as pairs of 32 bit unsigned integers (in machine byte order).
* first pair is `0x1e9e10f1, 0x20227a79`
* second pair consists of the number of configuration entries, and a zero (reserved)
* then configuration entries follow, where the first element is the configuration
entry key number, and the second is the value (these entries are sorted by key number)
* finally, a number of zeroes follows (typically at least a few hundred),
to store any additional configuration data in future
The file `configkeys.h` with definitions of key names can be downloaded from the
patcher website (see below).
If you require your own key names, please use
[random large key names](https://github.com/Microsoft/uf2#picking-numbers-at-random).
## The Patcher
At https://microsoft.github.io/uf2/patcher/ we provide a tool, which given a UF2 or BIN file
and a configuration definition, binary-patches the UF2/BIN file and lets the user download it.
The tool also parses existing configuration information from the UF2/BIN file to show it.
Such tool is to be used by makers of devices.
For example, for MakeCode Arcade, this includes both factories and users who take an existing
multi-purpose board and connect keys and screen.
Such user would then download generic MakeCode Arcade bootloader (either a UF2 file,
which upgrades the bootloader, or a .BIN file with the bootloader) for the given MCU,
and binary patch it with their configuration.
Then, they would update the bootloader, and have a Arcade-compatible device.
## Configuration file syntax
Example:
```bash
# This is comment, which is ignored
// this is also a comment
# Configuration values for display registers and size
DISPLAY_CFG0 = 0x80
DISPLAY_CFG1 = 0x603
DISPLAY_CFG2 = 0x16
DISPLAY_HEIGHT = 128
DISPLAY_WIDTH = 160
PINS_PORT_SIZE = PA_32 # see below
# pin headers (if any)
PIN_A0 = PA02
PIN_A1 = PA05
PIN_A2 = PB08
PIN_D2 = PA07
PIN_D3 = PB22
PIN_SCK = PA01
PIN_MISO = PB23
PIN_MOSI = PA00
# pin functions
PIN_BTN_LEFT = PIN_D2 # use pin header name
PIN_BTN_UP = PB13 # use pin directly
PIN_DISPLAY_CS = 18 # can even just use a number for the pin
PIN_DISPLAY_SCK = PIN_SCK
PIN_DISPLAY_MOSI = PIN_MOSI
# custom configuration keys
_679732427 = 123
_815320287 = 0x80192
# remove an existing config entry
PIN_BTN_MENU2 = null
```
The keys are either key names, or underscore followed by a decimal number.
The values are numbers in either decimal or hexadecimal,
references to other keys, or pin numbers.
The way pin numbers are parsed depends on the `PINS_PORT_SIZE`:
* `PA_16` - pins are `PA00`-`PA15`, `PB00-PB15`, ..., used on STM32
* `PA_32` - pins are `PA00`-`PA31`, ... - used on Microchip ATSAMD
* `P0_16` - pins are `P0_0`-`P0_15`, `P1_0-P1_15`, ... - not used?
* `P0_32` - pins are `P0_0-P0_31`, ... - used on Nordic NRF
* `0` or missing - pins are `P_0`, `P_1`, ..., `P_1000`
Certain keys (like `PINS_PORT_SIZE`) have a number of pre-defined values,
which can be used instead of integers.
Because you're usually use this syntax to patch an existing configuration,
you sometimes may want to remove an entry that's already there.
To do that, use `null` as the value of the key.
For list of keys and predefined values, see `configkeys.h` which can be downloaded
from the patcher website.
## Running from node.js
The patcher tool can be also run from command line.
Download [patcher.js](https://raw.githubusercontent.com/Microsoft/uf2/master/patcher/patcher.js)
and run it with node. It will print out help.

5
hf2.md
View file

@ -14,8 +14,8 @@ ones, but be less efficient.
In particular, it is suitable for running over USB HID (Human Interface Device),
which is widely supported in various operating systems without the need for kernel-space
drivers. It is also possible to run the protocol over a WebUSB link with either a single
interrupt endpoint or two bulk endpoints, allowing direct access from supported
browsers.
interrupt endpoint or two bulk endpoints, as well as using just the control pipe,
allowing direct access from supported browsers.
## Raw message format
@ -142,6 +142,7 @@ struct HF2_BININFO_Result {
uint32_t flash_page_size;
uint32_t flash_num_pages;
uint32_t max_message_size;
uint32_t family_id; // optional
};
```

83
patcher/index.html Normal file
View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>CF2 binary patcher</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#157878">
<link rel="stylesheet" href="https://microsoft.github.io/uf2/assets/css/style.css">
<script src="patcher.js"></script>
<script src="web.js"></script>
<style>
#patch {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 0.9rem;
width: 100%;
height: 12em;
}
.page-header {
padding: 2rem 2rem !important;
}
.btn-dl,
.btn-dl:hover {
background-color: green;
float: right;
color: white;
}
footer {
text-align: center;
margin-top: 5em;
}
footer a {
margin-right: 2em;
}
</style>
</head>
<body ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
<section class="page-header">
<h1 class="project-name">CF2 patcher</h1>
</section>
<section class="main-content">
<h2>Your patch</h2>
<textarea id="patch" spellcheck=false onchange="savePatch(event);"></textarea>
<a href="#" id="apply" class="btn btn-dl">Apply my patch</a>
<h2>Information</h2>
<pre><code id="currconfig">Drop UF2 or BIN file above to see its config.</code></pre>
<p>
<a href="https://github.com/Microsoft/uf2/blob/master/cf2.md">Learn more</a>
or
<a href="#" onclick="defines()">download configkeys.h</a>.
</p>
<p>
<a href="#" id="rnd">Generate random number</a>
<span id="rnd-res"></span>
</p>
<footer>
<a href="https://makecode.com/privacy" target="_blank" rel="noopener">Privacy &amp; Cookies</a>
<a href="https://makecode.com/termsofuse" target="_blank" rel="noopener"> Terms Of Use</a>
<a href="https://makecode.com/trademarks" target="_blank" rel="noopener">Trademarks</a>
<span>© 2019 Microsoft</span>
</footer>
</section>
<script>
restorePatch()
</script>
</body>
</html>

1001
patcher/patcher.js Normal file

File diff suppressed because it is too large Load diff

109
patcher/web.js Normal file
View file

@ -0,0 +1,109 @@
"use strict";
function savePatch(ev) {
let text = document.getElementById("patch")
localStorage["UF2_PATCH"] = text.value
}
function genRnd(ev) {
ev.preventDefault()
let vals = new Uint32Array(1)
window.crypto.getRandomValues(vals)
document.getElementById("rnd-res").textContent = "Random number: 0x" +
("000000000" + vals[0].toString(16)).slice(-8)
}
function restorePatch() {
let text = document.getElementById("patch")
text.value = localStorage["UF2_PATCH"] || ""
document.getElementById("apply").onclick = applyPatch
document.getElementById("rnd").onclick = genRnd
}
function download(buf, name) {
let blob = new Blob([buf], {
type: "application/x-uf2"
});
let url = URL.createObjectURL(blob);
let a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = name;
a.click();
window.URL.revokeObjectURL(url);
}
let currUF2 = null
let currUF2Name = ""
function showMSG() {
if (infoMsg)
document.getElementById("currconfig").textContent = infoMsg
}
function wrap(f) {
try {
infoMsg = ""
f()
showMSG()
} catch (e) {
log("Exception: " + e.message)
showMSG()
}
}
function defines() {
download(configkeysH(), "configkeys.h")
}
function applyPatch() {
wrap(() => {
let text = document.getElementById("patch")
let newcfg = text.value.trim()
if (!currUF2)
log("You have to drop a UF2 or BIN file with bootloader above before applying patches.")
else if (!newcfg)
log("You didn't give any patch to apply.")
else {
let buf = currUF2.slice()
let r = patchConfig(buf, newcfg)
if (!r.changes) {
log("No changes.")
} else {
log("\nChanges:\n" + r.changes)
}
log("Downloading " + currUF2Name)
download(r.patched, currUF2Name)
}
})
}
function dropHandler(ev) {
ev.preventDefault();
for (let i = 0; i < ev.dataTransfer.items.length; i++) {
if (ev.dataTransfer.items[i].kind === 'file') {
let file = ev.dataTransfer.items[i].getAsFile();
let reader = new FileReader();
infoMsg = ""
reader.onload = e => {
wrap(() => {
let buf = new Uint8Array(reader.result)
let cfg = readConfig(buf)
currUF2 = buf
infoMsg += "\n" + cfg
currUF2Name = file.name
})
}
reader.readAsArrayBuffer(file);
break
}
}
}
function dragOverHandler(ev) {
ev.preventDefault();
ev.dataTransfer.dropEffect = 'copy';
}

171
utils/uf2conv.py Executable file → Normal file
View file

@ -1,5 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python3
import sys
import struct
import subprocess
@ -8,17 +7,20 @@ import os
import os.path
import argparse
UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
UF2_MAGIC_END = 0x0AB16F30 # Ditto
families = {
'SAMD21': 0x68ed2b88,
'SAML21': 0x1851780a,
'SAMD51': 0x55114460,
'NRF52': 0x1b57745f,
'STM32F1': 0x5ee21072,
'STM32F4': 0x57755a57,
'ATMEGA32': 0x16573617,
'MIMXRT10XX': 0x4FB2D5BD
}
INFO_FILE = "/INFO_UF2.TXT"
@ -26,27 +28,31 @@ INFO_FILE = "/INFO_UF2.TXT"
appstartaddr = 0x2000
familyid = 0x0
def isUF2(buf):
def is_uf2(buf):
w = struct.unpack("<II", buf[0:8])
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1
def isHEX(buf):
w = buf[0:30]
if w[0] == ':' and re.match("^[:0-9a-fA-F\r\n]+$", buf):
def is_hex(buf):
try:
w = buf[0:30].decode("utf-8")
except UnicodeDecodeError:
return False
if w[0] == ':' and re.match(b"^[:0-9a-fA-F\r\n]+$", buf):
return True
return False
def convertFromUF2(buf):
def convert_from_uf2(buf):
global appstartaddr
numblocks = len(buf) / 512
numblocks = len(buf) // 512
curraddr = None
outp = ""
for blockno in range(0, numblocks):
outp = b""
for blockno in range(numblocks):
ptr = blockno * 512
block = buf[ptr:ptr + 512]
hd = struct.unpack("<IIIIIIII", block[0:32])
hd = struct.unpack(b"<IIIIIIII", block[0:32])
if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1:
print "Skipping block at " + ptr + "; bad magic"
print("Skipping block at " + ptr + "; bad magic")
continue
if hd[2] & 1:
# NO-flash flag set; skip block
@ -67,30 +73,39 @@ def convertFromUF2(buf):
assert False, "Non-word padding size at " + ptr
while padding > 0:
padding -= 4
outp += "\x00\x00\x00\x00"
outp += b"\x00\x00\x00\x00"
outp += block[32 : 32 + datalen]
curraddr = newaddr + datalen
return outp
def convertToUF2(fileContent):
def convert_to_carray(file_content):
outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {"
for i in range(len(file_content)):
if i % 16 == 0:
outp += "\n"
outp += "0x%02x, " % ord(file_content[i])
outp += "\n};\n"
return outp
def convert_to_uf2(file_content):
global familyid
datapadding = ""
datapadding = b""
while len(datapadding) < 512 - 256 - 32 - 4:
datapadding += "\x00\x00\x00\x00"
numblocks = (len(fileContent) + 255) / 256
outp = ""
for blockno in range(0, numblocks):
datapadding += b"\x00\x00\x00\x00"
numblocks = (len(file_content) + 255) // 256
outp = b""
for blockno in range(numblocks):
ptr = 256 * blockno
chunk = fileContent[ptr:ptr + 256]
chunk = file_content[ptr:ptr + 256]
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack("<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
hd = struct.pack(b"<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, ptr + appstartaddr, 256, blockno, numblocks, familyid)
while len(chunk) < 256:
chunk += "\x00"
block = hd + chunk + datapadding + struct.pack("<I", UF2_MAGIC_END)
chunk += b"\x00"
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
assert len(block) == 512
outp += block
return outp
@ -98,26 +113,23 @@ def convertToUF2(fileContent):
class Block:
def __init__(self, addr):
self.addr = addr
self.bytes = []
for i in range(0, 256):
self.bytes.append(0)
self.bytes = bytearray(256)
def encode(self, blockno, numblocks):
global familyid
flags = 0x0
if familyid:
flags |= 0x2000
hd = struct.pack("<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
hd = struct.pack("<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
flags, self.addr, 256, blockno, numblocks, familyid)
for i in range(0, 256):
hd += chr(self.bytes[i])
hd += self.bytes[0:256]
while len(hd) < 512 - 4:
hd += "\x00"
hd += b"\x00"
hd += struct.pack("<I", UF2_MAGIC_END)
return hd
def convertFromHexToUF2(buf):
def convert_from_hex_to_uf2(buf):
global appstartaddr
appstartaddr = None
upper = 0
@ -152,17 +164,21 @@ def convertFromHexToUF2(buf):
addr += 1
i += 1
numblocks = len(blocks)
resfile = ""
resfile = b""
for i in range(0, numblocks):
resfile += blocks[i].encode(i, numblocks)
return resfile
def to_str(b):
return b.decode("utf-8")
def getdrives():
def get_drives():
drives = []
if sys.platform == "win32":
r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk", "get", "DeviceID,", "VolumeName,", "FileSystem,", "DriveType"])
for line in r.split('\n'):
r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk",
"get", "DeviceID,", "VolumeName,",
"FileSystem,", "DriveType"])
for line in to_str(r).split('\n'):
words = re.split('\s+', line)
if len(words) >= 3 and words[1] == "2" and words[2] == "FAT":
drives.append(words[0])
@ -176,36 +192,41 @@ def getdrives():
rootpath = tmp
for d in os.listdir(rootpath):
drives.append(os.path.join(rootpath, d))
def hasInfo(d):
def has_info(d):
try:
return os.path.isfile(d + INFO_FILE)
except:
return False
return filter(hasInfo, drives)
def boardID(path):
return list(filter(has_info, drives))
def board_id(path):
with open(path + INFO_FILE, mode='r') as file:
fileContent = file.read()
return re.search("Board-ID: ([^\r\n]*)", fileContent).group(1)
def listdrives():
for d in getdrives():
print d, boardID(d)
file_content = file.read()
return re.search("Board-ID: ([^\r\n]*)", file_content).group(1)
def writeFile(name, buf):
def list_drives():
for d in get_drives():
print(d, board_id(d))
def write_file(name, buf):
with open(name, "wb") as f:
f.write(buf)
print "Wrote %d bytes to %s." % (len(buf), name)
print("Wrote %d bytes to %s." % (len(buf), name))
def main():
global appstartaddr, familyid
def error(msg):
print msg
print(msg)
sys.exit(1)
parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
help='input file (HEX, BIN or UF2)')
parser.add_argument('-b' , '--base', dest='base', type=str,
default="0x2000",
@ -218,9 +239,13 @@ def main():
help='list connected devices')
parser.add_argument('-c' , '--convert', action='store_true',
help='do not flash, just convert')
parser.add_argument('-D' , '--deploy', action='store_true',
help='just flash, do not convert')
parser.add_argument('-f' , '--family', dest='family', type=str,
default="0x0",
help='specify familyID - number or name (default: 0x0)')
parser.add_argument('-C' , '--carray', action='store_true',
help='convert binary file to a C array, not UF2')
args = parser.parse_args()
appstartaddr = int(args.base, 0)
@ -233,38 +258,44 @@ def main():
error("Family ID needs to be a number or one of: " + ", ".join(families.keys()))
if args.list:
listdrives()
list_drives()
else:
if not args.input:
error("Need input file")
with open(args.input, mode='rb') as file:
inpbuf = file.read()
fromUF2 = isUF2(inpbuf)
with open(args.input, mode='rb') as f:
inpbuf = f.read()
from_uf2 = is_uf2(inpbuf)
ext = "uf2"
if fromUF2:
outbuf = convertFromUF2(inpbuf)
if args.deploy:
outbuf = inpbuf
elif from_uf2:
outbuf = convert_from_uf2(inpbuf)
ext = "bin"
elif isHEX(inpbuf):
outbuf = convertFromHexToUF2(inpbuf)
elif is_hex(inpbuf):
outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8"))
elif args.carray:
outbuf = convert_to_carray(inpbuf)
ext = "h"
else:
outbuf = convertToUF2(inpbuf)
print "Converting to %s, output size: %d, start address: 0x%x" % (ext, len(outbuf), appstartaddr)
if args.convert:
outbuf = convert_to_uf2(inpbuf)
print("Converting to %s, output size: %d, start address: 0x%x" %
(ext, len(outbuf), appstartaddr))
if args.convert or ext != "uf2":
drives = []
if args.output == None:
args.output = "flash." + ext
else:
drives = getdrives()
drives = get_drives()
if args.output:
writeFile(args.output, outbuf)
write_file(args.output, outbuf)
else:
if len(drives) == 0:
error("No drive to deploy.")
for d in drives:
print "Flashing %s (%s)" % (d, boardID(d))
writeFile(outbuf, d + "/NEW.UF2")
print("Flashing %s (%s)" % (d, board_id(d)))
write_file(d + "/NEW.UF2", outbuf)
if __name__ == "__main__":
main()