Ei kuvausta

monitor.go 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. package monitor
  2. import (
  3. "bytes"
  4. "code.beefchicken.com/trimtools/dotx"
  5. "encoding/binary"
  6. "fmt"
  7. // "github.com/jacobsa/go-serial/serial"
  8. "io"
  9. "strconv"
  10. "strings"
  11. "time"
  12. )
  13. const (
  14. readWriteBlockSize = 244
  15. NrmCmdGetSerial = 0x06
  16. NrmCmdRSerial = 0x07
  17. NrmCmdGetOpt = 0x4A
  18. NrmCmdRetOpt = 0x4B
  19. NrmCmdModeChange = 0x87
  20. MonCmdWriteMem = 0x80
  21. MonCmdReadMem = 0x82
  22. MonCmdBaudRate = 0x86
  23. MonCmdReset = 0x88
  24. MonCmdJmp = 0x89
  25. MonCmdReadMemAck = 0x92
  26. )
  27. type Monitor struct {
  28. receiverType ReceiverType
  29. Dummy bool
  30. inMonitor bool
  31. receiver *Receiver
  32. seekPos uint32
  33. }
  34. type ReceiverState int
  35. const (
  36. ReceiverUnexpected ReceiverState = iota
  37. ReceiverUnresponsive
  38. ReceiverNormal
  39. ReceiverInMonitor
  40. )
  41. type ReceiverType int
  42. const (
  43. ReceiverType4000 ReceiverType = iota
  44. ReceiverType4400
  45. )
  46. func NewMonitor(receiver *Receiver) *Monitor {
  47. return &Monitor{receiver: receiver}
  48. }
  49. func (m *Monitor) StartMonitor() error {
  50. if m.Dummy {
  51. m.inMonitor = true
  52. return nil
  53. }
  54. fmt.Println("Starting monitor mode...")
  55. // once we have something that looks like a receiver on the line, figure
  56. // out what mode it's in.
  57. state, err := m.receiver.ProbeReceiverState()
  58. if err != nil {
  59. return err
  60. }
  61. if state == ReceiverUnresponsive {
  62. return fmt.Errorf("receiver unresponsive")
  63. }
  64. if state == ReceiverNormal {
  65. // get config
  66. conf, err := m.CmdGetRuntimeConfig()
  67. if err != nil {
  68. return err
  69. }
  70. fmt.Printf("PPU Version = %.2f\n", conf.BootRomVersion)
  71. opts, err := m.CmdGetOptions()
  72. if opts.ReceiverType == 3 { // gauss
  73. }
  74. // switch to monitor mode
  75. err = m.receiver.DoAckCommand(NrmCmdModeChange, []byte{0x57}) // 0x57 is what an ack at 38400 looks like at 9600 baud.
  76. if err != nil {
  77. return err
  78. }
  79. // When the monitor starts, it reverts back to 9600-N-8-1, so we have to
  80. // re-configure the serial port.
  81. err = m.receiver.useSlowBaudRate()
  82. if err != nil {
  83. return err
  84. }
  85. // It can take a while to boot into monitor mode
  86. err = m.receiver.waitForMonitor()
  87. if err != nil {
  88. return err
  89. }
  90. }
  91. // reconfigure monitor to speak at 38400-N-8-1
  92. // 0x6D = 4800
  93. // 0x37 = 9600
  94. // 0x1B = 19200
  95. // 0x0E = 38400
  96. // This appears to respond with 0xFE, but that is just is what a 38400
  97. // baud ACK (0x06) looks like when received at 9600 baud, and depending
  98. // on where in the bit the UART samples, different UARTs might see
  99. // different values, so we just ignore any no-ack error.
  100. err = m.receiver.DoAckCommand(MonCmdBaudRate, []byte{0x00, 0x0E})
  101. if err != nil {
  102. if _, ok := err.(*ProtocolError); !ok {
  103. return err
  104. }
  105. }
  106. // re-configure port for 38400 baud
  107. err = m.receiver.useFastBaudRate()
  108. if err != nil {
  109. return err
  110. }
  111. // Make sure baud switch was successful
  112. err = m.receiver.waitForMonitor()
  113. if err != nil {
  114. return err
  115. }
  116. // }
  117. m.inMonitor = true
  118. // we should be in monitor mode now.
  119. fmt.Printf("Setting chip selects...\n")
  120. err = m.setChipSelects()
  121. if err != nil {
  122. return err
  123. }
  124. m.inMonitor = true
  125. fmt.Println("Monitor mode active.")
  126. return nil
  127. }
  128. func (m *Monitor) setChipSelects() error {
  129. // I don't understand the mechanism the PPU uses to communicate to the
  130. // system memory. The chip select registers only apply to signals originating
  131. // from the internal bus, so if the PPU is just taking over the bus, then the
  132. // chip selects wouldn't matter. But they definitely do, and if they're not
  133. // set properly, the PPU ends up seeing the wrong memory.
  134. // Maybe the PPU just loads a small ROM monitor into RAM, then hands control
  135. // back to the CPU? Hmmm.
  136. err := m.WriteMemory(0x00FFFA58, []uint16{
  137. 0x1004, // CSBAR3 128k @ 0x100000
  138. 0x7B71, // CSOR3 Change DSACK to 13 wait
  139. })
  140. if err != nil {
  141. return err
  142. }
  143. err = m.WriteMemory(0x00100000, []byte{0x55, 0x55, 0xAA, 0xAA})
  144. if err != nil {
  145. return err
  146. }
  147. b, err := m.ReadMemory(0x00100000, 4)
  148. if err != nil {
  149. return err
  150. }
  151. if bytes.Compare(b, []byte{0x55, 0x55, 0xAA, 0xAA}) == 0 {
  152. fmt.Printf("SE/SSE/SSi H/W target receiver detected.\n")
  153. fmt.Printf("Setting SE/SSE/SSi chip selects...\n")
  154. err = m.WriteMemory(0x00FFFA54, []uint16{
  155. 0x7007, // CSBAR2
  156. 0x7871, // CSOR2
  157. })
  158. if err != nil {
  159. return err
  160. }
  161. err = m.WriteMemory(0x00FFFA46, []uint16{
  162. 0x03F5, // CSPAR1
  163. })
  164. if err != nil {
  165. return err
  166. }
  167. err = m.WriteMemory(0x00FFFA58, []uint16{
  168. 0x1004, // CSBAR3
  169. 0x7BF1, // CSOR3
  170. })
  171. if err != nil {
  172. return err
  173. }
  174. m.receiverType = ReceiverType4000
  175. } else {
  176. fmt.Printf("Cheetah/7400 MSi target receiver detected.\n")
  177. fmt.Printf("Setting Cheetah/7400 MSi chip selects...\n")
  178. err = m.WriteMemory(0x00FFFA48, []uint16{
  179. 0x0005, // CSBARBT
  180. 0x7831, // CSORBT
  181. 0x0405, // CSBAR0
  182. 0x7831, // CSOR0
  183. 0x7005, // CSBAR1
  184. 0x7831, // CSOR1
  185. 0x7405, // CSBAR2
  186. 0x7831, // CSOR2
  187. })
  188. if err != nil {
  189. return err
  190. }
  191. m.receiverType = ReceiverType4400
  192. }
  193. return nil
  194. }
  195. // Stop sends a reboot, which disconnects the monitor, and reconfigures the port back
  196. // to the user configuration.
  197. func (m *Monitor) Stop() error {
  198. return m.CmdResetReceiver()
  199. }
  200. // Close closes the serial port associated with the monitor
  201. func (m *Monitor) Close() {
  202. m.receiver.port.Close()
  203. }
  204. // ReadMemory reads the device memory, breaking the read up into multiple
  205. // commands as needed.
  206. func (m *Monitor) ReadMemory(addr uint32, length int) ([]byte, error) {
  207. if !m.inMonitor {
  208. return nil, fmt.Errorf("receiver not in monitor")
  209. }
  210. //fmt.Printf("ReadMemory: addr=%08X length=%d\n", addr, length)
  211. out := make([]byte, 0)
  212. for i := 0; i < length; i += readWriteBlockSize {
  213. l := readWriteBlockSize
  214. if i+l > length {
  215. l = length - i
  216. }
  217. blockAddr := addr + uint32(i)
  218. b, err := m.CmdReadMemory(blockAddr, uint8(l))
  219. if err != nil {
  220. return nil, err
  221. }
  222. out = append(out, b...)
  223. }
  224. return out, nil
  225. }
  226. func (m *Monitor) CmdReadMemory(addr uint32, length uint8) ([]byte, error) {
  227. b := make([]byte, 5)
  228. binary.BigEndian.PutUint32(b[0:4], addr)
  229. b[4] = byte(length)
  230. //fmt.Printf("CmdReadMemory: addr=%08X length=%d\n", blockAddr, l)
  231. var err error
  232. const maxRetries = 3
  233. for r := 0; r < maxRetries; r++ {
  234. if r > 0 {
  235. fmt.Printf("CmdReadMemory: read failed: %v. Retrying.\n", err)
  236. }
  237. var reply *CommandReply
  238. if reply, err = m.receiver.DoStxEtxCommand(MonCmdReadMem, b); err != nil {
  239. continue
  240. }
  241. if reply.Command != MonCmdReadMemAck || reply.Status != 0 {
  242. err = newProtocolError("unexpected response from read memory")
  243. continue
  244. }
  245. if replyAddr := binary.BigEndian.Uint32(reply.Data[0:4]); replyAddr != addr {
  246. err = newProtocolError("address mismatch in read reply. expected 0x%06X, received 0x%06X", addr, replyAddr)
  247. continue
  248. }
  249. return reply.Data[4:], nil
  250. }
  251. return nil, err
  252. }
  253. // WriteMemory writes the device memory, breaking the write up into multiple
  254. // commands as needed.
  255. func (m *Monitor) WriteMemory(addr uint32, data interface{}) error {
  256. if !m.inMonitor {
  257. return fmt.Errorf("receiver not in monitor")
  258. }
  259. buf := &bytes.Buffer{}
  260. binary.Write(buf, binary.BigEndian, data)
  261. b := buf.Bytes()
  262. length := len(b)
  263. for i := 0; i < length; i += readWriteBlockSize {
  264. l := readWriteBlockSize
  265. if i+l > length {
  266. l = length - i
  267. }
  268. blockAddr := addr + uint32(i)
  269. err := m.CmdWriteMemory(blockAddr, b[i:i+l])
  270. if err != nil {
  271. return err
  272. }
  273. }
  274. return nil
  275. }
  276. func (m *Monitor) CmdWriteMemory(addr uint32, data []byte) error {
  277. const maxRetries = 3
  278. buf := make([]byte, 4)
  279. // for writes the address words are in little endian order, but the bytes
  280. // within the words are in big endian order
  281. binary.BigEndian.PutUint16(buf[0:2], uint16(addr&0xFFFF))
  282. binary.BigEndian.PutUint16(buf[2:4], uint16(addr>>16&0xFFFF))
  283. buf = append(buf, data...)
  284. var err error
  285. for r := 0; r < maxRetries; r++ {
  286. if r > 0 {
  287. fmt.Printf("CmdWriteMemory: write failed: %v. Retrying.\n", err)
  288. }
  289. err = m.receiver.DoAckCommand(MonCmdWriteMem, buf)
  290. if err == nil {
  291. break
  292. }
  293. }
  294. if err != nil {
  295. return err
  296. }
  297. return nil
  298. }
  299. // Jump calls the monitor's jump command.
  300. func (m *Monitor) CmdJump(addr uint32) error {
  301. if !m.inMonitor {
  302. return fmt.Errorf("receiver not in monitor")
  303. }
  304. b := make([]byte, 4)
  305. binary.BigEndian.PutUint32(b[0:4], addr)
  306. return m.receiver.DoAckCommand(MonCmdJmp, b)
  307. }
  308. // ResetReceiver calls the monitor's reset command.
  309. func (m *Monitor) CmdResetReceiver() error {
  310. if !m.inMonitor {
  311. return fmt.Errorf("receiver not in monitor")
  312. }
  313. err := m.receiver.SendStxEtxRequest(MonCmdReset, []byte{})
  314. if err != nil {
  315. return err
  316. }
  317. m.inMonitor = false
  318. // it seems that if I switch the baud rate too soon, the UART will still
  319. // be transmitting the above data, which will corrupt the command.
  320. time.Sleep(2 * time.Second)
  321. // revert the serial port
  322. err = m.receiver.useUserBaudRate()
  323. if err != nil {
  324. return err
  325. }
  326. return nil
  327. }
  328. // ReceiverInfo holds all the information we can glean from the receiver by
  329. // probing its memory.
  330. type ReceiverInfo struct {
  331. Name1 string
  332. Name2 string
  333. SerialNumber int
  334. SerialNumberString string
  335. OptionMemory []byte
  336. ConfigMemory []byte
  337. FirmwareDate time.Time
  338. FirmwareVersionMajor int
  339. FirmwareVersionMinor int
  340. FirmwareVersion float64
  341. ReceiverType ReceiverType
  342. Code1Start uint32
  343. Code1End uint32
  344. Code1Checksum uint32
  345. Code2Start uint32
  346. Code2End uint32
  347. Code2Checksum uint32
  348. }
  349. // PrintOptions emulates the output of the loader.exe 'O' monitor mode command
  350. func (info *ReceiverInfo) PrintOptions() {
  351. // Print receiver identity information
  352. fmt.Printf(" name1:%s\n", info.Name1)
  353. fmt.Printf(" name2:%s\n", info.Name2)
  354. fmt.Printf("ASCII serial #:%14s\n", info.SerialNumberString)
  355. fmt.Printf(" int serial #:%14d\n", info.SerialNumber)
  356. // Print Header
  357. for i := 0; i <= 48; i += 12 {
  358. fmt.Printf("Options %02d-%02d ", i, i+11)
  359. }
  360. fmt.Printf("\n")
  361. // Print option values
  362. optNames := []string{
  363. "opt #00", "opt #01", "Locator", "opt #03", "RTCMAsci", "CyclPrnt", "PosStats", "TailBuoy", "PFinder", "LandSeis", "RTCMnetw", "CarPhDis",
  364. "Caltrans", "MxL1only", "RmtDnlod", "Demo", "opt #16", "RT17dsab", "LclDatum", "opt #19", "DualFreq", "SerPorts", "MulDatum", "ExtFreq",
  365. "EventMrk", "1PPS", "opt #26", "opt #27", "RTCM in", "RTCM out", "SyncLimt", "NMEA out", "NGS", "opt #33", "MultWYPT", "LctrCrPh",
  366. "Kinematc", "Config'd", "MemLimit", "RTK-L1", "RTK-OTF", "IONOFREE", "opt #42", "opt #43", "opt #44", "opt #45", "opt #46", "opt #47",
  367. "opt #48", "opt #49", "opt #50", "opt #51", "opt #52", "opt #53", "opt #54", "opt #55", "opt #56", "opt #57", "opt #58", "opt #59",
  368. }
  369. for i := 0; i < 12; i++ {
  370. for j := i; j <= i+48; j += 12 {
  371. fmt.Printf("$%02x-%-11s", info.OptionMemory[j], optNames[j])
  372. }
  373. fmt.Printf("\n")
  374. }
  375. }
  376. func (info *ReceiverInfo) PrintVersions() {
  377. // TODO: empty string in param 3 should say '(TEST)' when in test mode
  378. fmt.Printf(" Code Version: %1d.%02d %s Date: %s\n", info.FirmwareVersionMajor, info.FirmwareVersionMinor, "", info.FirmwareDate.Format("02-Jan-06"))
  379. fmt.Printf(" Code1: %06X-%06X Code2: %06X-%06X\n", info.Code1Start, info.Code1End-1, info.Code2Start, info.Code2End-1)
  380. fmt.Printf("Checksums: %06X %06X\n", info.Code1Checksum, info.Code2Checksum)
  381. }
  382. // GetReceiverInfo reads receiver information out of the receiver. Unlike GetOptions
  383. // and GetRuntimeConfig, this reads the values straight out of memory.
  384. func (m *Monitor) GetReceiverInfo() (*ReceiverInfo, error) {
  385. if !m.inMonitor {
  386. return nil, fmt.Errorf("receiver not in monitor")
  387. }
  388. info := &ReceiverInfo{}
  389. // Read the receiver-specific configuration.
  390. // 0x80600 and 0x22d both contain the same data, but for some reason some
  391. // code reads from one area and some from the other.
  392. b, err := m.ReadMemory(0x80600, 0x97) // or 0x80600? I'm so confused.
  393. if err != nil {
  394. return nil, err
  395. }
  396. info.Name1 = cStrtoGoStr(b[60:96])
  397. info.Name2 = cStrtoGoStr(b[96:132])
  398. info.SerialNumberString = cStrtoGoStr(b[132:147])
  399. info.SerialNumber = int(binary.BigEndian.Uint32(b[147:151]))
  400. info.OptionMemory = b[0:60]
  401. info.ReceiverType = m.receiverType
  402. configBase := uint32(0x000001F0)
  403. // read the configuration memory
  404. b, err = m.ReadMemory(configBase, 0x3A)
  405. if err != nil {
  406. return nil, err
  407. }
  408. info.ConfigMemory = b
  409. date := int(binary.BigEndian.Uint32(info.ConfigMemory[0x222-configBase:]))
  410. month := date / 10000
  411. day := date / 100 % 100
  412. year := date % 100
  413. if year >= 80 {
  414. year += 1900
  415. } else {
  416. year += 2000
  417. }
  418. info.FirmwareDate = time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
  419. ver := int(binary.BigEndian.Uint16(info.ConfigMemory[0x204-configBase:]))
  420. info.FirmwareVersionMajor = ver / 100
  421. info.FirmwareVersionMinor = ver % 100
  422. info.FirmwareVersion = float64(ver) / 100
  423. info.Code1Start = binary.BigEndian.Uint32(info.ConfigMemory[0x1f0-configBase:])
  424. info.Code1End = binary.BigEndian.Uint32(info.ConfigMemory[0x1f4-configBase:])
  425. info.Code2Start = binary.BigEndian.Uint32(info.ConfigMemory[0x1f8-configBase:])
  426. info.Code2End = binary.BigEndian.Uint32(info.ConfigMemory[0x1fc-configBase:])
  427. // read checksums
  428. b, err = m.ReadMemory(info.Code1End-12, 4)
  429. if err != nil {
  430. return nil, err
  431. }
  432. info.Code1Checksum = binary.BigEndian.Uint32(b)
  433. b, err = m.ReadMemory(info.Code2End-12, 4)
  434. if err != nil {
  435. return nil, err
  436. }
  437. info.Code2Checksum = binary.BigEndian.Uint32(b)
  438. if info.FirmwareVersion > 5.60 {
  439. }
  440. return info, nil
  441. }
  442. func cStrtoGoStr(b []byte) string {
  443. i := bytes.IndexByte(b, 0)
  444. if i < 0 {
  445. return string(b)
  446. }
  447. return string(b[:i])
  448. }
  449. type RuntimeConfig struct {
  450. SerialNumber string
  451. ReceiverType string
  452. NavProcessVersion float64
  453. SigProcessVersion float64
  454. BootRomVersion float64
  455. AntennaSerial string
  456. AntennaType string
  457. Channels string
  458. ChannelsL1 string
  459. }
  460. func progressBar(width, progress, total int) string {
  461. progressBlocks := []rune{'▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'}
  462. p := float64(progress) / float64(total)
  463. blocks := int(float64(width) * p)
  464. eighths := int(float64(width)*p*8) % 8
  465. bar := strings.Repeat("█", blocks)
  466. blankWidth := width - blocks - 1
  467. if blankWidth < 0 {
  468. blankWidth = 0
  469. }
  470. blank := strings.Repeat("-", blankWidth)
  471. return fmt.Sprintf("(%0.2f%%) %s%c%s\n", p*100, bar, progressBlocks[eighths], blank)
  472. }
  473. type codeBlock struct {
  474. start uint32
  475. end uint32
  476. }
  477. func (m *Monitor) CaptureReceiverFirmware() (*dotx.DotXFile, error) {
  478. info, err := m.GetReceiverInfo()
  479. if err != nil {
  480. return nil, err
  481. }
  482. dotX := dotx.NewDotX()
  483. // these chip selects are hard-coded into the first two records in the file
  484. dotX.AddBlock(0x00FFFA54, []byte{0x70, 0x07, 0x78, 0x71})
  485. dotX.AddBlock(0x00FFFA46, []byte{0x03, 0xF5})
  486. // then the code blocks
  487. codeBlocks := []*dotx.Block{
  488. {StartAddr: info.Code1Start, EndAddr: info.Code1End},
  489. {StartAddr: info.Code2Start, EndAddr: info.Code2End},
  490. }
  491. totalBytes := 0
  492. for _, cb := range codeBlocks {
  493. totalBytes += cb.Len()
  494. }
  495. bytesWriten := 0
  496. for _, block := range codeBlocks {
  497. blockLen := block.Len()
  498. b, err := m.ReadMemory(block.StartAddr, blockLen)
  499. if err != nil {
  500. return nil, err
  501. }
  502. block.Bytes = b
  503. dotX.Blocks = append(dotX.Blocks, block)
  504. bytesWriten += blockLen
  505. }
  506. // func(i uint32) {
  507. // fmt.Printf("$%08X %s\r", i, progressBar(50, int(i-block.StartAddr)+bytesWriten, totalBytes))
  508. // }
  509. return dotX, nil
  510. }
  511. func (m *Monitor) CmdGetRuntimeConfig() (*RuntimeConfig, error) {
  512. if m.inMonitor {
  513. return nil, fmt.Errorf("receiver not in normal mode")
  514. }
  515. r, err := m.receiver.DoStxEtxCommand(NrmCmdGetSerial, []byte{})
  516. if err != nil {
  517. return nil, err
  518. }
  519. if r.Command != NrmCmdRSerial || r.Status != 0 {
  520. return nil, newProtocolError("unexpected response from read memory")
  521. }
  522. conf := &RuntimeConfig{}
  523. conf.SerialNumber = strings.TrimSpace(cStrtoGoStr(r.Data[0:8]))
  524. conf.ReceiverType = strings.TrimSpace(cStrtoGoStr(r.Data[8:16]))
  525. conf.NavProcessVersion, _ = strconv.ParseFloat(cStrtoGoStr(r.Data[16:21]), 64)
  526. conf.NavProcessVersion /= 100
  527. conf.SigProcessVersion, _ = strconv.ParseFloat(cStrtoGoStr(r.Data[21:26]), 64)
  528. conf.SigProcessVersion /= 100
  529. conf.BootRomVersion, _ = strconv.ParseFloat(cStrtoGoStr(r.Data[26:31]), 64)
  530. conf.BootRomVersion /= 100
  531. conf.AntennaSerial = strings.TrimSpace(cStrtoGoStr(r.Data[31:39]))
  532. conf.AntennaType = strings.TrimSpace(cStrtoGoStr(r.Data[39:41]))
  533. conf.Channels = strings.TrimSpace(cStrtoGoStr(r.Data[41:43]))
  534. conf.ChannelsL1 = strings.TrimSpace(cStrtoGoStr(r.Data[43:45]))
  535. return conf, nil
  536. }
  537. type Options struct {
  538. ElevationMask int
  539. PDOPMask float64
  540. SyncTime float64
  541. FastestMeasRate float64
  542. CurrentPortID int
  543. PortsAvailable int
  544. L1L2Operation int
  545. CarrierPhase bool
  546. KinematicMode bool
  547. LocatorMode bool
  548. PowerUpOption bool
  549. RTKOption bool
  550. NMEA0183Outputs bool
  551. RTCM1Input bool
  552. RTCM2Input bool
  553. RTCM1Output bool
  554. RTCM2Output bool
  555. NavOption bool
  556. FirmwareUpdate bool
  557. EventMarker int
  558. PulsePerSec int
  559. ExtTimeInput int
  560. CoCOM bool
  561. MemoryInstalled int
  562. MemoryUsed int
  563. RTCMNetwork bool
  564. DataFormat int
  565. DataOffset int
  566. PositionStatistics bool
  567. RemoteDownload bool
  568. LocalDatums bool
  569. RealTimeSurveyData bool
  570. CalTrans bool
  571. ReceiverType int
  572. }
  573. func (m *Monitor) CmdGetOptions() (*Options, error) {
  574. if m.inMonitor {
  575. return nil, fmt.Errorf("receiver not in normal mode")
  576. }
  577. r, err := m.receiver.DoStxEtxCommand(NrmCmdGetOpt, []byte{})
  578. if err != nil {
  579. return nil, err
  580. }
  581. if r.Command != NrmCmdRetOpt || r.Status != 0 {
  582. return nil, newProtocolError("unexpected response from read memory")
  583. }
  584. opts := &Options{
  585. ElevationMask: int(r.Data[0]),
  586. PDOPMask: float64(r.Data[1]) * 0.1,
  587. SyncTime: float64(binary.BigEndian.Uint16(r.Data[2:4])) * 1,
  588. FastestMeasRate: float64(binary.BigEndian.Uint16(r.Data[4:6])) * .1,
  589. CurrentPortID: int(r.Data[6]),
  590. PortsAvailable: int(r.Data[7]),
  591. L1L2Operation: int(r.Data[8]),
  592. CarrierPhase: r.Data[9] == 1,
  593. KinematicMode: r.Data[10] == 1,
  594. LocatorMode: r.Data[11] == 1,
  595. PowerUpOption: r.Data[12] == 1,
  596. RTKOption: r.Data[13] == 1,
  597. NMEA0183Outputs: r.Data[18] == 1,
  598. RTCM1Input: r.Data[19] == 1,
  599. RTCM2Input: r.Data[20] == 1,
  600. RTCM1Output: r.Data[21] == 1,
  601. RTCM2Output: r.Data[22] == 1,
  602. NavOption: r.Data[23] == 1,
  603. FirmwareUpdate: r.Data[24] == 1,
  604. EventMarker: int(r.Data[25]),
  605. PulsePerSec: int(r.Data[26]),
  606. ExtTimeInput: int(r.Data[27]),
  607. CoCOM: r.Data[28] == 1,
  608. MemoryInstalled: int(binary.BigEndian.Uint16(r.Data[29:31])),
  609. MemoryUsed: int(r.Data[31]),
  610. RTCMNetwork: r.Data[32] == 1,
  611. DataFormat: int(r.Data[34]),
  612. DataOffset: int(binary.BigEndian.Uint16(r.Data[35:37])),
  613. PositionStatistics: r.Data[37] == 1,
  614. RemoteDownload: r.Data[38] == 1,
  615. LocalDatums: r.Data[39] == 1,
  616. RealTimeSurveyData: r.Data[40] == 1,
  617. CalTrans: r.Data[41] == 1,
  618. ReceiverType: int(r.Data[44]),
  619. }
  620. return opts, nil
  621. }
  622. func (m *Monitor) ProgramReceiver(fw *dotx.DotXFile) error {
  623. fmt.Printf("Writing receiver program...\n")
  624. save := make([]byte, 8)
  625. totalBytes := fw.TotalBytes()
  626. t := 0
  627. var err error
  628. progressBarWidth := 50
  629. progressBlocks := []rune{'▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'}
  630. // set fixFailedWrite to true to have the code just correct the first 8
  631. // bytes of memory to remove the boot blocker. This is a kludge for testing.
  632. fixFailedWrite := false
  633. for i, block := range fw.Blocks {
  634. if fixFailedWrite && i > 2 {
  635. // all we want are the chip selects and CODE1
  636. continue
  637. }
  638. recs := block.ToRecords(244)
  639. fmt.Printf("Writing block %d ($%08X - $%08X)...\n", i, block.StartAddr, block.EndAddr)
  640. for _, rec := range recs {
  641. t += len(rec.Bytes)
  642. p := float64(t) / float64(totalBytes)
  643. blocks := int(float64(progressBarWidth) * p)
  644. eighths := int(float64(progressBarWidth)*p*8) % 8
  645. bar := strings.Repeat("█", blocks)
  646. blankWidth := progressBarWidth - blocks - 1
  647. if blankWidth < 0 {
  648. blankWidth = 0
  649. }
  650. blank := strings.Repeat("-", blankWidth)
  651. progressBar := fmt.Sprintf("%s%c%s", bar, progressBlocks[eighths], blank)
  652. fmt.Printf("$%08X (%0.2f%%) %s\r", rec.Addr, p*100, progressBar)
  653. if rec.Addr == 0x00000000 {
  654. // This replaces the first 8 bytes of the firmware image with
  655. // 4E72270000000000. The first 8 bytes are the stack pointer and
  656. // reset vector. The first value is actually a STOP #$2700
  657. // instruction, and the 0x00000000 reset vector means that STOP
  658. // is the only thing that will be executed. This saves the intended
  659. // value to write to memory at the end of the firmware upgrade
  660. // process, guaranteeing that the receiver will not function
  661. // with a half-baked firmware. Crafty, Trimble.
  662. b2 := make([]byte, len(rec.Bytes))
  663. copy(b2, rec.Bytes)
  664. copy(save[0:8], rec.Bytes[0:8])
  665. binary.BigEndian.PutUint32(b2[0:], 0x4E722700)
  666. binary.BigEndian.PutUint32(b2[4:], 0x00000000)
  667. err = m.WriteMemory(rec.Addr, b2)
  668. if fixFailedWrite {
  669. // for a fixFailedWrite all I care about is the first record.
  670. break
  671. }
  672. } else {
  673. err = m.WriteMemory(rec.Addr, rec.Bytes)
  674. }
  675. if err != nil {
  676. return err
  677. }
  678. if m.Dummy {
  679. time.Sleep(1 * time.Millisecond)
  680. }
  681. }
  682. fmt.Printf("% 80s\r", "")
  683. }
  684. fmt.Printf("\rDone. %d bytes written.\n", t)
  685. err = m.WriteMemory(0x00000000, save)
  686. if err != nil {
  687. return err
  688. }
  689. fmt.Printf("Rebooting receiver.\n")
  690. return m.CmdResetReceiver()
  691. }
  692. // Read implements the io.ReadSeeker interface
  693. func (m *Monitor) Read(p []byte) (n int, err error) {
  694. p, err = m.ReadMemory(m.seekPos, len(p))
  695. m.seekPos += uint32(len(p))
  696. return len(p), err
  697. }
  698. // Seek implements the io.ReadSeeker interface
  699. func (m *Monitor) Seek(offset int64, whence int) (int64, error) {
  700. var abs int64
  701. switch whence {
  702. case io.SeekStart:
  703. abs = offset
  704. case io.SeekCurrent:
  705. abs = int64(m.seekPos) + offset
  706. default:
  707. return 0, fmt.Errorf("Seek: invalid whence")
  708. }
  709. if abs < 0 {
  710. return 0, fmt.Errorf("Seek: negative position")
  711. }
  712. m.seekPos = uint32(abs)
  713. return abs, nil
  714. }
  715. func ReadMemory(f io.ReadSeeker, addr uint32, length int) ([]byte, error) {
  716. _, err := f.Seek(int64(addr), io.SeekStart)
  717. if err != nil {
  718. return nil, err
  719. }
  720. b := make([]byte, length)
  721. _, err = f.Read(b)
  722. if err != nil {
  723. return nil, err
  724. }
  725. return b, nil
  726. }
  727. type RawReceiverInfo struct {
  728. Options [60]byte
  729. Name1 [36]byte
  730. Name2 [36]byte
  731. SerialNumberString [15]byte
  732. SerialNumber uint32
  733. }
  734. // GetReceiverInfo reads receiver information out of the receiver. Unlike GetOptions
  735. // and GetRuntimeConfig, this reads the values straight out of memory.
  736. func GetReceiverInfo(f io.ReadSeeker) (*ReceiverInfo, error) {
  737. info := &ReceiverInfo{}
  738. // Read the receiver-specific configuration.
  739. // 0x80600 and 0x22d both contain the same data, but for some reason some
  740. // code reads from one area and some from the other.
  741. b, err := ReadMemory(f, 0x80600, 0x97)
  742. if err != nil {
  743. return nil, err
  744. }
  745. info.OptionMemory = b[0:60]
  746. info.Name1 = cStrtoGoStr(b[60:96])
  747. info.Name2 = cStrtoGoStr(b[96:132])
  748. info.SerialNumberString = cStrtoGoStr(b[132:147])
  749. info.SerialNumber = int(binary.BigEndian.Uint32(b[147:151]))
  750. configBase := uint32(0x000001F0)
  751. // read the configuration memory
  752. b, err = ReadMemory(f, configBase, 0x3A)
  753. if err != nil {
  754. return nil, err
  755. }
  756. info.ConfigMemory = b
  757. date := int(binary.BigEndian.Uint32(info.ConfigMemory[0x222-configBase:]))
  758. month := date / 10000
  759. day := date / 100 % 100
  760. year := date % 100
  761. if year >= 80 {
  762. year += 1900
  763. } else {
  764. year += 2000
  765. }
  766. info.FirmwareDate = time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
  767. ver := int(binary.BigEndian.Uint16(info.ConfigMemory[0x204-configBase:]))
  768. info.FirmwareVersionMajor = ver / 100
  769. info.FirmwareVersionMinor = ver % 100
  770. info.FirmwareVersion = float64(ver) / 100
  771. info.Code1Start = binary.BigEndian.Uint32(info.ConfigMemory[0x1f0-configBase:])
  772. info.Code1End = binary.BigEndian.Uint32(info.ConfigMemory[0x1f4-configBase:])
  773. info.Code2Start = binary.BigEndian.Uint32(info.ConfigMemory[0x1f8-configBase:])
  774. info.Code2End = binary.BigEndian.Uint32(info.ConfigMemory[0x1fc-configBase:])
  775. // read checksums
  776. b, err = ReadMemory(f, info.Code1End-12, 4)
  777. if err != nil {
  778. return nil, err
  779. }
  780. info.Code1Checksum = binary.BigEndian.Uint32(b)
  781. b, err = ReadMemory(f, info.Code2End-12, 4)
  782. if err != nil {
  783. return nil, err
  784. }
  785. info.Code2Checksum = binary.BigEndian.Uint32(b)
  786. if info.FirmwareVersion > 5.60 {
  787. }
  788. return info, nil
  789. }
  790. func CaptureReceiverFirmware(f io.ReadSeeker) (*dotx.DotXFile, error) {
  791. info, err := GetReceiverInfo(f)
  792. if err != nil {
  793. return nil, err
  794. }
  795. dotX := dotx.NewDotX()
  796. // these chip selects are hard-coded into the first two records in the file
  797. dotX.AddBlock(0x00FFFA54, []byte{0x70, 0x07, 0x78, 0x71})
  798. dotX.AddBlock(0x00FFFA46, []byte{0x03, 0xF5})
  799. // then the code blocks
  800. codeBlocks := []*dotx.Block{
  801. {StartAddr: info.Code1Start, EndAddr: info.Code1End},
  802. {StartAddr: info.Code2Start, EndAddr: info.Code2End},
  803. }
  804. totalBytes := 0
  805. for _, cb := range codeBlocks {
  806. totalBytes += cb.Len()
  807. }
  808. bytesWriten := 0
  809. for _, block := range codeBlocks {
  810. blockLen := block.Len()
  811. b, err := ReadMemory(f, block.StartAddr, blockLen)
  812. if err != nil {
  813. return nil, err
  814. }
  815. block.Bytes = b
  816. dotX.Blocks = append(dotX.Blocks, block)
  817. bytesWriten += blockLen
  818. }
  819. return dotX, nil
  820. }