In-app flash write, UF2 parser, remove picotool dependency, reboot command
This commit is contained in:
@@ -117,6 +117,21 @@ func (c *Client) Log() (*ResponseLog, error) {
|
||||
return first(roundTrip[ResponseLog](c, &RequestLog{}))
|
||||
}
|
||||
|
||||
func (c *Client) FlashErase(addr, length uint32) error {
|
||||
_, err := first(roundTrip[ResponseFlashErase](c, &RequestFlashErase{Addr: addr, Len: length}))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) FlashWrite(addr uint32, data []byte) error {
|
||||
_, err := first(roundTrip[ResponseFlashWrite](c, &RequestFlashWrite{Addr: addr, Data: data}))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) Reboot() error {
|
||||
_, err := first(roundTrip[ResponseReboot](c, &RequestReboot{}))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) ListTests() (*ResponseListTests, error) {
|
||||
return first(roundTrip[ResponseListTests](c, &RequestListTests{}))
|
||||
}
|
||||
|
||||
@@ -24,6 +24,21 @@ type ResponseLog struct {
|
||||
Entries []LogEntry
|
||||
}
|
||||
|
||||
type RequestFlashErase struct {
|
||||
Addr uint32
|
||||
Len uint32
|
||||
}
|
||||
type ResponseFlashErase struct{}
|
||||
|
||||
type RequestFlashWrite struct {
|
||||
Addr uint32
|
||||
Data []byte
|
||||
}
|
||||
type ResponseFlashWrite struct{}
|
||||
|
||||
type RequestReboot struct{}
|
||||
type ResponseReboot struct{}
|
||||
|
||||
type RequestListTests struct{}
|
||||
type ResponseListTests struct {
|
||||
Names []string
|
||||
@@ -62,6 +77,12 @@ func init() {
|
||||
msgpack.RegisterExt(5, (*ResponseInfo)(nil))
|
||||
msgpack.RegisterExt(6, (*RequestLog)(nil))
|
||||
msgpack.RegisterExt(7, (*ResponseLog)(nil))
|
||||
msgpack.RegisterExt(8, (*RequestFlashErase)(nil))
|
||||
msgpack.RegisterExt(9, (*ResponseFlashErase)(nil))
|
||||
msgpack.RegisterExt(10, (*RequestFlashWrite)(nil))
|
||||
msgpack.RegisterExt(11, (*ResponseFlashWrite)(nil))
|
||||
msgpack.RegisterExt(12, (*RequestReboot)(nil))
|
||||
msgpack.RegisterExt(13, (*ResponseReboot)(nil))
|
||||
msgpack.RegisterExt(125, (*RequestListTests)(nil))
|
||||
msgpack.RegisterExt(124, (*ResponseListTests)(nil))
|
||||
msgpack.RegisterExt(127, (*RequestTest)(nil))
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package picotool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Load(uf2Path string, serial string, timeout time.Duration) error {
|
||||
deadline := time.Now().Add(timeout)
|
||||
var out []byte
|
||||
var err error
|
||||
for {
|
||||
cmd := exec.Command("picotool", "load", uf2Path, "-x", "--ser", serial)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
return fmt.Errorf("picotool load: %w\n%s", err, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Reboot(serial string) error {
|
||||
cmd := exec.Command("picotool", "reboot", "--ser", serial)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("picotool reboot: %w\n%s", err, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
71
lib/uf2/uf2.go
Normal file
71
lib/uf2/uf2.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package uf2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
blockSize = 512
|
||||
magic0 = 0x0A324655
|
||||
magic1 = 0x9E5D5157
|
||||
magicEnd = 0x0AB16F30
|
||||
|
||||
flagNotMainFlash = 0x00000001
|
||||
flagFamilyIDPresent = 0x00002000
|
||||
absoluteFamilyID = 0xe48bff57
|
||||
)
|
||||
|
||||
type Block struct {
|
||||
Addr uint32
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func Parse(path string) ([]Block, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(data)%blockSize != 0 {
|
||||
return nil, fmt.Errorf("file size %d not multiple of %d", len(data), blockSize)
|
||||
}
|
||||
|
||||
var blocks []Block
|
||||
for i := 0; i < len(data); i += blockSize {
|
||||
b := data[i : i+blockSize]
|
||||
m0 := binary.LittleEndian.Uint32(b[0:4])
|
||||
m1 := binary.LittleEndian.Uint32(b[4:8])
|
||||
me := binary.LittleEndian.Uint32(b[508:512])
|
||||
if m0 != magic0 || m1 != magic1 || me != magicEnd {
|
||||
return nil, fmt.Errorf("block %d: bad magic", i/blockSize)
|
||||
}
|
||||
flags := binary.LittleEndian.Uint32(b[8:12])
|
||||
if flags&flagNotMainFlash != 0 {
|
||||
continue
|
||||
}
|
||||
if flags&flagFamilyIDPresent != 0 {
|
||||
familyID := binary.LittleEndian.Uint32(b[28:32])
|
||||
if familyID == absoluteFamilyID {
|
||||
continue
|
||||
}
|
||||
}
|
||||
addr := binary.LittleEndian.Uint32(b[12:16])
|
||||
size := binary.LittleEndian.Uint32(b[16:20])
|
||||
if size > 256 {
|
||||
return nil, fmt.Errorf("block %d: data size %d > 256", i/blockSize, size)
|
||||
}
|
||||
blocks = append(blocks, Block{
|
||||
Addr: addr,
|
||||
Data: make([]byte, size),
|
||||
})
|
||||
copy(blocks[len(blocks)-1].Data, b[32:32+size])
|
||||
}
|
||||
|
||||
sort.Slice(blocks, func(i, j int) bool {
|
||||
return blocks[i].Addr < blocks[j].Addr
|
||||
})
|
||||
|
||||
return blocks, nil
|
||||
}
|
||||
Reference in New Issue
Block a user