diff --git a/cli/cli.go b/cli/cli.go index 2fa31b02..3d304dfb 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -20,26 +20,18 @@ package cli import ( - "encoding/json" "fmt" "io/ioutil" - "log" "os" "strings" - "time" "github.com/arduino/FirmwareUploader/cli/certificates" "github.com/arduino/FirmwareUploader/cli/firmware" "github.com/arduino/FirmwareUploader/cli/version" - "github.com/arduino/FirmwareUploader/modules/nina" - "github.com/arduino/FirmwareUploader/modules/sara" - "github.com/arduino/FirmwareUploader/modules/winc" - "github.com/arduino/FirmwareUploader/utils" - "github.com/arduino/FirmwareUploader/utils/context" + v "github.com/arduino/FirmwareUploader/version" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" - "github.com/arduino/go-paths-helper" "github.com/mattn/go-colorable" "github.com/rifflock/lfshook" "github.com/sirupsen/logrus" @@ -47,7 +39,6 @@ import ( ) var ( - ctx = &context.Context{} outputFormat string verbose bool logFile string @@ -63,7 +54,6 @@ func NewCommand() *cobra.Command { Long: "FirmwareUploader (FirmwareUploader).", Example: " " + os.Args[0] + " [flags...]", Args: cobra.NoArgs, - Run: run, PersistentPreRun: preRun, } @@ -71,20 +61,7 @@ func NewCommand() *cobra.Command { rootCmd.AddCommand(firmware.NewCommand()) rootCmd.AddCommand(certificates.NewCommand()) - rootCmd.Flags().StringVar(&ctx.PortName, "port", "", "serial port to use for flashing") - rootCmd.Flags().StringVar(&ctx.RootCertDir, "certs", "", "root certificate directory") - rootCmd.Flags().StringSliceVar(&ctx.Addresses, "address", []string{}, "address (host:port) to fetch and flash root certificate for, multiple values allowed") - rootCmd.Flags().StringVar(&ctx.FirmwareFile, "firmware", "", "firmware file to flash") - rootCmd.Flags().BoolVar(&ctx.ReadAll, "read", false, "read all firmware and output to stdout") - rootCmd.Flags().StringVar(&ctx.FWUploaderBinary, "flasher", "", "firmware upload binary (precompiled for the right target)") - rootCmd.Flags().StringVar(&ctx.BinaryToRestore, "restore_binary", "", "binary to restore after the firmware upload (precompiled for the right target)") - rootCmd.Flags().StringVar(&ctx.ProgrammerPath, "programmer", "", "path of programmer in use (avrdude/bossac)") - rootCmd.Flags().StringVar(&ctx.Model, "model", "", "module model (winc, nina or sara)") - rootCmd.Flags().StringVar(&ctx.BoardName, "get_available_for", "", "Ask for available firmwares matching a given board") - rootCmd.Flags().IntVar(&ctx.Retries, "retries", 9, "Number of retries in case of upload failure") - rootCmd.PersistentFlags().StringVar(&outputFormat, "format", "text", "The output format, can be {text|json}.") - rootCmd.PersistentFlags().StringVar(&logFile, "log-file", "", "Path to the file where logs will be written") rootCmd.PersistentFlags().StringVar(&logFormat, "log-format", "", "The output format for the logs, can be {text|json}.") rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Messages with this level and above will be logged. Valid levels are: trace, debug, info, warn, error, fatal, panic") @@ -93,60 +70,6 @@ func NewCommand() *cobra.Command { return rootCmd } -func run(cmd *cobra.Command, args []string) { - if ctx.BoardName != "" { - el, _ := json.Marshal(utils.GetCompatibleWith(ctx.BoardName, "")) - fmt.Println(string(el)) - os.Exit(0) - } - - if ctx.PortName == "" { - log.Fatal("Please specify a serial port") - } - - if ctx.BinaryToRestore != "" { - // sanity check for BinaryToRestore - f := paths.New(ctx.BinaryToRestore) - info, err := f.Stat() - if err != nil { - log.Fatalf("Error opening restore_binary: %s", err) - } - if info.IsDir() { - log.Fatalf("Error opening restore_binary: is a directory...") - } - if info.Size() == 0 { - log.Println("WARNING: restore_binary is empty! Will not restore binary after upload.") - ctx.BinaryToRestore = "" - } - } - - retry := 0 - for { - var err error - if ctx.Model == "nina" || strings.Contains(ctx.FirmwareFile, "NINA") || strings.Contains(ctx.FWUploaderBinary, "NINA") { - err = nina.Run(ctx) - } else if ctx.Model == "winc" || strings.Contains(ctx.FirmwareFile, "WINC") || strings.Contains(ctx.FWUploaderBinary, "WINC") { - err = winc.Run(ctx) - } else { - err = sara.Run(ctx) - } - if err == nil { - log.Println("Operation completed: success! :-)") - break - } - log.Println("Error: " + err.Error()) - - if retry >= ctx.Retries { - log.Fatal("Operation failed. :-(") - } - - retry++ - log.Println("Waiting 1 second before retrying...") - time.Sleep(time.Second) - log.Printf("Retrying upload (%d of %d)", retry, ctx.Retries) - } -} - // Convert the string passed to the `--log-level` option to the corresponding // logrus formal level. func toLogLevel(s string) (t logrus.Level, found bool) { diff --git a/go.mod b/go.mod index 4909756d..7d86f080 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,9 @@ replace go.bug.st/serial => github.com/cmaglie/go-serial v0.0.0-20200923162623-b require ( github.com/arduino/arduino-cli v0.0.0-20210603144340-aef5a54882fa github.com/arduino/go-paths-helper v1.6.0 - github.com/arduino/go-properties-orderedmap v1.3.0 // indirect + github.com/arduino/go-properties-orderedmap v1.3.0 github.com/cmaglie/go.rice v1.0.3 github.com/mattn/go-colorable v0.1.8 - github.com/pkg/errors v0.9.1 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.1.3 diff --git a/modules/nina/certificates.go b/modules/nina/certificates.go deleted file mode 100644 index 396ee9d7..00000000 --- a/modules/nina/certificates.go +++ /dev/null @@ -1,134 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package nina - -import ( - "crypto/tls" - "crypto/x509" - "encoding/pem" - "errors" - "io/ioutil" - "log" - "path" - "path/filepath" -) - -type CertEntry []byte - -func ConvertCertificates(directory string, addresses []string) ([]byte, error) { - var entryBytes []byte - - if directory != "" { - cerFiles, err := filepath.Glob(path.Join(directory, "*.cer")) - if err != nil { - return nil, err - } - - for _, cerFile := range cerFiles { - cerEntry, err := EntryForFile(cerFile) - - if err != nil { - log.Printf("Converting '%v' failed, skipping: %v\n", cerFile, err) - } else { - entryBytes = append(entryBytes, cerEntry...) - } - } - } - - for _, address := range addresses { - cerEntry, err := EntryForAddress(address) - - if err != nil { - log.Printf("Converting address '%v' failed, skipping: %v\n", address, err) - } else { - entryBytes = append(entryBytes, cerEntry...) - } - } - - return entryBytes, nil -} - -func EntryForFile(file string) (b CertEntry, err error) { - cerData, err := ioutil.ReadFile(file) - if err != nil { - return nil, err - } - - certs, err := x509.ParseCertificates(cerData) - if err != nil { - return nil, err - } - - if len(certs) < 1 { - return nil, errors.New("No certificates in file") - } - - cert := certs[0] - - return entryForCert(cert) -} - -func EntryForAddress(address string) (b CertEntry, err error) { - config := &tls.Config{ - InsecureSkipVerify: true, - } - - conn, err := tls.Dial("tcp", address, config) - if err != nil { - return nil, err - } - - if err := conn.Handshake(); err != nil { - return nil, err - } - - peerCerts := conn.ConnectionState().PeerCertificates - - if len(peerCerts) == 0 { - return nil, errors.New("No peer certificates") - } - - rootCert := peerCerts[len(peerCerts)-1] - - conn.Close() - - return entryForCert(rootCert) -} - -/* Write Root Certificate to flash. Must convert certificates to PEM and append them -- SHA1_DIGEST_SIZE --> NameSHA1 of the Root certificate. -- uint16 --> N_SIZE (Byte count for the RSA modulus N). -- uint16 --> E_SIZE (Byte count for the RSA public exponent E). -- START_DATE --> Start date of the root certificate(20 bytes). -- EXPIRATION_DATE --> Expiration date of the root certificate(20 bytes). -- N_SIZE --> RSA Modulus N. -- E_SIZE --> RSA Public exponent. -*/ - -func entryForCert(cert *x509.Certificate) (b CertEntry, err error) { - return certToPEM(cert), nil -} - -// CertToPEM is a utility function returns a PEM encoded x509 Certificate -func certToPEM(cert *x509.Certificate) []byte { - pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) - - return pemCert -} diff --git a/modules/nina/flasher.go b/modules/nina/flasher.go deleted file mode 100644 index 2c54c01e..00000000 --- a/modules/nina/flasher.go +++ /dev/null @@ -1,259 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package nina - -import ( - "bytes" - "crypto/md5" - "encoding/binary" - "log" - "time" - - "github.com/arduino/FirmwareUploader/utils" - "go.bug.st/serial" -) - -type FlasherError struct { - err string -} - -func (e FlasherError) Error() string { - return e.err -} - -type Flasher struct { - port serial.Port -} - -// Ping the programmer to see if it is alive. -// Also check if the version of the programmer protocol match the uploader -func (flasher *Flasher) Hello() error { - // "HELLO" command - if err := flasher.sendCommand(0x99, 0x11223344, 0x55667788, nil); err != nil { - return err - } - - // Wait a bit - time.Sleep(100 * time.Millisecond) - - // Receive response - res := make([]byte, 65535) - n, err := flasher.port.Read(res) - if err != nil { - return err - } - // flush eventual leftover from the rx buffer - if n >= 6 { - res = res[n-6 : n] - } - - if res[0] != 'v' { - return &FlasherError{err: "Programmer is not responding"} - } - if string(res) != "v10000" { - return &FlasherError{err: "Programmer version mismatch: " + string(res) + " (needed v10000)"} - } - return nil -} - -func (flasher *Flasher) Close() error { - return flasher.port.Close() -} - -// Get maximum payload size for upload. -func (flasher *Flasher) GetMaximumPayloadSize() (uint16, error) { - // "MAX_PAYLOAD_SIZE" command - if err := flasher.sendCommand(0x50, 0, 0, nil); err != nil { - return 0, err - } - - // Receive response - res := make([]byte, 2) - if err := flasher.serialFillBuffer(res); err != nil { - return 0, err - } - return (uint16(res[0]) << 8) + uint16(res[1]), nil -} - -// Read a block of flash memory -func (flasher *Flasher) Read(address uint32, length uint32) ([]byte, error) { - // "FLASH_READ" command - if err := flasher.sendCommand(0x01, address, length, nil); err != nil { - return nil, err - } - - // Receive response - result := make([]byte, length) - if err := flasher.serialFillBuffer(result); err != nil { - return nil, err - } - ack := make([]byte, 2) - if err := flasher.serialFillBuffer(ack); err != nil { - return nil, err - } - if string(ack) != "OK" { - return nil, &FlasherError{err: "Error during FlashRead()"} - } - return result, nil -} - -// Write a block of flash memory -func (flasher *Flasher) Write(address uint32, buffer []byte) error { - // "FLASH_WRITE" command - if err := flasher.sendCommand(0x02, address, 0, buffer); err != nil { - return err - } - - // wait acknowledge - ack := make([]byte, 2) - if err := flasher.serialFillBuffer(ack); err != nil { - return err - } - if string(ack) != "OK" { - return &FlasherError{err: "Error during FlashWrite()"} - } - return nil -} - -// Erase a block of flash memory -func (flasher *Flasher) Erase(address uint32, length uint32) error { - // "FLASH_ERASE" command - if err := flasher.sendCommand(0x03, address, length, nil); err != nil { - return err - } - - log.Printf("Erasing %d bytes from address 0x%X\n", length, address) - - // wait acknowledge - ack := make([]byte, 2) - if err := flasher.serialFillBuffer(ack); err != nil { - return err - } - if string(ack) != "OK" { - return &FlasherError{err: "Error during FlashErase()"} - } - return nil -} - -// Fill buffer with data coming from serial port. -// Blocks until the buffer is full. -func (flasher *Flasher) serialFillBuffer(buffer []byte) error { - read := 0 - for read < len(buffer) { - n, err := flasher.port.Read(buffer[read:]) - if err != nil { - return err - } - if n == 0 { - return &FlasherError{err: "Serial port closed unexpectedly"} - } - read += n - } - return nil -} - -func (flasher *Flasher) sendCommand(command byte, address uint32, val uint32, payload []byte) error { - buff := new(bytes.Buffer) - if err := binary.Write(buff, binary.BigEndian, command); err != nil { - return err - } - if err := binary.Write(buff, binary.BigEndian, address); err != nil { - return err - } - if err := binary.Write(buff, binary.BigEndian, val); err != nil { - return err - } - var length uint16 - if payload == nil { - length = 0 - } else { - length = uint16(len(payload)) - } - if err := binary.Write(buff, binary.BigEndian, length); err != nil { - return err - } - if payload != nil { - buff.Write(payload) - } - data := buff.Bytes() - for { - sent, err := flasher.port.Write(data) - if err != nil { - return err - } - if sent == len(data) { - break - } - // fmt.Println("HEY! sent", sent, "out of", len(data)) - data = data[sent:] - } - return nil -} - -func (flasher *Flasher) Md5sum(data []byte) error { - hasher := md5.New() - hasher.Write(data) - - log.Println("Checking firmware integrity") - - // Get md5sum - if err := flasher.sendCommand(0x04, 0, uint32(len(data)), nil); err != nil { - return err - } - - // wait acknowledge - ack := make([]byte, 2) - if err := flasher.serialFillBuffer(ack); err != nil { - return err - } - if string(ack) != "OK" { - return &FlasherError{err: "Error during Md5sum()"} - } - - // wait md5 - md5sum := make([]byte, 16) - if err := flasher.serialFillBuffer(md5sum); err != nil { - return err - } - - md5sumfromdevice := hasher.Sum(nil) - - i := 0 - for i < 16 { - if md5sumfromdevice[i] != md5sum[i] { - return &FlasherError{err: "MD5sum failed"} - } - i++ - } - - log.Println("Integrity ok") - - return nil -} - -func OpenFlasher(portName string) (*Flasher, error) { - port, err := utils.OpenSerial(portName) - if err != nil { - return nil, &FlasherError{err: "Error opening serial port. " + err.Error()} - } - - time.Sleep(2 * time.Second) - return &Flasher{port: port}, err -} diff --git a/modules/nina/nina.go b/modules/nina/nina.go deleted file mode 100644 index 9ea18161..00000000 --- a/modules/nina/nina.go +++ /dev/null @@ -1,202 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package nina - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/arduino/FirmwareUploader/programmers/avrdude" - "github.com/arduino/FirmwareUploader/programmers/bossac" - "github.com/arduino/FirmwareUploader/programmers/rp2040load" - "github.com/arduino/FirmwareUploader/utils" - "github.com/arduino/FirmwareUploader/utils/context" - "github.com/pkg/errors" -) - -var flasher *Flasher -var payloadSize uint16 - -func Run(ctx *context.Context) error { - var programmer utils.Programmer - - if ctx.ProgrammerPath != "" { - if strings.Contains(filepath.Base(ctx.ProgrammerPath), "bossac") { - programmer = bossac.NewBossac(ctx) - } else if strings.Contains(filepath.Base(ctx.ProgrammerPath), "avrdude") { - programmer = avrdude.NewAvrdude(ctx) - } else if strings.Contains(filepath.Base(ctx.ProgrammerPath), "rp2040load") { - programmer = rp2040load.NewRP2040Load(ctx) - } else { - return errors.New("Programmer path not specified correctly, programmer path set to: " + ctx.ProgrammerPath) - } - } - - if ctx.FWUploaderBinary != "" { - log.Println("Flashing firmware uploader nina") - if programmer == nil { - return errors.New("ERROR: You must specify a programmer!") - } - if err := programmer.Flash(ctx.FWUploaderBinary, nil); err != nil { - return err - } - } - - log.Println("Connecting to programmer") - if f, err := OpenFlasher(ctx.PortName); err != nil { - return err - } else { - flasher = f - } - defer flasher.Close() - - // Synchronize with programmer - log.Println("Sync with programmer") - if err := flasher.Hello(); err != nil { - return err - } - - // Check maximum supported payload size - log.Println("Reading max payload size") - if _payloadSize, err := flasher.GetMaximumPayloadSize(); err != nil { - return err - } else { - payloadSize = _payloadSize - } - if payloadSize < 1024 { - return errors.Errorf("Programmer reports %d as maximum payload size (1024 is needed)", payloadSize) - } - - if ctx.FirmwareFile != "" { - if err := flashFirmware(ctx); err != nil { - return err - } - } - - if ctx.RootCertDir != "" || len(ctx.Addresses) != 0 { - if err := flashCerts(ctx); err != nil { - return err - } - } - - if ctx.ReadAll { - log.Println("Reading all flash") - if err := readAllFlash(); err != nil { - return err - } - } - - flasher.Close() - - if ctx.BinaryToRestore != "" { - log.Println("Restoring binary") - if programmer == nil { - errors.New("ERROR: You must specify a programmer!") - } - if err := programmer.Flash(ctx.BinaryToRestore, nil); err != nil { - return err - } - } - return nil -} - -func readAllFlash() error { - for i := 0; i < 256; i++ { - if data, err := flasher.Read(uint32(i*1024), 1024); err != nil { - return err - } else { - os.Stdout.Write(data) - } - } - return nil -} - -func flashCerts(ctx *context.Context) error { - CertificatesOffset := 0x10000 - - if ctx.RootCertDir != "" { - log.Printf("Converting and flashing certificates from '%v'", ctx.RootCertDir) - } - - certificatesData, err := ConvertCertificates(ctx.RootCertDir, ctx.Addresses) - if err != nil { - return err - } - - if len(certificatesData) > 0x20000 { - errors.New("Too many certificates! Aborting") - } - - // pad certificatesData to flash page - for len(certificatesData)%int(payloadSize) != 0 { - certificatesData = append(certificatesData, 0) - } - - log.Println(string(certificatesData)) - - return flashChunk(CertificatesOffset, certificatesData, false) -} - -func flashFirmware(ctx *context.Context) error { - FirmwareOffset := 0x0000 - - log.Printf("Flashing firmware from '%v'", ctx.FirmwareFile) - - fwData, err := ioutil.ReadFile(ctx.FirmwareFile) - if err != nil { - return err - } - - return flashChunk(FirmwareOffset, fwData, true) -} - -func flashChunk(offset int, buffer []byte, doChecksum bool) error { - chunkSize := int(payloadSize) - bufferLength := len(buffer) - - if err := flasher.Erase(uint32(offset), uint32(bufferLength)); err != nil { - return err - } - - for i := 0; i < bufferLength; i += chunkSize { - fmt.Printf("\rFlashing: " + strconv.Itoa((i*100)/bufferLength) + "%%") - start := i - end := i + chunkSize - if end > bufferLength { - end = bufferLength - } - if err := flasher.Write(uint32(offset+i), buffer[start:end]); err != nil { - return err - } - } - - fmt.Println("") - - if doChecksum { - return flasher.Md5sum(buffer) - } else { - return nil - } -} diff --git a/modules/sara/flasher.go b/modules/sara/flasher.go deleted file mode 100644 index 8b1d7d82..00000000 --- a/modules/sara/flasher.go +++ /dev/null @@ -1,151 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package sara - -import ( - "log" - "strings" - "time" - - "github.com/arduino/FirmwareUploader/utils" - "go.bug.st/serial" -) - -type FlasherError struct { - err string -} - -func (e FlasherError) Error() string { - return e.err -} - -type Flasher struct { - port serial.Port -} - -func (flasher *Flasher) Hello() error { - flasher.Expect("ATE0", "OK", 100) - flasher.Expect("ATE0", "OK", 100) - flasher.Expect("ATE0", "OK", 100) - _, err := flasher.Expect("AT", "OK", 100) - return err -} - -func (flasher *Flasher) ExpectMinBytes(buffer string, response string, timeout int, min_bytes int) (string, error) { - err := flasher.sendCommand([]byte(buffer + "\r\n")) - if err != nil { - return "", err - } - - log.Println("Sending " + buffer) - - // Wait a bit - // time.Sleep(time.Duration(timeout) * time.Millisecond) - - // Receive response - var res []byte - n := 0 - - start := time.Now() - - for (time.Since(start) < time.Duration(timeout)*time.Millisecond && !strings.Contains(string(res), response)) || (len(res) < min_bytes) { - data := 0 - partial := make([]byte, 65535) - data, err = flasher.port.Read(partial) - res = append(res, partial[:data]...) - n += data - if err != nil { - return "", err - } - } - - log.Println(string(res)) - - if !strings.Contains(string(res), response) { - return string(res), &FlasherError{err: "Expected " + response + ", got " + string(res)} - } - return string(res), nil -} - -func (flasher *Flasher) Expect(buffer string, response string, timeout int) (string, error) { - return flasher.ExpectMinBytes(buffer, response, timeout, 0) -} - -func (flasher *Flasher) Close() error { - return flasher.port.Close() -} - -func (flasher *Flasher) GetFwVersion() (string, error) { - return flasher.ExpectMinBytes("ATI9", "05.06,A.02.", 100, 25) -} - -// Write a block of flash memory -func (flasher *Flasher) Write(address uint32, buffer []byte) error { - if err := flasher.sendCommand(buffer); err != nil { - return err - } - return nil -} - -// Fill buffer with data coming from serial port. -// Blocks until the buffer is full. -func (flasher *Flasher) serialFillBuffer(buffer []byte) error { - read := 0 - for read < len(buffer) { - n, err := flasher.port.Read(buffer[read:]) - if err != nil { - return err - } - if n == 0 { - return &FlasherError{err: "Serial port closed unexpectedly"} - } - read += n - } - return nil -} - -func (flasher *Flasher) sendCommand(payload []byte) error { - if payload != nil { - for { - if sent, err := flasher.port.Write(payload); err != nil { - return err - } else if sent < len(payload) { - payload = payload[sent:] - } else { - break - } - } - } - return nil -} - -func OpenFlasher(portName string) (*Flasher, error) { - - port, err := utils.OpenSerial(portName) - if err != nil { - return nil, &FlasherError{err: "Error opening serial port. " + err.Error()} - } - - flasher := &Flasher{ - port: port, - } - - return flasher, err -} diff --git a/modules/sara/sara.go b/modules/sara/sara.go deleted file mode 100644 index 05bf3b4d..00000000 --- a/modules/sara/sara.go +++ /dev/null @@ -1,166 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package sara - -import ( - "fmt" - "io/ioutil" - "log" - "strconv" - "time" - - "github.com/arduino/FirmwareUploader/programmers/bossac" - "github.com/arduino/FirmwareUploader/utils/context" -) - -var flasher *Flasher -var payloadSize uint16 - -func Run(ctx *context.Context) error { - programmer := bossac.NewBossac(ctx) - - if ctx.FWUploaderBinary != "" { - log.Println("Flashing firmware uploader sara") - if err := programmer.Flash(ctx.FWUploaderBinary, nil); err != nil { - return err - } - } - - log.Println("Connecting to programmer") - if f, err := OpenFlasher(ctx.PortName); err != nil { - return err - } else { - flasher = f - } - defer flasher.Close() - - time.Sleep(2 * time.Second) - - // Synchronize with programmer - log.Println("Sync with programmer") - if err := flasher.Hello(); err != nil { - return err - } - - // Check maximum supported payload size - log.Println("Reading actual firmware version") - - if fwVersion, err := flasher.GetFwVersion(); err != nil { - return err - } else { - log.Println("Initial firmware version: " + fwVersion) - } - - payloadSize = 128 - - if ctx.FirmwareFile != "" { - if err := flashFirmware(ctx); err != nil { - return err - } - } - - if fwVersion, err := flasher.GetFwVersion(); err != nil { - return err - } else { - log.Println("After applying update firmware version: " + fwVersion) - } - - flasher.Close() - - if ctx.BinaryToRestore != "" { - log.Println("Restoring previous sketch") - - if err := programmer.Flash(ctx.BinaryToRestore, nil); err != nil { - return err - } - } - return nil -} - -func flashFirmware(ctx *context.Context) error { - FirmwareOffset := 0x0000 - - log.Printf("Flashing firmware from '%v'", ctx.FirmwareFile) - - fwData, err := ioutil.ReadFile(ctx.FirmwareFile) - if err != nil { - return err - } - - _, err = flasher.Expect("AT+ULSTFILE", "+ULSTFILE:", 1000) - if err != nil { - return err - } - - _, err = flasher.Expect("AT+UDWNFILE=\"UPDATE.BIN\","+strconv.Itoa(len(fwData))+",\"FOAT\"", ">", 20000) - if err != nil { - return err - } - - err = flashChunk(FirmwareOffset, fwData) - if err != nil { - return err - } - - time.Sleep(1 * time.Second) - - _, err = flasher.Expect("", "OK", 1000) - if err != nil { - return err - } - - _, err = flasher.Expect("AT+UFWINSTALL", "OK", 60000) - if err != nil { - return err - } - - time.Sleep(10 * time.Second) - - // wait up to 20 minutes trying to ping the module. After 20 minutes signal the error - start := time.Now() - for time.Since(start) < time.Minute*20 { - err = flasher.Hello() - if err == nil { - return nil - } - time.Sleep(1 * time.Second) - } - return err -} - -func flashChunk(offset int, buffer []byte) error { - chunkSize := int(payloadSize) - bufferLength := len(buffer) - - for i := 0; i < bufferLength; i += chunkSize { - fmt.Printf("\rFlashing: " + strconv.Itoa((i*100)/bufferLength) + "%%") - start := i - end := i + chunkSize - if end > bufferLength { - end = bufferLength - } - if err := flasher.Write(uint32(offset+i), buffer[start:end]); err != nil { - return err - } - //time.Sleep(1 * time.Millisecond) - } - - return nil -} diff --git a/modules/winc/certificates.go b/modules/winc/certificates.go deleted file mode 100644 index c3ba639b..00000000 --- a/modules/winc/certificates.go +++ /dev/null @@ -1,253 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package winc - -import ( - "bytes" - "crypto/rsa" - "crypto/sha1" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "encoding/binary" - "errors" - "io/ioutil" - "log" - "path" - "path/filepath" - "time" -) - -var START_PATTERN = []byte{0x01, 0xF1, 0x02, 0xF2, 0x03, 0xF3, 0x04, 0xF4, 0x05, 0xF5, 0x06, 0xF6, 0x07, 0xF7, 0x08, 0xF8} - -type CertEntry []byte - -func ConvertCertificates(directory string, addresses []string) ([]byte, error) { - var entryBytes []byte - var numCerts int = 0 - - if directory != "" { - cerFiles, err := filepath.Glob(path.Join(directory, "*.cer")) - if err != nil { - return nil, err - } - - for _, cerFile := range cerFiles { - cerEntry, err := EntryForFile(cerFile) - - if err != nil { - log.Printf("Converting '%v' failed, skipping: %v\n", cerFile, err) - } else { - entryBytes = append(entryBytes, cerEntry...) - numCerts++ - } - } - } - - for _, address := range addresses { - cerEntry, err := EntryForAddress(address) - - if err != nil { - log.Printf("Converting address '%v' failed, skipping: %v\n", address, err) - } else { - entryBytes = append(entryBytes, cerEntry...) - numCerts++ - } - } - - numCertsBytes := uint32ToBytes(numCerts) - - flashData := START_PATTERN - flashData = append(flashData, numCertsBytes...) - flashData = append(flashData, entryBytes...) - - return flashData, nil -} - -func ConvertCertEntries(entries []CertEntry) []byte { - numCertsBytes := uint32ToBytes(len(entries)) - - flashData := START_PATTERN - flashData = append(flashData, numCertsBytes...) - for _, entry := range entries { - flashData = append(flashData, entry...) - } - - return flashData -} - -func EntryForFile(file string) (b CertEntry, err error) { - cerData, err := ioutil.ReadFile(file) - if err != nil { - return nil, err - } - - certs, err := x509.ParseCertificates(cerData) - if err != nil { - return nil, err - } - - if len(certs) < 1 { - return nil, errors.New("No certificates in file") - } - - cert := certs[0] - - return entryForCert(cert) -} - -func EntryForAddress(address string) (b CertEntry, err error) { - config := &tls.Config{ - InsecureSkipVerify: true, - } - - conn, err := tls.Dial("tcp", address, config) - if err != nil { - return nil, err - } - - if err := conn.Handshake(); err != nil { - return nil, err - } - - peerCerts := conn.ConnectionState().PeerCertificates - - if len(peerCerts) == 0 { - return nil, errors.New("No peer certificates") - } - - rootCert := peerCerts[len(peerCerts)-1] - - conn.Close() - - return entryForCert(rootCert) -} - -/* Write Root Certificate to flash. The entry is ordered as follows: -- SHA1_DIGEST_SIZE --> NameSHA1 of the Root certificate. -- uint16 --> N_SIZE (Byte count for the RSA modulus N). -- uint16 --> E_SIZE (Byte count for the RSA public exponent E). -- START_DATE --> Start date of the root certificate(20 bytes). -- EXPIRATION_DATE --> Expiration date of the root certificate(20 bytes). -- N_SIZE --> RSA Modulus N. -- E_SIZE --> RSA Public exponent. -*/ - -func entryForCert(cert *x509.Certificate) (b CertEntry, err error) { - nameSHA1Bytes, err := calculateNameSha1(*cert) - if err != nil { - return nil, err - } - - notBeforeBytes, err := convertTime(cert.NotBefore) - if err != nil { - return nil, err - } - - notAfterBytes, err := convertTime(cert.NotAfter) - if err != nil { - return nil, err - } - - rsaPublicKey := *cert.PublicKey.(*rsa.PublicKey) - - rsaModulusNBytes := getModulusN(rsaPublicKey) - rsaPublicExponentBytes := getPublicExponent(rsaPublicKey) - - rsaModulusNLenBytes := uint16ToBytes(len(rsaModulusNBytes)) - rsaPublicExponentLenBytes := uint16ToBytes(len(rsaPublicExponentBytes)) - - b = append(b, nameSHA1Bytes...) - b = append(b, rsaModulusNLenBytes...) - b = append(b, rsaPublicExponentLenBytes...) - b = append(b, notBeforeBytes...) - b = append(b, notAfterBytes...) - b = append(b, rsaModulusNBytes...) - b = append(b, rsaPublicExponentBytes...) - for (len(b) & 3) != 0 { - b = append(b, 0xff) // padding - } - - return -} - -func uint16ToBytes(i int) (b []byte) { - b = make([]byte, 2) - - binary.LittleEndian.PutUint16(b, uint16(i)) - - return -} - -func uint32ToBytes(i int) (b []byte) { - b = make([]byte, 4) - - binary.LittleEndian.PutUint32(b, uint32(i)) - - return -} - -func calculateNameSha1(cert x509.Certificate) (b []byte, err error) { - nameSha1 := sha1.New() - - var subjectDistinguishedNameSequence pkix.RDNSequence - - if _, err = asn1.Unmarshal(cert.RawSubject, &subjectDistinguishedNameSequence); err != nil { - return nil, err - } - - for _, dn := range subjectDistinguishedNameSequence { - nameSha1.Write([]byte(dn[0].Value.(string))) - } - - b = nameSha1.Sum(nil) - - return -} - -func getModulusN(publicKey rsa.PublicKey) []byte { - return publicKey.N.Bytes() -} - -func getPublicExponent(publicKey rsa.PublicKey) (b []byte) { - b = make([]byte, 4) - - binary.BigEndian.PutUint32(b, uint32(publicKey.E)) - - // strip leading zeros - for b[0] == 0 { - b = b[1:] - } - - return -} - -func convertTime(time time.Time) (b []byte, err error) { - asn1Bytes, err := asn1.Marshal(time) - if err != nil { - return nil, err - } - - b = bytes.Repeat([]byte{0x00}, 20) // value must be zero bytes - copy(b, asn1Bytes[2:]) // copy but drop the first two bytes - - return -} diff --git a/modules/winc/flasher.go b/modules/winc/flasher.go deleted file mode 100644 index 179cba2a..00000000 --- a/modules/winc/flasher.go +++ /dev/null @@ -1,222 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package winc - -import ( - "bytes" - "encoding/binary" - "log" - "time" - - "github.com/arduino/FirmwareUploader/utils" - "go.bug.st/serial" -) - -type FlasherError struct { - err string -} - -func (e FlasherError) Error() string { - return e.err -} - -type Flasher struct { - port serial.Port -} - -// Ping the programmer to see if it is alive. -// Also check if the version of the programmer protocol match the uploader -func (flasher *Flasher) Hello() error { - // "HELLO" command - if err := flasher.sendCommand(0x99, 0x11223344, 0x55667788, nil); err != nil { - return err - } - - // Wait a bit - time.Sleep(100 * time.Millisecond) - - // Receive response - res := make([]byte, 65535) - n, err := flasher.port.Read(res) - if err != nil { - return err - } - // flush eventual leftover from the rx buffer - if n >= 6 { - res = res[n-6 : n] - } - - if res[0] != 'v' { - return &FlasherError{err: "Programmer is not responding"} - } - if string(res) != "v10000" { - return &FlasherError{err: "Programmer version mismatch: " + string(res) + " (needed v10000)"} - } - return nil -} - -func (flasher *Flasher) Close() error { - return flasher.port.Close() -} - -// Get maximum payload size for upload. -func (flasher *Flasher) GetMaximumPayloadSize() (uint16, error) { - // "MAX_PAYLOAD_SIZE" command - if err := flasher.sendCommand(0x50, 0, 0, nil); err != nil { - return 0, err - } - - // Receive response - res := make([]byte, 2) - if err := flasher.serialFillBuffer(res); err != nil { - return 0, err - } - return (uint16(res[0]) << 8) + uint16(res[1]), nil -} - -// Read a block of flash memory -func (flasher *Flasher) Read(address uint32, length uint32) ([]byte, error) { - // "FLASH_READ" command - if err := flasher.sendCommand(0x01, address, length, nil); err != nil { - return nil, err - } - - // Receive response - result := make([]byte, length) - if err := flasher.serialFillBuffer(result); err != nil { - return nil, err - } - ack := make([]byte, 2) - if err := flasher.serialFillBuffer(ack); err != nil { - return nil, err - } - if string(ack) != "OK" { - return nil, &FlasherError{err: "Error during FlashRead()"} - } - return result, nil -} - -// Write a block of flash memory -func (flasher *Flasher) Write(address uint32, buffer []byte) error { - // "FLASH_WRITE" command - if err := flasher.sendCommand(0x02, address, 0, buffer); err != nil { - return err - } - - // wait acknowledge - ack := make([]byte, 2) - if err := flasher.serialFillBuffer(ack); err != nil { - return err - } - if string(ack) != "OK" { - return &FlasherError{err: "Error during FlashWrite()"} - } - return nil -} - -// Erase a block of flash memory -func (flasher *Flasher) Erase(address uint32, length uint32) error { - // "FLASH_ERASE" command - if err := flasher.sendCommand(0x03, address, length, nil); err != nil { - return err - } - - log.Printf("Erasing %d bytes from address 0x%X\n", length, address) - - // wait acknowledge - ack := make([]byte, 2) - if err := flasher.serialFillBuffer(ack); err != nil { - return err - } - if string(ack) != "OK" { - return &FlasherError{err: "Error during FlashErase()"} - } - return nil -} - -// Fill buffer with data coming from serial port. -// Blocks until the buffer is full. -func (flasher *Flasher) serialFillBuffer(buffer []byte) error { - read := 0 - for read < len(buffer) { - n, err := flasher.port.Read(buffer[read:]) - if err != nil { - return err - } - if n == 0 { - return &FlasherError{err: "Serial port closed unexpectedly"} - } - read += n - } - return nil -} - -func (flasher *Flasher) sendCommand(command byte, address uint32, val uint32, payload []byte) error { - buff := new(bytes.Buffer) - if err := binary.Write(buff, binary.BigEndian, command); err != nil { - return err - } - if err := binary.Write(buff, binary.BigEndian, address); err != nil { - return err - } - if err := binary.Write(buff, binary.BigEndian, val); err != nil { - return err - } - var length uint16 - if payload == nil { - length = 0 - } else { - length = uint16(len(payload)) - } - if err := binary.Write(buff, binary.BigEndian, length); err != nil { - return err - } - if payload != nil { - buff.Write(payload) - } - - data := buff.Bytes() - for { - sent, err := flasher.port.Write(data) - if err != nil { - return err - } - if sent == len(data) { - break - } - // fmt.Println("HEY! sent", sent, "out of", len(data)) - data = data[sent:] - } - return nil -} - -func OpenFlasher(portName string) (*Flasher, error) { - - port, err := utils.OpenSerial(portName) - if err != nil { - return nil, &FlasherError{err: "Error opening serial port. " + err.Error()} - } - - flasher := &Flasher{ - port: port, - } - - return flasher, err -} diff --git a/modules/winc/winc.go b/modules/winc/winc.go deleted file mode 100644 index 5e7402eb..00000000 --- a/modules/winc/winc.go +++ /dev/null @@ -1,185 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package winc - -import ( - "bytes" - "fmt" - "io/ioutil" - "log" - "os" - "strconv" - - "github.com/arduino/FirmwareUploader/programmers/bossac" - "github.com/arduino/FirmwareUploader/utils/context" - "github.com/pkg/errors" -) - -var flasher *Flasher -var payloadSize uint16 - -func Run(ctx *context.Context) error { - - programmer := bossac.NewBossac(ctx) - - if ctx.FWUploaderBinary != "" { - log.Println("Flashing firmware uploader winc") - if err := programmer.Flash(ctx.FWUploaderBinary, nil); err != nil { - return err - } - } - - log.Println("Connecting to programmer") - if f, err := OpenFlasher(ctx.PortName); err != nil { - return err - } else { - flasher = f - } - defer flasher.Close() - - // Synchronize with programmer - log.Println("Sync with programmer") - if err := flasher.Hello(); err != nil { - return err - } - - // Check maximum supported payload size - log.Println("Reading max payload size") - _payloadSize, err := flasher.GetMaximumPayloadSize() - if err != nil { - return err - } else { - payloadSize = _payloadSize - } - if payloadSize < 1024 { - return errors.Errorf("Programmer reports %d as maximum payload size (1024 is needed)", payloadSize) - } - - if ctx.FirmwareFile != "" { - if err := flashFirmware(ctx); err != nil { - return err - } - } - - if ctx.RootCertDir != "" || len(ctx.Addresses) != 0 { - if err := flashCerts(ctx); err != nil { - return err - } - } - - if ctx.ReadAll { - log.Println("Reading all flash") - if err := readAllFlash(); err != nil { - return err - } - } - - flasher.Close() - - if ctx.BinaryToRestore != "" { - log.Println("Restoring previous sketch") - - if err := programmer.Flash(ctx.BinaryToRestore, nil); err != nil { - return err - } - } - return nil -} - -func readAllFlash() error { - for i := 0; i < 256; i++ { - if data, err := flasher.Read(uint32(i*1024), 1024); err != nil { - return err - } else { - os.Stdout.Write(data) - } - } - return nil -} - -func flashCerts(ctx *context.Context) error { - CertificatesOffset := 0x4000 - - if ctx.RootCertDir != "" { - log.Printf("Converting and flashing certificates from '%v'", ctx.RootCertDir) - } - - certificatesData, err := ConvertCertificates(ctx.RootCertDir, ctx.Addresses) - if err != nil { - return err - } - - return flashChunk(CertificatesOffset, certificatesData) -} - -func flashFirmware(ctx *context.Context) error { - FirmwareOffset := 0x0000 - - log.Printf("Flashing firmware from '%v'", ctx.FirmwareFile) - - fwData, err := ioutil.ReadFile(ctx.FirmwareFile) - if err != nil { - return err - } - - return flashChunk(FirmwareOffset, fwData) -} - -func flashChunk(offset int, buffer []byte) error { - chunkSize := int(payloadSize) - bufferLength := len(buffer) - - if err := flasher.Erase(uint32(offset), uint32(bufferLength)); err != nil { - return err - } - - for i := 0; i < bufferLength; i += chunkSize { - fmt.Printf("\rFlashing: " + strconv.Itoa((i*100)/bufferLength) + "%%") - start := i - end := i + chunkSize - if end > bufferLength { - end = bufferLength - } - if err := flasher.Write(uint32(offset+i), buffer[start:end]); err != nil { - return err - } - } - - var flashData []byte - for i := 0; i < bufferLength; i += chunkSize { - readLength := chunkSize - if (i + chunkSize) > bufferLength { - readLength = bufferLength % chunkSize - } - - data, err := flasher.Read(uint32(offset+i), uint32(readLength)) - if err != nil { - return err - } - - flashData = append(flashData, data...) - } - - if !bytes.Equal(buffer, flashData) { - return errors.New("Flash data does not match written!") - } - - return nil -} diff --git a/programmers/avrdude/avrdude.go b/programmers/avrdude/avrdude.go deleted file mode 100644 index d7d7ce50..00000000 --- a/programmers/avrdude/avrdude.go +++ /dev/null @@ -1,74 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package avrdude - -import ( - "fmt" - "log" - "os" - "time" - - "github.com/arduino/FirmwareUploader/utils/context" - "github.com/arduino/arduino-cli/arduino/serialutils" - "github.com/arduino/arduino-cli/executils" - "github.com/arduino/go-paths-helper" -) - -type Avrdude struct { - avrdudePath *paths.Path - configPath *paths.Path -} - -func NewAvrdude(ctx *context.Context) *Avrdude { - avrdudePath := paths.New(ctx.ProgrammerPath) - return &Avrdude{ - avrdudePath: avrdudePath, - configPath: avrdudePath.Parent().Join("..", "etc", "avrdude.conf"), - } -} - -func (b *Avrdude) Flash(filename string, cb *serialutils.ResetProgressCallbacks) error { - log.Println("Flashing " + filename) - err := b.invoke( - fmt.Sprintf("-C%s", b.configPath), - "-v", - "-patmega4809", - "-cxplainedmini_updi", - "-Pusb", - "-b115200", - "-e", - "-D", - fmt.Sprintf("-Uflash:w:%s:i", filename), - "-Ufuse8:w:0x00:m") - - time.Sleep(5 * time.Second) - - return err -} - -func (b *Avrdude) invoke(args ...string) error { - cmd, err := executils.NewProcessFromPath(b.avrdudePath, args...) - if err != nil { - return err - } - cmd.RedirectStdoutTo(os.Stdout) - cmd.RedirectStderrTo(os.Stderr) - return cmd.Run() -} diff --git a/programmers/bossac/bossac.go b/programmers/bossac/bossac.go deleted file mode 100644 index 0718b953..00000000 --- a/programmers/bossac/bossac.go +++ /dev/null @@ -1,71 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package bossac - -import ( - "log" - "os" - "time" - - "github.com/arduino/FirmwareUploader/utils/context" - "github.com/arduino/arduino-cli/arduino/serialutils" - "github.com/arduino/arduino-cli/executils" - "github.com/arduino/go-paths-helper" -) - -type Bossac struct { - bossacPath *paths.Path - portName string -} - -func NewBossac(ctx *context.Context) *Bossac { - return &Bossac{ - bossacPath: paths.New(ctx.ProgrammerPath), - portName: ctx.PortName, - } -} - -func (b *Bossac) Flash(filename string, cb *serialutils.ResetProgressCallbacks) error { - log.Println("Entering board into bootloader mode") - port, err := serialutils.Reset(b.portName, true, cb) - if err != nil { - return err - } - - log.Println("Flashing " + filename) - if port == "" { - port = b.portName - } - err = b.invoke("-e", "-R", "-p", port, "-w", filename) - - time.Sleep(5 * time.Second) - - return err -} - -func (b *Bossac) invoke(args ...string) error { - cmd, err := executils.NewProcessFromPath(b.bossacPath, args...) - if err != nil { - return err - } - cmd.RedirectStdoutTo(os.Stdout) - cmd.RedirectStderrTo(os.Stderr) - return cmd.Run() -} diff --git a/programmers/rp2040load/rp2040load.go b/programmers/rp2040load/rp2040load.go deleted file mode 100644 index becb3065..00000000 --- a/programmers/rp2040load/rp2040load.go +++ /dev/null @@ -1,71 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package rp2040load - -import ( - "log" - "os" - "time" - - "github.com/arduino/FirmwareUploader/utils/context" - "github.com/arduino/arduino-cli/arduino/serialutils" - "github.com/arduino/arduino-cli/executils" - "github.com/arduino/go-paths-helper" - "github.com/pkg/errors" -) - -type RP2040Load struct { - rp2040LoadPath *paths.Path - portName string -} - -func NewRP2040Load(ctx *context.Context) *RP2040Load { - return &RP2040Load{ - rp2040LoadPath: paths.New(ctx.ProgrammerPath), - portName: ctx.PortName, - } -} - -func (b *RP2040Load) Flash(filename string, cb *serialutils.ResetProgressCallbacks) error { - log.Println("Entering board into bootloader mode") - _, err := serialutils.Reset(b.portName, true, cb) - if err != nil { - return err - } - - log.Println("Flashing " + filename) - if err := b.invoke("-v", "-D", filename); err != nil { - return errors.Errorf("Error flashing %s: %s", filename, err) - } - - time.Sleep(5 * time.Second) - - return err -} - -func (b *RP2040Load) invoke(args ...string) error { - cmd, err := executils.NewProcessFromPath(b.rp2040LoadPath, args...) - if err != nil { - return err - } - cmd.RedirectStdoutTo(os.Stdout) - cmd.RedirectStderrTo(os.Stderr) - return cmd.Run() -} diff --git a/utils/context/context.go b/utils/context/context.go deleted file mode 100644 index 6d50333f..00000000 --- a/utils/context/context.go +++ /dev/null @@ -1,34 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package context - -type Context struct { - PortName string - RootCertDir string - Addresses []string - FirmwareFile string - FWUploaderBinary string - ReadAll bool - BinaryToRestore string - ProgrammerPath string - Model string - BoardName string - Retries int -} diff --git a/utils/flasher.go b/utils/flasher.go deleted file mode 100644 index 3a2df2d4..00000000 --- a/utils/flasher.go +++ /dev/null @@ -1,64 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package utils - -import ( - "log" - "time" - - "github.com/arduino/arduino-cli/arduino/serialutils" - "go.bug.st/serial" -) - -// http://www.ni.com/product-documentation/54548/en/ -var baudRates = []int{ - // Standard baud rates supported by most serial ports - 115200, - 57600, - 56000, - 38400, -} - -type Programmer interface { - Flash(filename string, cb *serialutils.ResetProgressCallbacks) error -} - -func OpenSerial(portName string) (serial.Port, error) { - var lastError error - - for _, baudRate := range baudRates { - port, err := serial.Open(portName, &serial.Mode{BaudRate: baudRate}) - if err != nil { - lastError = err - // try another baudrate - continue - } - log.Printf("Opened the serial port with baud rate %d", baudRate) - - if err := port.SetReadTimeout(30 * time.Second); err != nil { - log.Fatalf("Could not set timeout on serial port: %s", err) - return nil, err - } - - return port, nil - } - - return nil, lastError -} diff --git a/utils/utils.go b/utils/utils.go deleted file mode 100644 index 99b660cb..00000000 --- a/utils/utils.go +++ /dev/null @@ -1,114 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package utils - -import ( - "os" - "path/filepath" - "regexp" - "strings" -) - -type firmware struct { - Path string - Name string - extra string - IsLoader bool -} - -type combo struct { - match string - loader string -} - -func GetCompatibleWith(name string, rootPath string) map[string][]firmware { - - files := make(map[string][]firmware) - - knownBoards := make(map[string]combo) - knownBoards["mkr1000"] = combo{match: "(WINC1500)*(3a0)", loader: "WINC1500/FirmwareUpdater.mkr1000.ino.bin"} - knownBoards["mkrwifi1010"] = combo{match: "NINA_W102.bin", loader: "NINA/FirmwareUpdater.mkrwifi1010.ino.bin"} - knownBoards["nano_33_iot"] = combo{match: "NINA_W102.bin", loader: "NINA/FirmwareUpdater.nano_33_iot.ino.bin"} - knownBoards["mkrvidor4000"] = combo{match: "NINA_W102.bin", loader: "NINA/FirmwareUpdater.mkrvidor4000.ino.bin"} - knownBoards["uno2018"] = combo{match: "NINA_W102-Uno_WiFi_Rev2.bin", loader: "NINA/FirmwareUpdater.unowifirev2.without_bl.ino.hex"} - knownBoards["mkrnb1500"] = combo{match: "SARA", loader: "SARA/SerialSARAPassthrough*"} - knownBoards["nanorp2040connect"] = combo{match: "NINA_W102-Nano_RP2040_Connect", loader: "NINA/FirmwareUpdater.nanorp2040connect.ino.elf"} - - listAll := false - - if knownBoards[strings.ToLower(name)].match == "" { - listAll = true - } - exePath := rootPath - if exePath == "" { - exePath, _ = os.Executable() - } - root := filepath.Dir(exePath) - root = filepath.Join(root, "firmwares") - loader := regexp.MustCompile(knownBoards[name].loader) - fw := regexp.MustCompile(knownBoards[name].match) - - err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if info.IsDir() { - return nil - } - unixPath := filepath.ToSlash(path) - parts := strings.Split(unixPath, "/") - fancyName := parts[len(parts)-3] + " " + parts[len(parts)-2] - f := firmware{ - Path: unixPath, - Name: fancyName, - IsLoader: loader.MatchString(unixPath) && !listAll, - } - folder := filepath.Dir(path) - if strings.HasPrefix(f.Name, "firmwares") && !f.IsLoader { - return nil - } - if listAll && !strings.HasPrefix(f.Name, "firmwares") { - files[folder] = append(files[folder], f) - } else if !listAll && (fw.MatchString(path) || f.IsLoader) { - files[folder] = append(files[folder], f) - } - return nil - }) - - // check files and add information to fw.Name in case of name clashing - for k := range files { - for i := range files[k] { - for j := range files[k] { - if files[k][i].Name == files[k][j].Name && i != j { - files[k][i].extra = filepath.Base(files[k][i].Path) - } - } - } - } - for k := range files { - for i := range files[k] { - if files[k][i].extra != "" { - files[k][i].Name = files[k][i].Name + " (" + files[k][i].extra + ")" - } - } - } - - if err != nil { - return files - } - return files -} diff --git a/utils/utils_test.go b/utils/utils_test.go deleted file mode 100644 index c4510725..00000000 --- a/utils/utils_test.go +++ /dev/null @@ -1,55 +0,0 @@ -/* - FirmwareUploader - Copyright (c) 2021 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -package utils - -import ( - "testing" - - "github.com/arduino/go-paths-helper" - "github.com/stretchr/testify/require" -) - -func TestGetCompatibleWith(t *testing.T) { - root, err := paths.Getwd() - require.NoError(t, err) - require.NoError(t, root.ToAbs()) - testrunner := func(board string) { - t.Run(board, func(t *testing.T) { - res := GetCompatibleWith(board, root.String()) - require.NotNil(t, res) - hasLoader := false - for _, e := range res { - for _, i := range e { - if i.IsLoader { - require.False(t, hasLoader, "loader must be unique") - hasLoader = true - require.NotEmpty(t, i.Name) - require.NotEmpty(t, i.Path) - } - } - } - require.True(t, hasLoader, "loader must be present") - }) - } - - testrunner("mkrwifi1010") - testrunner("mkr1000") - testrunner("nano_33_iot") -}