package main import ( "flag" "fmt" "os" ) func main() { var serial, option, value int var valueStr string var listOptions bool flag.BoolVar(&listOptions, "l", false, "list options and exit") flag.IntVar(&serial, "s", 0, "serial number of receiver") flag.IntVar(&option, "o", 0, "option number (use -l to list)") flag.StringVar(&valueStr, "v", "", "option value in hex (typically 00 = enable, FF = disable)") flag.Parse() if listOptions { for i, name := range optionNames { if name == "" { continue } fmt.Printf("Option %2d = %s\n", i, name) } os.Exit(0) } if serial == 0 || option == 0 || valueStr == "" { flag.PrintDefaults() os.Exit(1) } if option < 0 || option > 59 { fmt.Printf("Option number %d is out of range (allowed: 0-59)\n", option) os.Exit(1) } n, err := fmt.Sscanf(valueStr, "%2x", &value) if n == 0 || err != nil { fmt.Println("Unable to parse option value.") os.Exit(1) } e := encrypt(serial, option, value) fmt.Printf("Receiver Serial Number: %d\n", serial) if option < len(optionNames) { fmt.Printf("Option Number: %d (%s)\n", option, optionNames[option]) } else { fmt.Printf("Option Number: %d (out of range)\n", option) } fmt.Printf("Option Value: %02X\n", value) fmt.Printf("Code: %s\n", e) return } func encrypt(serialNumber, feature, value int) string { passwordStr := fmt.Sprintf("%05d%02d%02X", serialNumber, feature, value) password := []byte(passwordStr) fromASCII(password) sn := byte(serialNumber) & 0xF secret := []byte{7, 7, 5, 5, 9, 8, 1, 4, 2} encrypted := make([]byte, 10) for x := 0; x < 9; x++ { encrypted[8-x] = sn ^ secret[8-x] ^ reverseBits(password[x]) } encrypted[9] = calculateCheck(encrypted) toASCII(encrypted) return string(encrypted) } func decrypt(serialNumber int, passwordStr string) (int, int, int, error) { if len(passwordStr) != 10 { return 0, 0, 0, fmt.Errorf("password must be 10 characters long") } password := []byte(passwordStr) fromASCII(password) sum := calculateCheck(password) if password[9] != sum { return 0, 0, 0, fmt.Errorf("bad checksum") } sn := byte(serialNumber) & 0xF secret := []byte{7, 7, 5, 5, 9, 8, 1, 4, 2} decrypted := make([]byte, 9) for x := 0; x < 9; x++ { decrypted[8-x] = reverseBits(sn ^ secret[x] ^ password[x]) } toASCII(decrypted) var serial, option, value int _, err := fmt.Sscanf(string(decrypted), "%5d%2d%2X", &serial, &option, &value) if err != nil { return 0, 0, 0, err } return serial, option, value, nil } func calculateCheck(password []byte) byte { sum := 0 for i := 8; i >= 0; i-- { for j := 3; j >= 0; j-- { sum += int(password[i]) >> j & 1 } } return byte(sum & 0xF) } func reverseBits(in byte) byte { var out byte for i := 0; i < 4; i++ { if in&(1< '9' { s[i] -= '7' } else { s[i] -= '0' } } } func toASCII(s []byte) { for i, b := range s { if b > 9 { s[i] += '7' } else { s[i] += '0' } } } var optionNames = []string{ "POWER UP PORT SETTINGS", "POWER UP OUTPUT MSGS", "LOCATOR", "POWER UP NV ERASE", "RTCM ASCII", "CYCLE PRINT", "POSITION STATISTICS", "TAILBOUY", "PATHFINDER", "LANDSEIS", "RTCM NETWORK INPUT", "CARRIER PHASE", "HALF CYCLE L2", "MAXWELL L1 ONLY", "REMOTE DOWNLOAD", "DEMO EQUIPMENT ONLY", "", "RT SURVEY DATA", "LOCAL DATUMS", "RSIM INTERFACE", "DUAL FREQ / MULTI-BIT", "RS-232 PORTS", "MULTIPLE DATUMS", "EXTERNAL TIMEBASE", "EVENT MARKER", "1 PPS", "", "FIRMWARE UPDATE", "RTCM INPUTS", "RTCM OUTPUTS", "SYNC INTERVAL", "NMEA-0183", "SV SWAPPING", "KEYBOARD TYPE", "NAVIGATION", "LctrCrPh", "KINEMATIC", "CONFIGURED", "DATA LOGGING SIZE", "SURVEY TYPE", "RTK OTF CAPABILITIES", "IONO-FREE POSITIONING", "", "I/O DRIVERS", "", "CMR TYPE2 RATE", "RTK SPECIALS", "", "", "", "", "", "", "", "", "", "", "", "", "", }