diff --git a/command/ota/generate.go b/command/ota/generate.go index f2e6743f..def506bb 100644 --- a/command/ota/generate.go +++ b/command/ota/generate.go @@ -22,13 +22,14 @@ import ( "fmt" "io/ioutil" "os" + "strings" inota "github.com/arduino/arduino-cloud-cli/internal/ota" ) var ( - arduinoVendorID = "2341" - fqbnToPID = map[string]string{ + arduinoVendorID = "2341" + arduinoFqbnToPID = map[string]string{ "arduino:samd:nano_33_iot": "8057", "arduino:samd:mkr1000": "804E", "arduino:samd:mkrgsm1400": "8052", @@ -39,13 +40,31 @@ var ( "arduino:mbed_nicla:nicla_vision": "025F", "arduino:mbed_opta:opta": "0064", } + esp32MagicNumberPart1 = "4553" + esp32MagicNumberPart2 = "5033" ) // Generate takes a .bin file and generates a .ota file. func Generate(binFile string, outFile string, fqbn string) error { - productID, ok := fqbnToPID[fqbn] - if !ok { - return errors.New("fqbn not valid") + + // We are going to put a magic number in the ota .bin file, the fw will check the magic number once the binary is received + var magicNumberPart1, magicNumberPart2 string + + // The ota update is available for Arduino boards and ESP32 boards + + // Esp32 boards have a wide range of vid and pid, we don't map all of them + // If the fqbn is the one of an ESP32 board, we force a default magic number that matches the same default expected on the fw side + if strings.HasPrefix(fqbn, "esp32") { + magicNumberPart1 = esp32MagicNumberPart1 + magicNumberPart2 = esp32MagicNumberPart2 + } else { + //For Arduino Boards we use vendorId and productID to form the magic number + magicNumberPart1 = arduinoVendorID + productID, ok := arduinoFqbnToPID[fqbn] + if !ok { + return errors.New("fqbn not valid") + } + magicNumberPart2 = productID } data, err := ioutil.ReadFile(binFile) @@ -59,7 +78,7 @@ func Generate(binFile string, outFile string, fqbn string) error { } defer out.Close() - enc := inota.NewEncoder(out, arduinoVendorID, productID) + enc := inota.NewEncoder(out, magicNumberPart1, magicNumberPart2) err = enc.Encode(data) if err != nil { return fmt.Errorf("failed to encode binary file: %w", err) diff --git a/internal/ota/encoder.go b/internal/ota/encoder.go index b921e968..4d427555 100644 --- a/internal/ota/encoder.go +++ b/internal/ota/encoder.go @@ -33,18 +33,18 @@ type Encoder struct { w io.Writer // vendorID is the ID of the board vendor. - vendorID string + magicNumberPart1 string // productID is the ID of the board model. - productID string + magicNumberPart2 string } // NewEncoder creates a new ota encoder. -func NewEncoder(w io.Writer, vendorID, productID string) *Encoder { +func NewEncoder(w io.Writer, magicNumberPart1, magicNumberPart2 string) *Encoder { return &Encoder{ - w: w, - vendorID: vendorID, - productID: productID, + w: w, + magicNumberPart1: magicNumberPart1, + magicNumberPart2: magicNumberPart2, } } @@ -53,17 +53,17 @@ func NewEncoder(w io.Writer, vendorID, productID string) *Encoder { func (e *Encoder) Encode(data []byte) error { // Compute the magic number (VID/PID) magicNumber := make([]byte, 4) - vid, err := strconv.ParseUint(e.vendorID, 16, 16) + magicNumberPart1, err := strconv.ParseUint(e.magicNumberPart1, 16, 16) if err != nil { return fmt.Errorf("cannot parse vendorID: %w", err) } - pid, err := strconv.ParseUint(e.productID, 16, 16) + magicNumberPart2, err := strconv.ParseUint(e.magicNumberPart2, 16, 16) if err != nil { return fmt.Errorf("cannot parse productID: %w", err) } - binary.LittleEndian.PutUint16(magicNumber[0:2], uint16(pid)) - binary.LittleEndian.PutUint16(magicNumber[2:4], uint16(vid)) + binary.LittleEndian.PutUint16(magicNumber[0:2], uint16(magicNumberPart2)) + binary.LittleEndian.PutUint16(magicNumber[2:4], uint16(magicNumberPart1)) // Version field (byte array of size 8) version := Version{