diff --git a/firmware/firmware.go b/firmware/firmware.go new file mode 100644 index 0000000..a68d985 --- /dev/null +++ b/firmware/firmware.go @@ -0,0 +1,77 @@ +package firmware + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "hash/crc32" + "io" + "io/ioutil" + "os" + "path" +) + +// FwExists check if file exists +func FwExists(path string) bool { + _, err := os.Stat(path) + return !errors.Is(err, os.ErrNotExist) +} + +func ChkHeader(fwfile string) bool { + fmt.Println("checking ", fwfile) + // SCS has two different file layouts, one for the "Dragons", the other for any older modem + var offset uint32 + if path.Ext(fwfile) == ".dr7" { + offset = 0 + } else { + offset = 4 + } + r, err := os.Open(fwfile) + if err != nil { + return false + } + defer r.Close() + + var header [2]byte + _, err = io.ReadFull(r, header[:]) + if err != nil { + return false + } + + if offset == 0 { + if header != [2]byte{0x50, 0x34} { + fmt.Println("ERROR: wrong firmware header") + //return false + } + } else { + if header != [2]byte{0x60, 0xea} { + fmt.Println("ERROR: wrong firmware header") + //return false + } + } + + r.Close() + firmware, err := ioutil.ReadFile(fwfile) + if err != nil { + fmt.Println("ERROR: ReadFile operation failed") + } + + var size uint32 + if offset == 0 { + size = binary.LittleEndian.Uint32(firmware[4:8]) // Dragons + } else { + size = uint32(binary.LittleEndian.Uint16(firmware[2:4])) // PTC-3 and Co + } + a := make([]byte, 4) + //binary.LittleEndian.PutUint32(a, crc32.ChecksumIEEE(firmware[4:size+4])) // PTC-3 + binary.LittleEndian.PutUint32(a, crc32.ChecksumIEEE(firmware[offset:offset+size])) + //if bytes.Equal(a, firmware[4+size:8+size]) { // PTC-3 + if bytes.Equal(a, firmware[offset+size:offset+size+4]) { + fmt.Println("CRC checksum ok!") + } else { + fmt.Println("CRC checksum NOT ok!") + return false + } + return true +} diff --git a/go.mod b/go.mod index 97dfee2..3c4a292 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,16 @@ module go-scsupdate go 1.17 -require github.com/albenik/go-serial v1.2.0 +require ( + github.com/akamensky/argparse v1.3.1 + github.com/albenik/go-serial v1.2.0 +) require ( github.com/creack/goselect v0.1.0 // indirect + github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 // indirect + github.com/sigurn/crc8 v0.0.0-20160107002456-e55481d6f45c // indirect + github.com/sigurn/utils v0.0.0-20190728110027-e1fefb11a144 // indirect go.uber.org/atomic v1.4.0 // indirect go.uber.org/multierr v1.1.0 // indirect golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect diff --git a/go.sum b/go.sum index 17a385b..4f6d2d8 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/akamensky/argparse v1.3.1 h1:kP6+OyvR0fuBH6UhbE6yh/nskrDEIQgEA1SUXDPjx4g= +github.com/akamensky/argparse v1.3.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= github.com/albenik/go-serial v1.2.0 h1:VhEIWqP5tbWtsWoCjeBHHQEf6qeXpsJXvZBP9px5F84= github.com/albenik/go-serial v1.2.0/go.mod h1:9NHUOwCBJER+lAaitTWLJda/GnYoP4Vga7KU3vn1lmM= github.com/creack/goselect v0.1.0 h1:4QiXIhcpSQF50XGaBsFzesjwX/1qOY5bOveQPmN9CXY= @@ -7,6 +9,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= +github.com/sigurn/crc8 v0.0.0-20160107002456-e55481d6f45c h1:hk0Jigjfq59yDMgd6bzi22Das5tyxU0CtOkh7a9io84= +github.com/sigurn/crc8 v0.0.0-20160107002456-e55481d6f45c/go.mod h1:cyrWuItcOVIGX6fBZ/G00z4ykprWM7hH58fSavNkjRg= +github.com/sigurn/utils v0.0.0-20190728110027-e1fefb11a144 h1:ccb8W1+mYuZvlpn/mJUMAbsFHTMCpcJBS78AsBQxNcY= +github.com/sigurn/utils v0.0.0-20190728110027-e1fefb11a144/go.mod h1:VRI4lXkrUH5Cygl6mbG1BRUfMMoT2o8BkrtBDUAm+GU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/main.go b/main.go index c46fc26..2168cb3 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,51 @@ package main +import ( + "fmt" + "github.com/akamensky/argparse" + "go-scsupdate/firmware" + "go-scsupdate/usb" + "os" +) + func main() { - lsusb() + parser := argparse.NewParser("go-scsupdate", "Update Firmware of SCS PACTOR modems") + serialDevice := parser.String("s", "serialDevice", &argparse.Options{Required: false, Help: "(optional) serial device the modem is attached to, e.g. /dev/ttyUSB0. If not set, go-scsupdate will search for SCS modems."}) + _ = parser.String("b", "baudrate", &argparse.Options{Required: false, Help: "(optional) sets the serial baudrate, e.g. 115200"}) + f := parser.String("f", "file", &argparse.Options{Required: false, Help: "(required) the file to flash, e.g. profi41r.pro"}) + err := parser.Parse(os.Args) + if err != nil { + fmt.Print(parser.Usage(err)) + os.Exit(1) + } + fmt.Println(*serialDevice) + var ports []usb.Scsid + if *serialDevice == "" { + if ports, err = usb.FindSCS(); err == nil { + fmt.Println(ports) + if len(ports) == 0 { + fmt.Println("Found no SCS modem.") + //os.Exit(1) + } + if len(ports) != 1 { + fmt.Println("Found more than one SCS modem. You need to choose one with the -s flag.\nfound: ") + for _, p := range ports { + fmt.Printf("Port: %30s : Name: %s\n", p.Port, p.Name) + } + } + } else { + fmt.Println("Error while seaching SCS modems: ", err) + } + } + + if !firmware.FwExists(*f) { + fmt.Printf("Error: firmware file %s does not exist.\n", *f) + os.Exit(1) + } + + if !firmware.ChkHeader(*f) { + os.Exit(1) + } else { + fmt.Println("all ok") + } } diff --git a/usb.go b/usb.go deleted file mode 100644 index 4532a3a..0000000 --- a/usb.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "fmt" - "log" - - "github.com/albenik/go-serial/enumerator" -) - -/* - USB Product IDs of the SCS devices: - 0xD010 SCS PTC-IIusb - 0xD011 SCS Tracker / DSP TNC - 0xD012 SCS P4dragon DR-7800 - 0xD013 SCS P4dragon DR-7400 - 0xD014 - not used - 0xD015 SCS PTC-IIIusb - 0xD016 - not used - 0xD017 - not used -*/ - -func lsusb() { - ports, err := enumerator.GetDetailedPortsList() - if err != nil { - log.Fatal(err) - } - if len(ports) == 0 { - fmt.Println("No serial ports found!") - return - } - for _, port := range ports { - fmt.Printf("Found port: %s\n", port.Name) - if port.IsUSB { - fmt.Printf(" USB ID %s:%s\n", port.VID, port.PID) - fmt.Printf(" USB serial %s\n", port.SerialNumber) - } - } - -} diff --git a/usb/usb.go b/usb/usb.go new file mode 100644 index 0000000..a0bda1c --- /dev/null +++ b/usb/usb.go @@ -0,0 +1,67 @@ +package usb + +import ( + "errors" + "fmt" + "github.com/albenik/go-serial/enumerator" + "log" +) + +/* + USB Product IDs of the SCS devices: + 0xD010 SCS PTC-IIusb + 0xD011 SCS Tracker / DSP TNC + 0xD012 SCS P4dragon DR-7800 + 0xD013 SCS P4dragon DR-7400 + 0xD014 - not used + 0xD015 SCS PTC-IIIusb + 0xD016 - not used + 0xD017 - not used +*/ + +type Scsid struct { + Port, id, Name string + Baudrate int +} + +var scsids map[string]string = map[string]string{ + "d010": "SCS PTC-IIusb", + "d011": "SCS Tracker / DSP TNC", + "d012": "SCS P4dragon DR-7800", + "d013": "SCS P4dragon DR-7400", + "d015": "SCS PTC-IIIusb"} + +var scsbaudrates map[string]int = map[string]int{ + "d010": 115200, + "d011": 38400, + "d012": 829400, + "d013": 829400, + "d015": 115200} + +func FindSCS() ([]Scsid, error) { + + foundids := []Scsid{} + ports, err := enumerator.GetDetailedPortsList() + if err != nil { + log.Fatal(err) + return nil, err + } + if len(ports) == 0 { + return nil, errors.New("No serial ports found") + } + + for _, port := range ports { + fmt.Printf("Found Port: %s\n", port.Name) + if port.IsUSB { + // fmt.Printf(" USB ID %s:%s\n", Port.VID, Port.PID) + // fmt.Printf(" USB serial %s\n", Port.SerialNumber) + if port.VID == "0403" { + if _, ok := scsids[port.PID]; ok { + foundids = append(foundids, Scsid{Port: port.Name, id: port.PID, Name: scsids[port.PID], Baudrate: scsbaudrates[port.PID]}) + } + } + } + } + return foundids, nil + +}