Keelan Lightfoot 3 years ago
parent
commit
a768952eb1
7 changed files with 917 additions and 450 deletions
  1. 54
    2
      README.md
  2. 74
    36
      cmd/convertx/main.go
  3. 336
    209
      cmd/loader/main.go
  4. 227
    141
      dotx/dotx.go
  5. 222
    42
      monitor/monitor.go
  6. 0
    16
      monitor/protocol.go
  7. 4
    4
      monitor/serial.go

+ 54
- 2
README.md View File

@@ -1,3 +1,55 @@
1
-# trimtools
1
+# TrimTools
2
+TrimTools is an open source set of tools for managing the firmware on plastic box Trimble 4000 series GPS receivers.
2 3
 
3
-Tools to work with the Trimble 4000SE/SSE/SSi receivers' firmware upgrade mechanism.
4
+## Features
5
+* Fully Supported Receivers (Firmware read/write)
6
+	* 4000SE (Maxwell)
7
+	* 4000SSE
8
+	* 4000Si
9
+	* 4000SSi
10
+	* 4000RS
11
+	* 4000DS 
12
+* Partially Supported Receivers (interactive ROM Monitor only)
13
+	* 4000SE (Gauss)
14
+	* 4000RL2
15
+	* 4000DL2
16
+	* 4400
17
+	* 7400MSi
18
+* Cross Platform
19
+* Fast
20
+* Interactive ROM monitor
21
+
22
+
23
+## Command Line Tools
24
+`cmd/loader` - replacement for Trimble's loader.exe
25
+
26
+	Usage of loader:
27
+	  -b int
28
+	    	baud rate (default 38400)
29
+	  -d string
30
+	    	serial port device (default "/dev/tty.usbserial-AB0JS0VU")
31
+	  -dummy
32
+	    	dummy mode
33
+	  -f string
34
+	    	write firmware from file to receiver
35
+	  -m	start interactive monitor
36
+	  -p string
37
+	    	parity (none, even, lsodd) (default "none")
38
+	  -s string
39
+	    	save firmware from receiver to file
40
+	  -v	show version and exit
41
+	  -x	enable debug messages
42
+
43
+`cmd/convertx` - tool for converting to and from HP 64000 .X images as used by the loader tool.
44
+	
45
+	Usage convertx:
46
+	  -b string
47
+	    	binary image output filename
48
+	  -i	print image metadata
49
+	  -wnro
50
+	    	attempt to patch WNRO bug
51
+	  -x string
52
+	    	.X output filename
53
+
54
+## Known Issues
55
+* Firmware upload/download for the Gauss 4000SE and the 4400 is either missing or not tested.

+ 74
- 36
cmd/convertx/main.go View File

@@ -36,25 +36,58 @@ import (
36 36
 	"fmt"
37 37
 	"log"
38 38
 	"os"
39
+	"strings"
39 40
 )
40 41
 
42
+const (
43
+	memOpBlockSize = 244
44
+)
45
+
46
+
47
+func guessFileType(fn string) string {
48
+	switch filepath.Ext(fn) {
49
+	case ".X":
50
+		return "x"
51
+	case ".bin":
52
+		return "bin"
53
+	} 
54
+	return ""	
55
+}
56
+
41 57
 func main() {
42 58
 
43
-	var binOut string
44
-	var xOut string
59
+	var inFile,outFile,  inFileFormat, outFileFormat string
45 60
 	var printInfo bool
46
-	var patchWNRO bool
47 61
 
48
-	flag.StringVar(&binOut, "b", "", "binary image output filename")
49
-	flag.StringVar(&xOut, "x", "", ".X output filename")
50
-	flag.BoolVar(&printInfo, "i", false, "print image metadata")
51
-	flag.BoolVar(&patchWNRO, "wnro", false, "attempt to patch WNRO bug")
62
+	flag.StringVar(&inFile, "in", "", "input file")
63
+	flag.StringVar(&outFile, "out", "", "output file")
64
+	flag.StringVar(&inFileFormat, "infmt", "", "input file format (x or bin)")
65
+	flag.StringVar(&outFileFormat, "outfmt", "", "input file format (x or bin)")
66
+	flag.BoolVar(&printInfo, "i", false, "Print image metadata")
67
+
68
+	if inFileFormat == "" {
69
+		if inFileFormat = guessFileType(inFile, "x"); inFileFormat == "" {
70
+			fmt.Println("Input file format not specified and extension unrecognized. Assuming HP64000.")
71
+			inFileFormat = "x"
72
+		}
73
+	}
74
+	
75
+	if outFileFormat == "" {
76
+		if outFileFormat = guessFileType(inFile, "x"); outFileFormat == "" {
77
+			fmt.Println("Output file format not specified and extension unrecognized.  Assuming binary.")
78
+			outFileFormat = "bin"
79
+		}
80
+	}
52 81
 
53 82
 	flag.Parse()
54 83
 
55
-	inFile := flag.Arg(0)
56 84
 	if inFile == "" {
57
-		fmt.Printf("Usage:\n%s [flags] <.X file>\n", os.Args[0])
85
+		fmt.Printf("Input file is required.")
86
+		os.Exit(1)
87
+	}
88
+	
89
+	if outFile == "" {
90
+		fmt.Printf("Input file is required.")
58 91
 		os.Exit(1)
59 92
 	}
60 93
 
@@ -70,37 +103,42 @@ func main() {
70 103
 		log.Fatal(err)
71 104
 	}
72 105
 
106
+	dotX.Blocks[2].ToRecords(memOpBlockSize)
107
+
108
+	mem := dotX.ToMemory()
109
+
73 110
 	if printInfo {
74 111
 		dotX.PrintInfo()
112
+		mem.PrintInfo()
75 113
 	}
76 114
 
77
-	if patchWNRO {
78
-
79
-		verMaj, verMin := dotX.FirmwareVersion()
80
-		ver := float64(verMaj) + float64(verMin)/100
81
-
82
-		if ver < 7.19 {
83
-			fmt.Printf("Warning: WRNO auto-patching has only been tested for firmware versions >= 7.19, use on other versions may produce unpredictable results.")
84
-		}
85
-		// Because the memory slice backs both blocks and records, the data can be modified
86
-		// in any of the three records types simultaneously.
87
-		// This will apply the WRNO patch to 732.X and 719.X
88
-		// 1. find the matching instructions (addi.w  #$400,d2)
89
-		matches := dotX.FindSequence([]uint8{0x06, 0x42, 0x04, 0x00})
90
-		if len(matches) == 0 {
91
-			fmt.Printf("Could not find ADDI.W  #$400,D2 instruction. Aborting WRNO patch attempt")
92
-			os.Exit(1)
93
-		}
94
-		// 2. change partial-rollover check cmpi to 0
95
-		dotX.Memory[matches[0]-4] = 0
96
-		dotX.Memory[matches[0]-3] = 0
97
-
98
-		// 2. change $400 to $800
99
-		dotX.Memory[matches[0]+2] = 8
100
-
101
-		// 3. recalculate the block checksums
102
-		dotX.UpdateChecksums()
103
-	}
115
+	// 	if patchWNRO {
116
+	//
117
+	// 		verMaj, verMin := mem.FirmwareVersion()
118
+	// 		ver := float64(verMaj) + float64(verMin)/100
119
+	//
120
+	// 		if ver < 7.19 {
121
+	// 			fmt.Printf("Warning: WRNO auto-patching has only been tested for firmware versions >= 7.19, use on other versions may produce unpredictable results.")
122
+	// 		}
123
+	// 		// Because the memory slice backs both blocks and records, the data can be modified
124
+	// 		// in any of the three records types simultaneously.
125
+	// 		// This will apply the WRNO patch to 732.X and 719.X
126
+	// 		// 1. find the matching instructions (addi.w  #$400,d2)
127
+	// 		matches := mem.FindSequence([]uint8{0x06, 0x42, 0x04, 0x00})
128
+	// 		if len(matches) == 0 {
129
+	// 			fmt.Printf("Could not find ADDI.W  #$400,D2 instruction. Aborting WRNO patch attempt")
130
+	// 			os.Exit(1)
131
+	// 		}
132
+	// 		// 2. change partial-rollover check cmpi to 0
133
+	// 		mem.Memory[matches[0]-4] = 0
134
+	// 		mem.Memory[matches[0]-3] = 0
135
+	//
136
+	// 		// 2. change $400 to $800
137
+	// 		mem.Memory[matches[0]+2] = 8
138
+	//
139
+	// 		// 3. recalculate the block checksums
140
+	// 		mem.UpdateChecksums()
141
+	// 	}
104 142
 	//
105 143
 	// 	// Example 2: extracting and saving DSP firmware
106 144
 	// 	if !strings.HasSuffix(os.Args[1], "732.X") {

+ 336
- 209
cmd/loader/main.go View File

@@ -1,15 +1,15 @@
1 1
 package main
2 2
 
3 3
 import (
4
-	"bufio"
5 4
 	"code.beefchicken.com/trimtools/dotx"
6 5
 	"code.beefchicken.com/trimtools/monitor"
6
+	"github.com/chzyer/readline"
7
+
7 8
 	"encoding/binary"
8 9
 	"flag"
9 10
 	"fmt"
10
-	"io"
11
-	"io/ioutil"
12 11
 	"log"
12
+	"math"
13 13
 	"os"
14 14
 	"strconv"
15 15
 	"strings"
@@ -17,42 +17,30 @@ import (
17 17
 
18 18
 func main() {
19 19
 
20
-	var baud, dataBits, stopBits int
21
-	var debug, startMonitor, dummy bool
20
+	var baud int
21
+	var debug, interactiveMonitor, showVersion, dummy bool
22 22
 	var device, parity string
23
+	var inFile, outFile string
23 24
 
24
-	flag.IntVar(&baud, "baud", 38400, "baud rate")
25
-	flag.IntVar(&dataBits, "databits", 8, "data bits")
26
-	flag.IntVar(&stopBits, "stopbits", 1, "stop bits")
27
-	flag.BoolVar(&debug, "debug", false, "enable debug messages")
28
-	flag.BoolVar(&startMonitor, "M", false, "start monitor")
29
-	flag.BoolVar(&dummy, "dummy", false, "dummy mode")
30
-	flag.StringVar(&device, "device", "/dev/tty.usbserial-AB0JS0VU", "serial port device")
31
-	flag.StringVar(&parity, "parity", "n", "parity (n,e,o)")
25
+	flag.IntVar(&baud, "b", 38400, "baud rate")
26
+	flag.StringVar(&parity, "p", "none", "parity (none, even, lsodd)")
32 27
 
28
+	flag.BoolVar(&debug, "x", false, "enable debug messages")
29
+	flag.BoolVar(&interactiveMonitor, "m", false, "start interactive monitor")
30
+	flag.BoolVar(&showVersion, "v", false, "show version and exit")
31
+	flag.BoolVar(&dummy, "dummy", false, "dummy mode")
32
+	flag.StringVar(&device, "d", "/dev/tty.usbserial-AB0JS0VU", "serial port device")
33
+	flag.StringVar(&outFile, "s", "", "save firmware from receiver to file")
34
+	flag.StringVar(&inFile, "f", "", "write firmware from file to receiver")
33 35
 	flag.Parse()
34 36
 
35
-	inFile := flag.Arg(0)
36
-	// if inFile == "" {
37
-	// 		fmt.Printf("Usage:\n%s [flags] <.X file>\n", os.Args[0])
38
-	// 		os.Exit(1)
39
-	// 	}
37
+	if showVersion {
38
+		fmt.Println("loader(.exe) Trimble 4000 Firmware Loader")
39
+		fmt.Println("Written by Keelan Lightfoot - http://beefchicken.com")
40
+		return
41
+	}
40 42
 
41 43
 	var fw *dotx.DotXFile
42
-	if inFile != "" {
43
-		// load file
44
-		f, err := os.Open(inFile)
45
-		if err != nil {
46
-			log.Fatal(err)
47
-		}
48
-		defer f.Close()
49
-		fw, err = dotx.ReadDotX(f)
50
-		if err != nil {
51
-			log.Fatal(err)
52
-		}
53
-		fmt.Println(fw.FirmwareDate())
54
-
55
-	}
56 44
 
57 45
 	var mon *monitor.Monitor
58 46
 	var err error
@@ -60,9 +48,12 @@ func main() {
60 48
 	if dummy {
61 49
 		mon = &monitor.Monitor{
62 50
 			Debug: debug,
51
+			Dummy: dummy,
63 52
 		}
53
+		fmt.Println("Monitor dummy mode active.")
54
+
64 55
 	} else {
65
-		mon, err = monitor.Connect(device, baud, dataBits, stopBits, parity, debug)
56
+		mon, err = monitor.Connect(device, baud, 8, 1, parity, debug)
66 57
 		if err != nil {
67 58
 			log.Fatal(err)
68 59
 		}
@@ -74,147 +65,194 @@ func main() {
74 65
 		log.Fatal(err)
75 66
 	}
76 67
 
77
-	if fw != nil {
78
-		mon.WriteFirmware(fw)
68
+	if interactiveMonitor {
69
+		runMonitor(mon)
70
+		return
79 71
 	}
80 72
 
81
-	if startMonitor {
82
-		reader := bufio.NewReader(os.Stdin)
83
-		running := true
84
-		for running {
85
-			fmt.Print("\nenter command: ")
86
-			b, err := reader.ReadBytes('\n')
87
-			if err == io.EOF {
88
-				fmt.Println("bye")
89
-				break
90
-			}
91
-			cmd := strings.Fields(string(b))
92
-			if len(cmd) == 0 {
93
-				continue
94
-			}
95
-			switch strings.ToLower(cmd[0]) {
96
-			case "?":
97
-				fmt.Println("Manual help mode:")
98
-				fmt.Println("  Q or X       : Exit program.")
99
-				fmt.Println("  R            : Reset target and exit program.")
100
-				fmt.Println("  U addr count : hex/ascii dump of count bytes starting at addr")
101
-				fmt.Println("                 (UD command works with doubles)")
102
-				fmt.Println("  D addr count data... : download data bytes to target address")
103
-				fmt.Println("                 (DD command works with doubles)")
104
-				fmt.Println("  F addr count char : fill target memory block")
105
-				fmt.Println("  V            : Display firmware versions and code segment ranges.")
106
-				fmt.Println("  O            : Display options data.")
107
-				fmt.Println(" ")
108
-				fmt.Println("  Addresses and data default to hex.  Counts default to decimal.")
109
-				fmt.Println("  $xxxx or !dddd force hex or decimal.")
110
-				fmt.Println("  CoMmAnDs ArE CaSe InSeNsITiVe.")
111
-			case "q":
112
-				fallthrough
113
-			case "x":
114
-				running = false
115
-			case "r":
116
-				mon.Stop()
117
-				running = false
118
-			case "u":
119
-				handleUCommand(mon, cmd)
120
-			case "ul":
121
-				handleULCommand(mon, cmd)
122
-			case "uf": // dump to file
123
-				handleUFCommand(mon, cmd)
124
-			case "ud":
125
-				fmt.Println("unimplemented")
126
-			case "d":
127
-				handleDCommand(mon, cmd)
128
-			case "dd":
129
-				fmt.Println("unimplemented")
130
-			case "f":
131
-
132
-				b2, _ := mon.ReadMemory(0x80600+62, 10)
133
-				fmt.Printf("% 02x\n", b2)
134
-				fmt.Printf("%s\n", string(b2))
135
-
136
-				b3, _ := mon.ReadMemory(0x80600+72, 10)
137
-				fmt.Printf("% 02x\n", b3)
138
-				fmt.Printf("%s\n", string(b3))
139
-
140
-				fmt.Println("unimplemented")
141
-			case "v":
142
-				info, err := mon.GetReceiverInfo()
143
-				if err != nil {
144
-					log.Fatal(err)
145
-				}
146
-				info.PrintVersions()
147
-			case "o":
148
-				info, err := mon.GetReceiverInfo()
149
-				if err != nil {
150
-					log.Fatal(err)
151
-				}
152
-				info.PrintOptions()
153
-			}
73
+	if outFile != "" {
74
+		fmt.Printf("Saving .X format firmware to '%s'...\n", outFile)
75
+		fw, err = mon.CaptureReceiverFirmware()
76
+		if err != nil {
77
+			log.Fatal(err)
78
+		}
79
+		f, err := os.Create(outFile)
80
+		if err != nil {
81
+			log.Fatal(err)
82
+		}
83
+		err = fw.WriteDotX(f)
84
+		if err != nil {
85
+			log.Fatal(err)
86
+		}
87
+		f.Close()
88
+	}
154 89
 
90
+	if inFile != "" {
91
+		fmt.Printf("Loading .X format firmware from '%s'...\n", inFile)
92
+		f, err := os.Open(inFile)
93
+		if err != nil {
94
+			log.Fatal(err)
95
+		}
96
+		fw, err = dotx.ReadDotX(f)
97
+		if err != nil {
98
+			log.Fatal(err)
99
+		}
100
+		f.Close()
101
+		err = mon.ProgramReceiver(fw)
102
+		if err != nil {
103
+			log.Fatal(err)
155 104
 		}
156 105
 	}
157
-	//
158
-	// 	b, err := mon.ReadMemory(0x712804, 4)
159
-	// 	if err != nil {
160
-	// 		log.Fatal(err)
161
-	// 	}
162
-	// 	fmt.Printf("% 02x\n", b)
163 106
 
164 107
 }
165 108
 
166
-func handleDCommand(mon *monitor.Monitor, cmd []string) {
167
-	if len(cmd) < 3 {
168
-		fmt.Println("d address d1 d2 d3 dn...")
169
-		return
109
+func runMonitor(mon *monitor.Monitor) {
110
+	commands := map[string]func(*monitor.Monitor, []string) bool{
111
+		"?":  handleHelpCommand,
112
+		"q":  handleQuitCommand,
113
+		"x":  handleQuitCommand,
114
+		"r":  handleResetCommand,
115
+		"u":  handleUCommand,
116
+		"uw": handleUWCommand,
117
+		"ul": handleULCommand,
118
+		"ud": handleUDCommand,
119
+		"d":  handleDCommand,
120
+		"dw": handleDWCommand,
121
+		"dl": handleDLCommand,
122
+		"dd": handleDDCommand,
123
+		"f":  handleFCommand,
124
+		"v":  handleVersionCommand,
125
+		"o":  handleOptionsCommand,
126
+		"j":  handleJCommand,
170 127
 	}
171
-	addr, ok := parseNum(cmd[1], 16)
172
-	if !ok {
173
-		fmt.Println("invalid address")
174
-		return
128
+
129
+	rl, err := readline.New("enter command: ")
130
+	if err != nil {
131
+		panic(err)
175 132
 	}
176
-	v := make([]byte, 0)
177
-	for _, s := range cmd[2:] {
178
-		b, ok := parseNum(s, 16)
179
-		if !ok {
180
-			fmt.Printf("invalid byte: %s\n", s)
181
-			return
133
+	defer rl.Close()
134
+
135
+	for {
136
+		fmt.Println("")
137
+		s, err := rl.Readline()
138
+		fmt.Println("")
139
+
140
+		if err != nil {
141
+			fmt.Println("bye")
142
+			break
143
+		}
144
+		cmd := strings.Fields(s)
145
+		if len(cmd) == 0 {
146
+			continue
147
+		}
148
+		verb := strings.ToLower(cmd[0])
149
+
150
+		if f := commands[verb]; f != nil {
151
+			if f(mon, cmd) {
152
+				break
153
+			}
154
+		} else {
155
+			fmt.Printf("unrecognized command: %s\n", verb)
182 156
 		}
183
-		v = append(v, byte(b))
184
-	}
185
-	err := mon.WriteMemory(addr, v)
186
-	if err != nil {
187
-		fmt.Println("failed: %v\n", err)
188 157
 	}
158
+
159
+}
160
+
161
+func handleQuitCommand(mon *monitor.Monitor, cmd []string) bool {
162
+	return true
163
+}
164
+
165
+func handleHelpCommand(mon *monitor.Monitor, cmd []string) bool {
166
+	fmt.Print(
167
+		"Manual help mode:\n",
168
+		"  Q or X       : Exit program.\n",
169
+		"  R            : Reset target and exit program.\n",
170
+		"  U addr count : hex/ascii dump of count bytes starting at addr\n",
171
+		"                 (UD command works with doubles)\n",
172
+		"                 (UW command works with words)\n",
173
+		"                 (UL command works with longs)\n",
174
+		"  D addr count data... : download data bytes to target address\n",
175
+		"                 (DD command works with doubles)\n",
176
+		"                 (DW command works with words)\n",
177
+		"                 (DL command works with longs)\n",
178
+		"  F addr count byte : fill target memory block\n",
179
+		"  V            : Display firmware versions and code segment ranges.\n",
180
+		"  O            : Display options data.\n",
181
+		"  J addr       : Jump to address.\n",
182
+		" \n",
183
+		"  Addresses and data default to hex.  Counts default to decimal.\n",
184
+		"  $xxxx or !dddd force hex or decimal.\n",
185
+		"  CoMmAnDs ArE CaSe InSeNsITiVe.\n",
186
+	)
187
+
188
+	return false
189 189
 }
190 190
 
191
-func handleUCommand(mon *monitor.Monitor, cmd []string) {
191
+func handleResetCommand(mon *monitor.Monitor, cmd []string) bool {
192
+	mon.Stop()
193
+	return false
194
+}
195
+
196
+func handleUCommand(mon *monitor.Monitor, cmd []string) bool {
197
+	return ulCmd(mon, cmd, 1)
198
+}
199
+
200
+func handleUWCommand(mon *monitor.Monitor, cmd []string) bool {
201
+	return ulCmd(mon, cmd, 2)
202
+}
203
+
204
+func handleULCommand(mon *monitor.Monitor, cmd []string) bool {
205
+	return ulCmd(mon, cmd, 4)
206
+}
207
+
208
+func ulCmd(mon *monitor.Monitor, cmd []string, chunk int) bool {
192 209
 	if len(cmd) < 3 {
193
-		fmt.Println("u address count")
194
-		return
210
+		fmt.Printf("%s address count\n", cmd[0])
211
+		return false
195 212
 	}
196 213
 	addr, ok := parseNum(cmd[1], 16)
197 214
 	if !ok {
198
-		fmt.Println("invalid address")
199
-		return
215
+		fmt.Printf("invalid address: '%s'\n", cmd[1])
216
+		return false
200 217
 	}
201 218
 	count, ok := parseNum(cmd[2], 10)
202 219
 	if !ok {
203
-		fmt.Println("invalid count")
204
-		return
220
+		fmt.Printf("invalid count: '%s'\n", cmd[2])
221
+		return false
205 222
 	}
206
-	b, err := mon.ReadMemory(addr, int(count))
223
+
224
+	b, err := mon.ReadMemory(addr, int(count)*chunk)
207 225
 	if err != nil {
208 226
 		log.Fatal(err)
209 227
 	}
210
-	fmt.Printf("upload data from target memory\n")
211
-	fmt.Printf("start address: %08x number of bytes: %d\n", addr, count)
212
-	for i := 0; i < int(count); i += 16 {
228
+
229
+	var dataType string
230
+
231
+	if chunk == 1 {
232
+		dataType = "byte"
233
+	} else if chunk == 2 {
234
+		dataType = "word"
235
+	} else if chunk == 4 {
236
+		dataType = "long"
237
+	}
238
+	fmt.Printf("upload %s data from target memory\n", dataType)
239
+	fmt.Printf("start address: %08x number of %ss: %d\n", addr, dataType, count)
240
+	for i := 0; i < int(count)*chunk; i += 16 {
213 241
 		e := i + 16
214 242
 		if e > len(b) {
215 243
 			e = len(b)
216 244
 		}
217
-		line := fmt.Sprintf("%08x  % 02x", addr+uint32(i), b[i:e])
245
+		line := fmt.Sprintf("%08x ", addr+uint32(i))
246
+		for q := 0; q < (e - i); q += chunk {
247
+			if chunk == 1 {
248
+				line = fmt.Sprintf("%s %02x", line, b[i+q])
249
+			} else if chunk == 2 {
250
+				line = fmt.Sprintf("%s %04x", line, binary.BigEndian.Uint16(b[i+q:]))
251
+			} else if chunk == 4 {
252
+				line = fmt.Sprintf("%s %08x", line, binary.BigEndian.Uint32(b[i+q:]))
253
+			}
254
+		}
255
+
218 256
 		fmt.Printf("% -60s", line)
219 257
 		for j := i; j < e; j++ {
220 258
 			if b[j] >= 32 && b[j] <= 126 {
@@ -225,79 +263,190 @@ func handleUCommand(mon *monitor.Monitor, cmd []string) {
225 263
 		}
226 264
 		fmt.Printf("\n")
227 265
 	}
266
+	return false
228 267
 }
229 268
 
230
-func handleULCommand(mon *monitor.Monitor, cmd []string) {
269
+func handleUDCommand(mon *monitor.Monitor, cmd []string) bool {
231 270
 	if len(cmd) < 3 {
232 271
 		fmt.Println("u address count")
233
-		return
272
+		return false
234 273
 	}
235 274
 	addr, ok := parseNum(cmd[1], 16)
236 275
 	if !ok {
237
-		fmt.Println("invalid address")
238
-		return
276
+		fmt.Printf("invalid address: '%s'\n", cmd[1])
277
+		return false
239 278
 	}
240 279
 	count, ok := parseNum(cmd[2], 10)
241 280
 	if !ok {
242
-		fmt.Println("invalid count")
243
-		return
281
+		fmt.Printf("invalid count: '%s'\n", cmd[2])
282
+		return false
244 283
 	}
245
-	count *= 4
246
-	b, err := mon.ReadMemory(addr, int(count))
284
+	b, err := mon.ReadMemory(addr, int(count)*8)
247 285
 	if err != nil {
248
-		log.Fatal(err)
286
+		fmt.Printf("read failed: %v\n", err)
249 287
 	}
250
-	fmt.Printf("upload long data from target memory\n")
251
-	fmt.Printf("start address: %08x number of bytes: %d\n", addr, count)
252
-	for i := 0; i < int(count); i += 16 {
253
-		e := i + 16
254
-		if e > len(b) {
255
-			e = len(b)
288
+	fmt.Printf("upload doubles from target memory\n")
289
+	fmt.Printf("start address: %08x number of doubles: %d\n", addr, count)
290
+
291
+	for i := 0; i < int(count); i++ {
292
+		fmt.Printf("%08x  %23.13e\n", int(addr)+i*8, math.Float64frombits(binary.BigEndian.Uint64(b[i*8:])))
293
+	}
294
+	return false
295
+}
296
+
297
+func handleDCommand(mon *monitor.Monitor, cmd []string) bool {
298
+	return dlCmd(mon, cmd, 1)
299
+}
300
+
301
+func handleDWCommand(mon *monitor.Monitor, cmd []string) bool {
302
+	return dlCmd(mon, cmd, 2)
303
+}
304
+
305
+func handleDLCommand(mon *monitor.Monitor, cmd []string) bool {
306
+	return dlCmd(mon, cmd, 4)
307
+}
308
+
309
+func dlCmd(mon *monitor.Monitor, cmd []string, chunk int) bool {
310
+	if len(cmd) < 3 {
311
+		fmt.Printf("%s address v1 v2 v3 vn...\n", cmd[0])
312
+		return false
313
+	}
314
+	addr, ok := parseNum(cmd[1], 16)
315
+	if !ok {
316
+		fmt.Printf("invalid address: '%s'\n", cmd[1])
317
+		return false
318
+	}
319
+
320
+	var dataType string
321
+
322
+	if chunk == 1 {
323
+		dataType = "byte"
324
+	} else if chunk == 2 {
325
+		dataType = "word"
326
+	} else if chunk == 4 {
327
+		dataType = "long"
328
+	}
329
+	fmt.Printf("download %s data to target memory\n", dataType)
330
+	fmt.Printf("start address: %08x number of %ss: %d\n", addr, dataType, len(cmd[2:]))
331
+
332
+	v := make([]byte, len(cmd[2:])*chunk)
333
+	i := 0
334
+	for _, s := range cmd[2:] {
335
+		l, ok := parseNum(s, 16)
336
+		if !ok {
337
+			fmt.Printf("invalid value: %s\n", s)
338
+			return false
256 339
 		}
257
-		line := fmt.Sprintf("%08x    ", addr+uint32(i))
258
-		for q := 0; q < (e - i); q += 4 {
259
-			line = fmt.Sprintf("%s %08x", line, binary.BigEndian.Uint32(b[i+q:]))
340
+
341
+		if chunk == 1 {
342
+			v[i] = byte(l)
343
+		} else if chunk == 2 {
344
+			binary.BigEndian.PutUint16(v[i:], uint16(l))
345
+		} else if chunk == 4 {
346
+			binary.BigEndian.PutUint32(v[i:], l)
260 347
 		}
261 348
 
262
-		fmt.Printf("% -60s", line)
263
-		for j := i; j < e; j++ {
264
-			if b[j] >= 32 && b[j] <= 126 {
265
-				fmt.Print(string(b[j]))
266
-			} else {
267
-				fmt.Print(".")
268
-			}
349
+		i += chunk
350
+	}
351
+	err := mon.WriteMemory(addr, v)
352
+	if err != nil {
353
+		fmt.Println("failed: %v\n", err)
354
+	}
355
+	return false
356
+}
357
+
358
+func handleDDCommand(mon *monitor.Monitor, cmd []string) bool {
359
+	if len(cmd) < 3 {
360
+		fmt.Println("dd address d1 d2 d3 dn...")
361
+		return false
362
+	}
363
+	addr, ok := parseNum(cmd[1], 16)
364
+	if !ok {
365
+		fmt.Printf("invalid address: '%s'\n", cmd[1])
366
+		return false
367
+	}
368
+	v := make([]byte, len(cmd[2:])*8)
369
+	i := 0
370
+	for _, s := range cmd[2:] {
371
+		f, err := strconv.ParseFloat(s, 64)
372
+		if err != nil {
373
+			fmt.Printf("invalid float: %s\n", s)
374
+			return false
269 375
 		}
270
-		fmt.Printf("\n")
376
+
377
+		binary.BigEndian.PutUint64(v[i:], math.Float64bits(f))
378
+		i += 8
379
+	}
380
+	err := mon.WriteMemory(addr, v)
381
+	if err != nil {
382
+		fmt.Println("failed: %v\n", err)
271 383
 	}
384
+	return false
272 385
 }
273 386
 
274
-func handleUFCommand(mon *monitor.Monitor, cmd []string) {
387
+func handleFCommand(mon *monitor.Monitor, cmd []string) bool {
275 388
 	if len(cmd) < 4 {
276
-		fmt.Println("u file address count")
277
-		return
389
+		fmt.Println("f address count byte")
390
+		return false
278 391
 	}
279
-	fileName := cmd[1]
280
-
281
-	addr, ok := parseNum(cmd[2], 16)
392
+	addr, ok := parseNum(cmd[1], 16)
282 393
 	if !ok {
283
-		fmt.Println("invalid address")
284
-		return
394
+		fmt.Printf("invalid address: '%s'\n", cmd[1])
395
+		return false
285 396
 	}
286
-	count, ok := parseNum(cmd[3], 10)
397
+	count, ok := parseNum(cmd[2], 10)
287 398
 	if !ok {
288
-		fmt.Println("invalid count")
289
-		return
399
+		fmt.Printf("invalid count: '%s'\n", cmd[2])
400
+		return false
401
+	}
402
+	b, ok := parseNum(cmd[3], 16)
403
+	if !ok {
404
+		fmt.Printf("invalid byte: '%s'\n", cmd[3])
405
+		return false
406
+	}
407
+	v := make([]byte, count)
408
+	for i := 0; i < len(v); i++ {
409
+		v[i] = byte(b)
290 410
 	}
291
-	b, err := mon.ReadMemory(addr, int(count))
411
+	err := mon.WriteMemory(addr, v)
292 412
 	if err != nil {
293
-		fmt.Printf("read failed: %v\n", err)
413
+		fmt.Println("failed: %v\n", err)
294 414
 	}
295
-	err = ioutil.WriteFile(fileName, b, 0644)
415
+	return false
416
+}
417
+
418
+func handleVersionCommand(mon *monitor.Monitor, cmd []string) bool {
419
+	info, err := mon.GetReceiverInfo()
296 420
 	if err != nil {
297
-		fmt.Printf("write to file failed: %v\n", err)
421
+		fmt.Printf("GetReceiverInfo failed: %v\n", err)
422
+		return false
298 423
 	}
299
-	fmt.Printf("wrote %d bytes to %s\n", len(b), fileName)
424
+	info.PrintVersions()
425
+	return false
426
+}
427
+
428
+func handleOptionsCommand(mon *monitor.Monitor, cmd []string) bool {
429
+	info, err := mon.GetReceiverInfo()
430
+	if err != nil {
431
+		fmt.Printf("GetReceiverInfo failed: %v\n", err)
432
+		return false
433
+	}
434
+	info.PrintOptions()
435
+	return false
436
+}
300 437
 
438
+func handleJCommand(mon *monitor.Monitor, cmd []string) bool {
439
+	if len(cmd) < 2 {
440
+		fmt.Println("j address")
441
+		return false
442
+	}
443
+	addr, ok := parseNum(cmd[1], 16)
444
+	if !ok {
445
+		fmt.Printf("invalid address: '%s'\n", cmd[1])
446
+		return false
447
+	}
448
+	mon.Jump(addr)
449
+	return false
301 450
 }
302 451
 
303 452
 func parseNum(s string, base int) (uint32, bool) {
@@ -315,25 +464,3 @@ func parseNum(s string, base int) (uint32, bool) {
315 464
 	}
316 465
 	return uint32(v), true
317 466
 }
318
-
319
-// enter command: ud 0 100
320
-// upload doubles from target memory
321
-// start address: number of doubles: 00000000     1.1125369292673e-308
322
-// 00000008     6.8043917048940e-310
323
-// 00000010     6.8086356964769e-310
324
-// 00000018     6.8128796880598e-310
325
-// 00000020     6.8171236796428e-310
326
-// 00000028     6.8213676712257e-310
327
-// 00000030     0.0000000000000e+000
328
-// 00000038     0.0000000000000e+000
329
-// 00000040     0.0000000000000e+000
330
-// 00000048     0.0000000000000e+000
331
-// 00000050     0.0000000000000e+000
332
-// 00000058     0.0000000000000e+000
333
-// 00000060     6.8298556544112e-310
334
-// 00000068     7.5076211100665e-310
335
-// 00000070     8.9157775173783e-310
336
-// 00000078     6.8298556544421e-310
337
-// 00000080     6.8302800535493e-310
338
-// 00000088     7.0492700191769e-310
339
-// 00000090     6.8302800537515e-310

+ 227
- 141
dotx/dotx.go View File

@@ -21,7 +21,7 @@ main() function to write a short program to accomplish the task at hand. If I
21 21
 like it, it gets spun off into its own function to save it, which then frees up
22 22
 my main() for the next project.
23 23
 
24
-This  program is in the public domain.
24
+This program is in the public domain.
25 25
 
26 26
 This program was written by Keelan Lightfoot
27 27
 http://www.beefchicken.com/
@@ -44,16 +44,19 @@ import (
44 44
 type DotXFile struct {
45 45
 	ProductionFlag  uint8
46 46
 	HeaderText      string
47
-	ProcessorRecord *ProcessorRecord
48
-	DataRecords     []*DataRecord
49
-	Memory          []uint8
50
-	Blocks          []Block
51
-
52
-	minAddr    uint32
53
-	maxAddr    uint32
54
-	memSize    uint32
55
-	unused     uint32
56
-	totalBytes uint32
47
+	TransferAddress uint32
48
+	DataBusWidth    uint16
49
+	DataWidthBase   uint16
50
+
51
+	// 	Memory          []byte
52
+	Blocks []*Block
53
+	//	Records			[]*DataRecord
54
+}
55
+
56
+type Memory struct {
57
+	Memory      []byte
58
+	LowestAddr  uint32
59
+	HighestAddr uint32
57 60
 }
58 61
 
59 62
 // The .X file format is a HP 64000 Absolute format file. Documentation of this
@@ -90,12 +93,7 @@ func ReadDotX(f *os.File) (*DotXFile, error) {
90 93
 		return nil, fmt.Errorf("bad header magic")
91 94
 	}
92 95
 
93
-	dotX := &DotXFile{
94
-		ProcessorRecord: &ProcessorRecord{},
95
-		DataRecords:     make([]*DataRecord, 0),
96
-	}
97
-
98
-	dotX.ProductionFlag = header[17]
96
+	dotX := &DotXFile{}
99 97
 
100 98
 	rawHeader := string(header[3:13])
101 99
 
@@ -104,18 +102,24 @@ func ReadDotX(f *os.File) (*DotXFile, error) {
104 102
 		dotX.HeaderText = rawHeader[:nullIndex]
105 103
 	}
106 104
 
107
-	pr := dotX.ProcessorRecord
105
+	pr := &processorRecord{}
108 106
 	err = binary.Read(f, binary.BigEndian, pr)
109 107
 	if err != nil {
110 108
 		return nil, err
111 109
 	}
112 110
 
111
+	dotX.TransferAddress = uint32(pr.TransferAddressLS) + uint32(pr.TransferAddressMS)<<16
112
+	dotX.ProductionFlag = header[17]
113
+	dotX.DataBusWidth = pr.DataBusWidth
114
+	dotX.DataWidthBase = pr.DataWidthBase
113 115
 	// The HP docs say that if TransferAddressMS == 0, then the transfer address field is
114 116
 	// to be ignored, so I don't actually do anything useful with the processor record.
117
+	// Trimble native firmware seems to have the reset vector address (0x6BF0) in
118
+	// TransferAddressLS, but in a .X generated by a firmware save, the field is all zeros.
115 119
 
116
-	dotX.DataRecords = make([]*DataRecord, 0)
120
+	records := make([]*DataRecord, 0)
117 121
 	for {
118
-		dr := DataRecordHeader{}
122
+		dr := dataRecordHeader{}
119 123
 		err = binary.Read(f, binary.BigEndian, &dr)
120 124
 		if err != nil {
121 125
 			if err == io.EOF {
@@ -123,81 +127,106 @@ func ReadDotX(f *os.File) (*DotXFile, error) {
123 127
 			}
124 128
 			return nil, err
125 129
 		}
130
+		rec := &DataRecord{
131
+			Addr:  uint32(dr.LoadAddressMS)<<16 + uint32(dr.LoadAddressLS),
132
+			Bytes: make([]byte, dr.DataBytes),
133
+		}
126 134
 
127
-		db := make([]byte, dr.DataBytes)
128
-		_, err = f.Read(db)
135
+		_, err = f.Read(rec.Bytes)
129 136
 		if err != nil {
130 137
 			return nil, err
131 138
 		}
132 139
 
133
-		dotX.DataRecords = append(dotX.DataRecords, &DataRecord{
134
-			Header: dr,
135
-			Bytes:  db,
136
-		})
137
-
140
+		records = append(records, rec)
138 141
 	}
139 142
 
140 143
 	// figure out how big the target memory needs to be
141
-	dotX.minAddr = dotX.DataRecords[0].LoadAddr()
142
-	dotX.maxAddr = dotX.DataRecords[0].MaxAddr()
143 144
 
144
-	for _, r := range dotX.DataRecords {
145
-		if r.MaxAddr() > dotX.maxAddr {
146
-			dotX.maxAddr = r.MaxAddr()
147
-		}
148
-		if r.LoadAddr() < dotX.minAddr {
149
-			dotX.minAddr = r.LoadAddr()
150
-		}
151
-		dotX.totalBytes += uint32(len(r.Bytes))
152
-	}
145
+	dotX.Blocks = []*Block{}
153 146
 
154
-	dotX.memSize = dotX.maxAddr - dotX.minAddr
155
-	dotX.unused = dotX.maxAddr - dotX.minAddr - dotX.totalBytes
147
+	var block *Block
156 148
 
157
-	// create memory and a map of which bytes have been modified
158
-	dotX.Memory = make([]uint8, dotX.maxAddr)
159
-	dirtyBytes := make([]bool, dotX.maxAddr)
149
+	for _, r := range records {
150
+		start := r.Addr
151
+		end := r.Addr + uint32(len(r.Bytes)) - 1
160 152
 
161
-	for _, r := range dotX.DataRecords {
162
-		a := r.LoadAddr()
163
-		for i, b := range r.Bytes {
164
-			dotX.Memory[a+uint32(i)] = b
165
-			dirtyBytes[a+uint32(i)] = true
153
+		if block != nil {
154
+			if start == block.EndAddr+1 { // continuing block
155
+				block.EndAddr = end
156
+				block.Bytes = append(block.Bytes, r.Bytes...)
157
+			} else {
158
+				dotX.Blocks = append(dotX.Blocks, block)
159
+				block = nil
160
+			}
161
+		}
162
+		if block == nil {
163
+			block = &Block{
164
+				StartAddr: start,
165
+				EndAddr:   end,
166
+				Bytes:     r.Bytes,
167
+			}
166 168
 		}
167
-		r.Bytes = dotX.Memory[a : a+uint32(len(r.Bytes))] // this makes each data record a reference to memory
168 169
 
169 170
 	}
171
+	if block != nil {
172
+		dotX.Blocks = append(dotX.Blocks, block)
173
+	}
170 174
 
171
-	dotX.Blocks = []Block{}
175
+	return dotX, nil
176
+}
172 177
 
173
-	inBlock := false
174
-	var blockStart int
178
+func (dotX *DotXFile) ToMemory() *Memory {
179
+	m := &Memory{}
175 180
 
176
-	for i, d := range dirtyBytes {
177
-		if d && !inBlock {
178
-			inBlock = true
179
-			blockStart = i
181
+	m.HighestAddr = uint32(0)
182
+	m.LowestAddr = uint32(0xFFFFFFFF)
180 183
 
184
+	// find memory bounds
185
+	for _, block := range dotX.Blocks {
186
+		if block.Checksummable() {
187
+			if block.EndAddr > m.HighestAddr {
188
+				m.HighestAddr = block.EndAddr
189
+			}
190
+			if block.StartAddr < m.LowestAddr {
191
+				m.LowestAddr = block.StartAddr
192
+			}
181 193
 		}
182
-		if !d && inBlock {
183
-			inBlock = false
184
-			dotX.Blocks = append(dotX.Blocks, Block{
185
-				StartAddr: uint32(blockStart),
186
-				EndAddr:   uint32(i - 1),
187
-				Bytes:     dotX.Memory[blockStart:i],
188
-			})
194
+	}
195
+
196
+	m.Memory = make([]byte, m.HighestAddr+1)
197
+
198
+	for _, block := range dotX.Blocks {
199
+		if block.Checksummable() {
200
+			copy(m.Memory[block.StartAddr:block.EndAddr+1], block.Bytes)
189 201
 		}
202
+	}
190 203
 
204
+	return m
205
+}
206
+
207
+func NewDotX() *DotXFile {
208
+	return &DotXFile{
209
+		DataBusWidth:  16,
210
+		DataWidthBase: 8,
211
+		Blocks:        make([]*Block, 0),
191 212
 	}
213
+}
192 214
 
193
-	if inBlock {
194
-		dotX.Blocks = append(dotX.Blocks, Block{
195
-			StartAddr: uint32(blockStart),
196
-			EndAddr:   uint32(len(dirtyBytes) - 1),
197
-			Bytes:     dotX.Memory[blockStart:len(dirtyBytes)],
198
-		})
215
+func (dotX *DotXFile) AddBlock(addr uint32, b []byte) {
216
+	block := &Block{
217
+		StartAddr: addr,
218
+		EndAddr:   addr + uint32(len(b)),
219
+		Bytes:     b,
199 220
 	}
200
-	return dotX, nil
221
+	dotX.Blocks = append(dotX.Blocks, block)
222
+}
223
+
224
+func (dotX *DotXFile) TotalBytes() int {
225
+	t := 0
226
+	for _, block := range dotX.Blocks {
227
+		t += len(block.Bytes)
228
+	}
229
+	return t
201 230
 }
202 231
 
203 232
 func (dotX *DotXFile) WriteDotX(f *os.File) error {
@@ -206,28 +235,52 @@ func (dotX *DotXFile) WriteDotX(f *os.File) error {
206 235
 	trimbleHeader := make([]byte, 18)
207 236
 	trimbleHeader[0] = 0x82 // ?
208 237
 	trimbleHeader[1] = 0x04 // magic number
209
-	trimbleHeader[2] = 0x38 // ?
238
+	trimbleHeader[2] = 0x00 // ?
210 239
 	copy(trimbleHeader[3:17], dotX.HeaderText)
211 240
 	trimbleHeader[17] = dotX.ProductionFlag // Production Version
212 241
 	f.Write(trimbleHeader)
213 242
 
214 243
 	// Write Processor Record
215
-	err := binary.Write(f, binary.BigEndian, dotX.ProcessorRecord)
244
+	pr := &processorRecord{
245
+		Length:            7,
246
+		DataBusWidth:      dotX.DataBusWidth,
247
+		DataWidthBase:     dotX.DataWidthBase,
248
+		TransferAddressLS: uint16(dotX.TransferAddress & 0xFFFF),
249
+		TransferAddressMS: uint16(dotX.TransferAddress >> 16 & 0xFFFF),
250
+	}
251
+	err := binary.Write(f, binary.BigEndian, pr)
252
+	if err != nil {
253
+		return err
254
+	}
255
+	cs1 := &DataRecord{
256
+		Addr:  0x00FFFA54,
257
+		Bytes: []byte{0x70, 0x07, 0x78, 0x71},
258
+	}
259
+	err = cs1.Write(f)
260
+	if err != nil {
261
+		return err
262
+	}
263
+	cs2 := &DataRecord{
264
+		Addr:  0x00FFFA46,
265
+		Bytes: []byte{0x03, 0xF5},
266
+	}
267
+	err = cs2.Write(f)
216 268
 	if err != nil {
217 269
 		return err
218 270
 	}
219 271
 
220
-	// Write Data Records
221
-	for _, dr := range dotX.DataRecords {
222
-		err = binary.Write(f, binary.BigEndian, dr.Header)
223
-		if err != nil {
224
-			return err
272
+	for _, block := range dotX.Blocks {
273
+		if !block.Checksummable() {
274
+			continue
225 275
 		}
226
-		err = binary.Write(f, binary.BigEndian, dr.Bytes)
227
-		if err != nil {
228
-			return err
276
+		for _, rec := range block.ToRecords(244) {
277
+			err = rec.Write(f)
278
+			if err != nil {
279
+				return err
280
+			}
229 281
 		}
230 282
 	}
283
+
231 284
 	return nil
232 285
 }
233 286
 
@@ -237,13 +290,13 @@ func WriteBinary(memory []byte, outfile string) error {
237 290
 }
238 291
 
239 292
 func (dotX *DotXFile) SaveBinary(outfile string) error {
240
-	err := ioutil.WriteFile(outfile, []byte(dotX.Memory), 0644)
241
-	return err
293
+	//err := ioutil.WriteFile(outfile, []byte(dotX.Memory), 0644)
294
+	return nil //err
242 295
 }
243 296
 
244
-func (dotX *DotXFile) ExtractSigCode(baseAddr uint32) []uint8 {
297
+func (m *Memory) ExtractSigCode(baseAddr uint32) []byte {
245 298
 
246
-	tmsRAM := make([]uint8, 0x8000)
299
+	tmsRAM := make([]byte, 0x8000)
247 300
 
248 301
 	inAddr := baseAddr + 0x1C
249 302
 
@@ -252,17 +305,17 @@ func (dotX *DotXFile) ExtractSigCode(baseAddr uint32) []uint8 {
252 305
 	// 4-5		destination offset
253 306
 	// 6...n	data
254 307
 	for {
255
-		if binary.BigEndian.Uint16(dotX.Memory[inAddr:inAddr+3]) == 0 {
308
+		if binary.BigEndian.Uint16(m.Memory[inAddr:inAddr+3]) == 0 {
256 309
 			break
257 310
 		}
258
-		i := binary.BigEndian.Uint16(dotX.Memory[inAddr+2:inAddr+5]) >> 1
259
-		outAddr := uint32(binary.BigEndian.Uint16(dotX.Memory[inAddr+4:inAddr+7])) << 1
311
+		i := binary.BigEndian.Uint16(m.Memory[inAddr+2:inAddr+5]) >> 1
312
+		outAddr := uint32(binary.BigEndian.Uint16(m.Memory[inAddr+4:inAddr+7])) << 1
260 313
 		inAddr += 8
261 314
 		for ; i > 0; i-- {
262 315
 			// TMS320C25 is little endian
263 316
 			// MC68332 is big endian
264
-			tmsRAM[outAddr] = dotX.Memory[inAddr+1]
265
-			tmsRAM[outAddr+1] = dotX.Memory[inAddr]
317
+			tmsRAM[outAddr] = m.Memory[inAddr+1]
318
+			tmsRAM[outAddr+1] = m.Memory[inAddr]
266 319
 			inAddr += 2
267 320
 			outAddr += 2
268 321
 
@@ -275,45 +328,41 @@ func (dotX *DotXFile) ExtractSigCode(baseAddr uint32) []uint8 {
275 328
 func (dotX *DotXFile) PrintInfo() {
276 329
 
277 330
 	fmt.Println("----------------- Header Record -----------------")
278
-	fmt.Printf("                    Version: %d\n", dotX.ProductionFlag)
331
+	fmt.Printf("        Production firmware: %v\n", dotX.ProductionFlag == 'P')
279 332
 	fmt.Printf("        HP64000 header name: %s\n", dotX.HeaderText)
280 333
 
281 334
 	fmt.Println("------------ Processor Record ------------")
282
-	fmt.Printf("              Record Length: %d\n", dotX.ProcessorRecord.Length+1)
283
-	fmt.Printf("             Data Bus Width: %d\n", dotX.ProcessorRecord.DataBusWidth)
284
-	fmt.Printf("            Data Width Base: %d\n", dotX.ProcessorRecord.DataWidthBase)
285
-	fmt.Printf("        Transfer Address LS: 0x%04X\n", dotX.ProcessorRecord.TransferAddressLS)
286
-	fmt.Printf("        Transfer Address MS: 0x%04X\n", dotX.ProcessorRecord.TransferAddressMS)
287
-	fmt.Printf("  Transfer Address Combined: 0x%08X\n", dotX.ProcessorRecord.TransferAddress())
335
+	fmt.Printf("             Data Bus Width: %d\n", dotX.DataBusWidth)
336
+	fmt.Printf("            Data Width Base: %d\n", dotX.DataWidthBase)
337
+	fmt.Printf("           Transfer Address: 0x%08X\n", dotX.TransferAddress)
338
+
339
+	dotX.PrintBlocks()
340
+}
341
+
342
+func (m *Memory) PrintInfo() {
288 343
 
289 344
 	fmt.Println("-------------- Data Records --------------")
290
-	fmt.Printf("          Number of Records: %d\n", len(dotX.DataRecords))
291
-	fmt.Printf("             Lowest Address: 0x%08X\n", dotX.minAddr)
292
-	fmt.Printf("            Highest Address: 0x%08X\n", dotX.maxAddr)
293
-	fmt.Printf("                Memory Size: %d\n", dotX.memSize)
294
-	fmt.Printf("            Populated Space: %d (%0.2f%%)\n", dotX.totalBytes, float64(dotX.totalBytes)/float64(dotX.memSize)*100)
295
-	fmt.Printf("               Unused Space: %d (%0.2f%%)\n", dotX.unused, float64(dotX.unused)/float64(dotX.memSize)*100)
345
+	fmt.Printf("             Lowest Address: 0x%08X\n", m.LowestAddr)
346
+	fmt.Printf("            Highest Address: 0x%08X\n", m.HighestAddr)
296 347
 
297 348
 	fmt.Println("-------------- Firmware Metadata --------------")
298
-	verMaj, verMin := dotX.FirmwareVersion()
349
+	verMaj, verMin := m.FirmwareVersion()
299 350
 	fmt.Printf("           Firmware Version: %d.%d\n", verMaj, verMin)
300
-	fmt.Printf("              Test firmware: %v\n", dotX.Memory[0x229] != 0)
301
-	fmt.Printf("        Production firmware: %v\n", dotX.ProductionFlag == 'P')
302
-	fmt.Printf("              Firmware Date: %v\n", dotX.FirmwareDate().Format("02-Jan-2006"))
351
+	fmt.Printf("              Test firmware: %v\n", m.Memory[0x229] != 0)
352
+	fmt.Printf("              Firmware Date: %v\n", m.FirmwareDate().Format("02-Jan-2006"))
303 353
 
304
-	dotX.PrintBlocks()
305 354
 }
306 355
 
307
-func (dotX *DotXFile) FirmwareVersion() (int, int) {
308
-	ver := int(binary.BigEndian.Uint16(dotX.Memory[0x204 : 0x205+1]))
356
+func (m *Memory) FirmwareVersion() (int, int) {
357
+	ver := int(binary.BigEndian.Uint16(m.Memory[0x204 : 0x205+1]))
309 358
 	major := ver / 100
310 359
 	minor := ver % 100
311 360
 	return major, minor
312 361
 }
313 362
 
314
-func (dotX *DotXFile) FirmwareDate() time.Time {
363
+func (m *Memory) FirmwareDate() time.Time {
315 364
 
316
-	date := int(binary.BigEndian.Uint32(dotX.Memory[0x222 : 0x222+5]))
365
+	date := int(binary.BigEndian.Uint32(m.Memory[0x222 : 0x222+5]))
317 366
 	month := date / 10000
318 367
 	day := date / 100 % 100
319 368
 	year := date % 100
@@ -341,32 +390,34 @@ func (dotX *DotXFile) PrintBlocks() {
341 390
 			fmt.Printf("                   Checksum: %08X\n", cs)
342 391
 			ccs, _ := block.CalculateChecksum()
343 392
 			fmt.Printf("                 Calculated: %08X\n", ccs)
393
+		} else {
394
+			fmt.Printf("                      Bytes: % 02X\n", block.Bytes)
344 395
 		}
345 396
 	}
346 397
 
347 398
 }
348 399
 
349
-func (dotX *DotXFile) FindSequence(seq []uint8) []uint32 {
350
-
351
-	matches := make([]uint32, 0)
352
-	for _, block := range dotX.Blocks {
353
-		for i := 0; i <= len(block.Bytes)-len(seq); i++ {
354
-			if bytes.Compare(block.Bytes[i:i+len(seq)], seq) == 0 {
355
-				matches = append(matches, uint32(i)+block.StartAddr)
356
-			}
357
-		}
358
-	}
359
-	return matches
360
-
361
-}
400
+// func (m *Memory) FindSequence(seq []byte) []uint32 {
401
+//
402
+// 	matches := make([]uint32, 0)
403
+// 	for _, block := range dotX.Blocks {
404
+// 		for i := 0; i <= len(block.Bytes)-len(seq); i++ {
405
+// 			if bytes.Compare(block.Bytes[i:i+len(seq)], seq) == 0 {
406
+// 				matches = append(matches, uint32(i)+block.StartAddr)
407
+// 			}
408
+// 		}
409
+// 	}
410
+// 	return matches
411
+//
412
+// }
362 413
 
363
-func (dotX *DotXFile) UpdateChecksums() {
364
-	for _, block := range dotX.Blocks {
365
-		block.UpdateChecksum()
366
-	}
367
-}
414
+// func (dotX *DotXFile) UpdateChecksums() {
415
+// 	for _, block := range dotX.Blocks {
416
+// 		block.UpdateChecksum()
417
+// 	}
418
+// }
368 419
 
369
-type ProcessorRecord struct {
420
+type processorRecord struct {
370 421
 	Length            uint16
371 422
 	DataBusWidth      uint16
372 423
 	DataWidthBase     uint16
@@ -374,11 +425,11 @@ type ProcessorRecord struct {
374 425
 	TransferAddressMS uint16
375 426
 }
376 427
 
377
-func (p *ProcessorRecord) TransferAddress() int {
378
-	return int(p.TransferAddressLS) + int(p.TransferAddressMS)<<16
379
-}
428
+// func (p *processorRecord) TransferAddress() int {
429
+// 	return int(p.TransferAddressLS) + int(p.TransferAddressMS)<<16
430
+// }
380 431
 
381
-type DataRecordHeader struct {
432
+type dataRecordHeader struct {
382 433
 	Length        uint16
383 434
 	DataBytes     uint16
384 435
 	LoadAddressLS uint16
@@ -386,22 +437,57 @@ type DataRecordHeader struct {
386 437
 }
387 438
 
388 439
 type DataRecord struct {
389
-	Header DataRecordHeader
390
-	Bytes  []uint8
440
+	Addr  uint32
441
+	Bytes []byte
442
+	//Header  dataRecordHeader
391 443
 }
392 444
 
393
-func (d *DataRecord) LoadAddr() uint32 {
394
-	return uint32(d.Header.LoadAddressLS) + uint32(d.Header.LoadAddressMS)<<16
445
+func (d *DataRecord) LastAddr() uint32 {
446
+	return d.Addr + uint32(len(d.Bytes)) - 1
395 447
 }
396 448
 
397
-func (d *DataRecord) MaxAddr() uint32 {
398
-	return d.LoadAddr() + uint32(d.Header.DataBytes)
449
+func (d *DataRecord) Write(f *os.File) error {
450
+	header := dataRecordHeader{
451
+		Length:        uint16(len(d.Bytes) + 5),
452
+		DataBytes:     uint16(len(d.Bytes)),
453
+		LoadAddressMS: uint16(d.Addr >> 16 & 0xFFFF),
454
+		LoadAddressLS: uint16(d.Addr & 0xFFFF),
455
+	}
456
+	err := binary.Write(f, binary.BigEndian, header)
457
+	if err != nil {
458
+		return err
459
+	}
460
+	err = binary.Write(f, binary.BigEndian, d.Bytes)
461
+	if err != nil {
462
+		return err
463
+	}
464
+	return nil
399 465
 }
400 466
 
401 467
 type Block struct {
402 468
 	StartAddr uint32
403 469
 	EndAddr   uint32
404
-	Bytes     []uint8
470
+	Bytes     []byte
471
+}
472
+
473
+func (b *Block) Len() int {
474
+	return int(b.EndAddr - b.StartAddr)
475
+}
476
+
477
+func (b *Block) ToRecords(blockSize int) []*DataRecord {
478
+	recs := make([]*DataRecord, 0)
479
+	length := len(b.Bytes)
480
+	for i := 0; i < length; i += blockSize {
481
+		l := blockSize
482
+		if i+l > length {
483
+			l = length - i
484
+		}
485
+		recs = append(recs, &DataRecord{
486
+			Addr:  uint32(i) + b.StartAddr,
487
+			Bytes: b.Bytes[i : i+l],
488
+		})
489
+	}
490
+	return recs
405 491
 }
406 492
 
407 493
 func (b *Block) Checksummable() bool {

+ 222
- 42
monitor/monitor.go View File

@@ -14,6 +14,20 @@ import (
14 14
 
15 15
 const (
16 16
 	readWriteBlockSize = 244
17
+
18
+	NrmCmdGetSerial  = 0x06
19
+	NrmCmdRSerial    = 0x07
20
+	NrmCmdGetOpt     = 0x4A
21
+	NrmCmdRetOpt     = 0x4B
22
+	NrmCmdModeChange = 0x87
23
+
24
+	MonCmdWriteMem = 0x80
25
+	MonCmdReadMem  = 0x82
26
+	MonCmdBaudRate = 0x86
27
+	MonCmdReset    = 0x88
28
+	MonCmdJmp      = 0x89
29
+
30
+	MonCmdReadMemAck = 0x92
17 31
 )
18 32
 
19 33
 type Monitor struct {
@@ -31,6 +45,8 @@ type Monitor struct {
31 45
 	Dummy bool
32 46
 
33 47
 	inMonitor bool
48
+	
49
+	seekPos uint32
34 50
 }
35 51
 
36 52
 type RecieverState int
@@ -52,7 +68,6 @@ const (
52 68
 func (m *Monitor) StartMonitor() error {
53 69
 	if m.Dummy {
54 70
 		m.inMonitor = true
55
-		fmt.Println("Monitor dummy mode active.")
56 71
 		return nil
57 72
 	}
58 73
 	fmt.Println("Starting monitor mode...")
@@ -167,9 +182,10 @@ func (m *Monitor) setupChipSelects() error {
167 182
 	// back to the CPU? Hmmm.
168 183
 
169 184
 	err := m.WriteMemory(0x00FFFA58, []uint16{
170
-		0x1004, // CSBAR3
171
-		0x7B71, // CSOR3
185
+		0x1004, // CSBAR3 128k @ 0x100000
186
+		0x7B71, // CSOR3 Change DSACK to 13 wait
172 187
 	})
188
+
173 189
 	if err != nil {
174 190
 		return err
175 191
 	}
@@ -256,13 +272,17 @@ func (m *Monitor) waitForMonitor() error {
256 272
 func (m *Monitor) Stop() error {
257 273
 
258 274
 	// send the reboot command
259
-	err := m.SendStxEtxRequest(0x88, []byte{})
275
+	err := m.SendStxEtxRequest(MonCmdReset, []byte{})
260 276
 	if err != nil {
261 277
 		return err
262 278
 	}
263 279
 
264 280
 	m.inMonitor = false
265 281
 
282
+	// it seems that if I switch the baud rate too soon, the UART will still
283
+	// be transmitting the above data, which will corrupt the command.
284
+	time.Sleep(2 * time.Second)
285
+
266 286
 	// revert the serial port
267 287
 	err = m.useUserBaudRate()
268 288
 	if err != nil {
@@ -277,12 +297,19 @@ func (m *Monitor) Close() {
277 297
 	m.port.Close()
278 298
 }
279 299
 
280
-// ReadMemory reads the device memory
300
+// ReadMemory reads the device memory, breaking the read up into multiple
301
+// commands as needed.
281 302
 func (m *Monitor) ReadMemory(addr uint32, length int) ([]byte, error) {
303
+	return m.ReadMemoryWithProgress(addr, length, nil)
304
+}
305
+
306
+// ReadMemory reads the device memory, breaking the read up into multiple
307
+// commands as needed.
308
+func (m *Monitor) ReadMemoryWithProgress(addr uint32, length int, progressFunc func(uint32)) ([]byte, error) {
282 309
 	if !m.inMonitor {
283 310
 		return nil, fmt.Errorf("receiver not in monitor")
284 311
 	}
285
-	fmt.Printf("ReadMemory: addr=%08X length=%d\n", addr, length)
312
+	//fmt.Printf("ReadMemory: addr=%08X length=%d\n", addr, length)
286 313
 
287 314
 	maxRetries := 3
288 315
 
@@ -300,7 +327,7 @@ func (m *Monitor) ReadMemory(addr uint32, length int) ([]byte, error) {
300 327
 		binary.BigEndian.PutUint32(b[0:4], blockAddr)
301 328
 		b[4] = byte(l)
302 329
 
303
-		fmt.Printf("ReadMemory LOOP: addr=%08X length=%d\n", blockAddr, l)
330
+		//fmt.Printf("ReadMemory LOOP: addr=%08X length=%d\n", blockAddr, l)
304 331
 
305 332
 		var err error
306 333
 
@@ -326,11 +353,15 @@ func (m *Monitor) ReadMemory(addr uint32, length int) ([]byte, error) {
326 353
 		if err != nil {
327 354
 			return nil, err
328 355
 		}
356
+		if progressFunc != nil {
357
+			progressFunc(blockAddr)
358
+		}
329 359
 	}
330 360
 	return out, nil
331 361
 }
332 362
 
333
-// WriteMemory writes the device memory
363
+// WriteMemory writes the device memory, breaking the write up into multiple
364
+// commands as needed.
334 365
 func (m *Monitor) WriteMemory(addr uint32, data interface{}) error {
335 366
 	if !m.inMonitor {
336 367
 		return fmt.Errorf("receiver not in monitor")
@@ -367,6 +398,7 @@ func (m *Monitor) WriteMemory(addr uint32, data interface{}) error {
367 398
 				break
368 399
 			}
369 400
 		}
401
+
370 402
 		if err != nil {
371 403
 			return err
372 404
 		}
@@ -374,6 +406,30 @@ func (m *Monitor) WriteMemory(addr uint32, data interface{}) error {
374 406
 	return nil
375 407
 }
376 408
 
409
+// Jump calls the monitor's jump command.
410
+func (m *Monitor) Jump(addr uint32) error {
411
+	if !m.inMonitor {
412
+		return fmt.Errorf("receiver not in monitor")
413
+	}
414
+	b := make([]byte, 4)
415
+	binary.BigEndian.PutUint32(b[0:4], addr)
416
+
417
+	return m.DoAckCommand(MonCmdJmp, b)
418
+}
419
+
420
+// ResetReceiver calls the monitor's reset command.
421
+func (m *Monitor) ResetReceiver() error {
422
+	if !m.inMonitor {
423
+		return fmt.Errorf("receiver not in monitor")
424
+	}
425
+	err := m.SendStxEtxRequest(MonCmdReset, []byte{})
426
+	if err != nil {
427
+		return err
428
+	}
429
+	m.inMonitor = false
430
+	return nil
431
+}
432
+
377 433
 // checkMonitorMode checks if the receiver is in normal mode or monitor mode.
378 434
 // this is done by running command 0x82, which in normal mode is the screen dump
379 435
 // command, which replies with a packet of type 0x82. In monitor mode, the
@@ -401,17 +457,6 @@ func (m *Monitor) checkMonitorMode() (RecieverState, error) {
401 457
 	return ReceiverNormal, nil
402 458
 }
403 459
 
404
-func (m *Monitor) ResetReceiver() error {
405
-	fmt.Println("Resetting receiver...")
406
-
407
-	err := m.SendStxEtxRequest(MonCmdReset, []byte{})
408
-	if err != nil {
409
-		return err
410
-	}
411
-	m.inMonitor = false
412
-	return nil
413
-}
414
-
415 460
 // ReceiverInfo holds all the information we can glean from the receiver by
416 461
 // probing its memory.
417 462
 type ReceiverInfo struct {
@@ -438,7 +483,7 @@ type ReceiverInfo struct {
438 483
 func (info *ReceiverInfo) PrintOptions() {
439 484
 
440 485
 	// Print receiver identity information
441
-	fmt.Printf("\n   name1:%s\n", info.Name1)
486
+	fmt.Printf("   name1:%s\n", info.Name1)
442 487
 	fmt.Printf("   name2:%s\n", info.Name2)
443 488
 	fmt.Printf("ASCII serial #:%14s\n", info.SerialNumberString)
444 489
 	fmt.Printf("  int serial #:%14d\n", info.SerialNumber)
@@ -468,10 +513,9 @@ func (info *ReceiverInfo) PrintOptions() {
468 513
 
469 514
 func (info *ReceiverInfo) PrintVersions() {
470 515
 	// TODO: empty string in param 3 should say '(TEST)' when in test mode
471
-	fmt.Printf("\n")
472
-	fmt.Printf("  code version=%1d.%02d %s    Date: %s\n", info.FirmwareVersionMajor, info.FirmwareVersionMinor, "", info.FirmwareDate.Format("02-Jan-06"))
516
+	fmt.Printf("  Code Version: %1d.%02d %s    Date: %s\n", info.FirmwareVersionMajor, info.FirmwareVersionMinor, "", info.FirmwareDate.Format("02-Jan-06"))
473 517
 	fmt.Printf("    Code1: %06X-%06X   Code2: %06X-%06X\n", info.Code1Start, info.Code1End-1, info.Code2Start, info.Code2End-1)
474
-	fmt.Printf("checksums:    %06X               %06X\n", info.Code1Checksum, info.Code2Checksum)
518
+	fmt.Printf("Checksums:    %06X               %06X\n", info.Code1Checksum, info.Code2Checksum)
475 519
 }
476 520
 
477 521
 // GetReceiverInfo reads receiver information out of the receiver. Unlike GetOptions
@@ -563,6 +607,67 @@ type RuntimeConfig struct {
563 607
 	ChannelsL1        string
564 608
 }
565 609
 
610
+func progressBar(width, progress, total int) string {
611
+	progressBlocks := []rune{'▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'}
612
+	p := float64(progress) / float64(total)
613
+	blocks := int(float64(width) * p)
614
+	eighths := int(float64(width)*p*8) % 8
615
+	bar := strings.Repeat("█", blocks)
616
+	blankWidth := width - blocks - 1
617
+	if blankWidth < 0 {
618
+		blankWidth = 0
619
+	}
620
+	blank := strings.Repeat("-", blankWidth)
621
+	return fmt.Sprintf("(%0.2f%%) %s%c%s\n", p*100, bar, progressBlocks[eighths], blank)
622
+}
623
+
624
+type codeBlock struct {
625
+	start uint32
626
+	end   uint32
627
+}
628
+
629
+func (m *Monitor) CaptureReceiverFirmware() (*dotx.DotXFile, error) {
630
+
631
+	info, err := m.GetReceiverInfo()
632
+	if err != nil {
633
+		return nil, err
634
+	}
635
+	dotX := dotx.NewDotX()
636
+
637
+	// these chip selects are hard-coded into the first two records in the file
638
+	dotX.AddBlock(0x00FFFA54, []byte{0x70, 0x07, 0x78, 0x71})
639
+	dotX.AddBlock(0x00FFFA46, []byte{0x03, 0xF5})
640
+
641
+	// then the code blocks
642
+	codeBlocks := []*dotx.Block{
643
+		{StartAddr: info.Code1Start, EndAddr: info.Code1End},
644
+		{StartAddr: info.Code2Start, EndAddr: info.Code2End},
645
+	}
646
+
647
+	totalBytes := 0
648
+
649
+	for _, cb := range codeBlocks {
650
+		totalBytes += cb.Len()
651
+	}
652
+
653
+	bytesWriten := 0
654
+
655
+	for _, block := range codeBlocks {
656
+		blockLen := block.Len()
657
+		b, err := m.ReadMemoryWithProgress(block.StartAddr, blockLen, func(i uint32) {
658
+			fmt.Printf("$%08X  %s\r", i, progressBar(50, int(i-block.StartAddr)+bytesWriten, totalBytes))
659
+		})
660
+		if err != nil {
661
+			return nil, err
662
+		}
663
+		block.Bytes = b
664
+		dotX.Blocks = append(dotX.Blocks, block)
665
+		bytesWriten += blockLen
666
+	}
667
+
668
+	return dotX, nil
669
+}
670
+
566 671
 func (m *Monitor) GetRuntimeConfig() (*RuntimeConfig, error) {
567 672
 	if m.inMonitor {
568 673
 		return nil, fmt.Errorf("receiver not in normal mode")
@@ -686,28 +791,103 @@ func (m *Monitor) GetOptions() (*Options, error) {
686 791
 	return opts, nil
687 792
 }
688 793
 
689
-func (m *Monitor) WriteFirmware(fw *dotx.DotXFile) {
794
+func (m *Monitor) ProgramReceiver(fw *dotx.DotXFile) error {
690 795
 	fmt.Printf("Writing receiver program...\n")
691 796
 	save := make([]byte, 8)
692
-	numRecs := float64(len(fw.DataRecords))
797
+	totalBytes := fw.TotalBytes()
693 798
 	t := 0
694
-	for i, rec := range fw.DataRecords {
695
-		fmt.Printf("%08X  (%0.2f%%)\r", rec.LoadAddr(), float64(i)/numRecs*100)
696
-		//fmt.Printf("----%02X\n",rec.Bytes)
697
-		// 	fmt.Printf("LoadAddr: %08X\n",rec.LoadAddr())
698
-		t += len(rec.Bytes)
699
-		if rec.LoadAddr() == 0 {
700
-			b2 := make([]byte, len(rec.Bytes))
701
-			copy(b2, rec.Bytes)
702
-			copy(save[0:8], rec.Bytes[0:8])
703
-			binary.BigEndian.PutUint32(b2[0:], 0x4E722700)
704
-			binary.BigEndian.PutUint32(b2[4:], 0x00000000)
705
-			m.WriteMemory(rec.LoadAddr(), b2)
706
-		} else {
707
-			m.WriteMemory(rec.LoadAddr(), rec.Bytes)
799
+	var err error
800
+	progressBarWidth := 50
801
+	progressBlocks := []rune{'▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'}
802
+
803
+	// set fixFailedWrite to true to have the code just correct the first 8
804
+	// bytes of memory. This is basically a kludge for testing.
805
+	fixFailedWrite := false
806
+
807
+	for i, block := range fw.Blocks {
808
+		if fixFailedWrite && i > 2 {
809
+			// all we want are the chip selects and CODE1
810
+			continue
708 811
 		}
709
-		time.Sleep(1 * time.Millisecond)
812
+		recs := block.ToRecords(244)
813
+		fmt.Printf("Writing block %d ($%08X - $%08X)...\n", i, block.StartAddr, block.EndAddr)
814
+		for _, rec := range recs {
815
+			t += len(rec.Bytes)
816
+			p := float64(t) / float64(totalBytes)
817
+			blocks := int(float64(progressBarWidth) * p)
818
+			eighths := int(float64(progressBarWidth)*p*8) % 8
819
+			bar := strings.Repeat("█", blocks)
820
+			blankWidth := progressBarWidth - blocks - 1
821
+			if blankWidth < 0 {
822
+				blankWidth = 0
823
+			}
824
+			blank := strings.Repeat("-", blankWidth)
825
+
826
+			progressBar := fmt.Sprintf("%s%c%s", bar, progressBlocks[eighths], blank)
827
+			fmt.Printf("$%08X  (%0.2f%%) %s\r", rec.Addr, p*100, progressBar)
828
+
829
+			if rec.Addr == 0x00000000 {
830
+				// This replaces the first 8 bytes of the firmware image with
831
+				// 4E72270000000000. The first 8 bytes are the stack pointer and
832
+				// reset vector. The first value is actually a STOP #$2700
833
+				// instruction, and the 0x00000000 reset vector means that STOP
834
+				// is the only thing that will be executed. This saves the intended
835
+				// value to write to memory at the end of the firmware upgrade
836
+				// process, guaranteeing that the receiver will not function
837
+				// with a half-baked firmware. Crafty, Trimble.
838
+				b2 := make([]byte, len(rec.Bytes))
839
+				copy(b2, rec.Bytes)
840
+				copy(save[0:8], rec.Bytes[0:8])
841
+				binary.BigEndian.PutUint32(b2[0:], 0x4E722700)
842
+				binary.BigEndian.PutUint32(b2[4:], 0x00000000)
843
+				err = m.WriteMemory(rec.Addr, b2)
844
+
845
+				if fixFailedWrite {
846
+					// for a fixFailedWrite all I care about is the first record.
847
+					break
848
+				}
849
+			} else {
850
+				err = m.WriteMemory(rec.Addr, rec.Bytes)
851
+			}
852
+			if err != nil {
853
+				return err
854
+			}
855
+			if m.Dummy {
856
+				time.Sleep(1 * time.Millisecond)
857
+			}
858
+		}
859
+		fmt.Printf("% 80s\r", "")
710 860
 	}
711
-	fmt.Printf("\nDone. %d bytes written.\n", t)
712
-	m.WriteMemory(0x00000000, save)
861
+	fmt.Printf("\rDone. %d bytes written.\n", t)
862
+	err = m.WriteMemory(0x00000000, save)
863
+	if err != nil {
864
+		return err
865
+	}
866
+
867
+	fmt.Printf("Rebooting receiver.\n")
868
+	return m.ResetReceiver()
869
+}
870
+
871
+// Reader implements the io.Reader interface
872
+func (m *Monitor) xRead(p []byte) (n int, err error) {
873
+	p, err = m.ReadMemoryWithProgress(m.seekPos, len(p), nil)
874
+	return len(p), err
875
+}
876
+
877
+// Seek implements the io.Seeker interface
878
+func (m *Monitor) xSeek(offset int64, whence int) (int64, error) { 
879
+	var abs int64
880
+	switch whence {
881
+	case io.SeekStart:
882
+		abs = offset
883
+	case io.SeekCurrent:
884
+		abs = int64(m.seekPos) + offset
885
+	default:
886
+		return 0, fmt.Errorf("Seek: invalid whence")
887
+	}
888
+	if abs < 0 {
889
+		return 0, fmt.Errorf("Seek: negative position")
890
+	}
891
+	m.seekPos = uint32(abs)
892
+	return abs, nil
713 893
 }

+ 0
- 16
monitor/protocol.go View File

@@ -7,22 +7,6 @@ import (
7 7
 
8 8
 const (
9 9
 	MAXPACKETLLEN = 255 + 6
10
-	// 	STX           = 0x02
11
-	// 	ETX           = 0x03
12
-	// 	ENQ           = 0x05
13
-	// 	ACK           = 0x06
14
-
15
-	NrmCmdGetSerial = 0x06
16
-	NrmCmdRSerial   = 0x07
17
-	NrmCmdGetOpt    = 0x4A
18
-	NrmCmdRetOpt    = 0x4B
19
-
20
-	NrmCmdModeChange = 0x87
21
-	MonCmdBaudRate   = 0x86
22
-	MonCmdWriteMem   = 0x80
23
-	MonCmdReadMem    = 0x82
24
-	MonCmdReadMemAck = 0x92
25
-	MonCmdReset      = 0x88
26 10
 )
27 11
 
28 12
 type ProtocolError struct {

+ 4
- 4
monitor/serial.go View File

@@ -26,13 +26,13 @@ func Connect(device string, baud int, dataBits int, stopBits int, parity string,
26 26
 	}
27 27
 
28 28
 	switch parity {
29
-	case "n":
29
+	case "none":
30 30
 		m.parity = serial.PARITY_NONE
31 31
 		m.portConfig.ParityMode = serial.PARITY_NONE
32
-	case "e":
32
+	case "even":
33 33
 		m.parity = serial.PARITY_EVEN
34 34
 		m.portConfig.ParityMode = serial.PARITY_EVEN
35
-	case "o":
35
+	case "odd":
36 36
 		m.parity = serial.PARITY_ODD
37 37
 		m.portConfig.ParityMode = serial.PARITY_ODD
38 38
 	default:
@@ -117,7 +117,7 @@ func (m *Monitor) useUserBaudRate() error {
117 117
 }
118 118
 
119 119
 func parityToString(p serial.ParityMode) string {
120
-	s := []string{"n", "o", "e"}
120
+	s := []string{"none", "odd", "even"}
121 121
 	return s[p]
122 122
 }
123 123