summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2013-07-07 01:48:13 +0000
committerChristian Pointner <equinox@spreadspace.org>2013-07-07 01:48:13 +0000
commitfc547cad2fffcaa354b170694796beddf37dd4a1 (patch)
tree3d94e7692ce139cf11e29f401a4a73356b136971
parentskipping 'invalid' code doesn't work on some hardware (diff)
added length field for messages
git-svn-id: https://svn.spreadspace.org/pic/trunk@46 a09c6847-51d9-44de-8ef2-e725cf50f3c7
-rw-r--r--bootloader/bootloader.asm129
-rwxr-xr-xdownloader/downloader.py53
-rw-r--r--downloader/proto.txt52
3 files changed, 104 insertions, 130 deletions
diff --git a/bootloader/bootloader.asm b/bootloader/bootloader.asm
index f8b609c..ff23d61 100644
--- a/bootloader/bootloader.asm
+++ b/bootloader/bootloader.asm
@@ -37,11 +37,10 @@ VERSION_MAJ EQU .0
VERSION_MIN EQU .1
DEVID_H EQU H'20'
DEVID_L EQU H'82'
-FSS EQU .16
-MESS_H EQU .0
-MESS_L EQU .64
+FSS EQU .16 ; writing is done 8 words at a time but 16 words get erased
+MESS EQU .64 ; this limit is because of to combuff size and single byte len field for messages
SUPPORTED_H EQU .0
-SUPPORTED_L EQU b'00011110' ; read/write flash, read/write eeprom
+SUPPORTED_L EQU b'00000110' ; only read/write flash is supported by now
;; ERROR codes
E_OK EQU .0
@@ -76,7 +75,7 @@ current_cmdlen EQU H'0070'
csum EQU H'0071'
flags EQU H'007D'
-#define F_WEEP flags,0
+#define F_NEW_CMD flags,0
cnt2 EQU H'007E'
cnt1 EQU H'007F'
@@ -104,6 +103,9 @@ uart_tx_byte
return
send_answer
+ addlw .3
+ movwf combuff + .1
+ decf combuff + .1,w
movwf cnt1
movlw combuff
movwf FSR
@@ -119,19 +121,6 @@ send_answer_next
call uart_tx_byte
return
-get_cmdlen
- addwf PCL,f
- retlw .0 ; invalid
- retlw .1 ; identify: <csum>
- retlw .1 ; boot: <csum>
- retlw .1 ; reset: <csum>
- retlw .3 ; read flash: addr | <csum>
- retlw .3 + .2*FSS ; write flash: addr | data | <csum>
- retlw .5 ; read eeprom: addr | len | <csum>
- retlw .5 ; write eeprom: addr | len | data | <csum> (minimal)
- retlw .2 ; read config: nr | <csum>
- retlw .4 ; write config: nr | word | <csum>
-
get_name
addwf PCL,f
nop
@@ -197,6 +186,8 @@ uart_rx_byte ; process received command
movf RCREG,w
movwf INDF
incf FSR,f
+ btfss F_NEW_CMD
+ goto wait_cmd_len
movf current_cmdlen,f
btfsc STATUS,Z
goto new_cmd
@@ -208,39 +199,43 @@ uart_rx_fe ; recover from framing error
movf RCREG,w
goto wait_new_cmd
+wait_cmd_len
+ bsf F_NEW_CMD
+ goto wait_cmd
+
new_cmd ; got new command code
movf combuff,w
sublw CMD_MAX
btfss STATUS,C
goto invalid_cmd
- movf combuff,w
- call get_cmdlen
+ decfsz combuff + .1,w
+ goto load_cmdlen
+ goto invalid_cmd
+load_cmdlen
movwf current_cmdlen
+ decfsz current_cmdlen,f
goto wait_cmd
-
-invalid_cmd ; received command code is not known
+invalid_cmd ; received command code is not known or len is bogus
movlw E_INV_CMD
- movwf combuff + .1
- movlw .2
+ movwf combuff + .2
+ movlw .1
call send_answer
goto wait_new_cmd
exec_cmd ; command is correct and complete
- ;; TODO: check csum -> csum for write eeprom will not be correct because
- ;; it isn't finished yet....???
+ ;; TODO: check csum
movf combuff,w ; dispatch commands
addwf PCL,f
goto wait_new_cmd
- goto cmd_identify
- goto cmd_boot
- goto cmd_reset
- goto cmd_r_flash
- goto cmd_w_flash
- goto cmd_r_eeprom
- goto cmd_w_eeprom
- goto cmd_r_config
- goto cmd_w_config
- goto wait_new_cmd
+ goto cmd_identify ; identify
+ goto cmd_boot ; boot
+ goto cmd_not_impl ; reset
+ goto cmd_r_flash ; read flash segment
+ goto cmd_w_flash ; write flash segment
+ goto cmd_not_impl ; read eeprom
+ goto cmd_not_impl ; write eeprom
+ goto cmd_not_impl ; read config
+ goto cmd_not_impl ; write config
;; ** Command Handlers ********************
;; ** identify *******
@@ -249,6 +244,9 @@ cmd_identify
movf combuff,w
call uart_tx_byte
+ movlw .22
+ call uart_tx_byte
+
movlw E_OK
call uart_tx_byte
@@ -273,10 +271,7 @@ cmd_identify_send_name
movlw FSS
call uart_tx_byte
-
- movlw MESS_L
- call uart_tx_byte
- movlw MESS_H
+ movlw MESS
call uart_tx_byte
movlw SUPPORTED_L
@@ -291,8 +286,8 @@ cmd_identify_send_name
;; ** boot *******
cmd_boot
movlw E_OK
- movwf combuff + .1
- movlw .2
+ movwf combuff + .2
+ movlw .1
call send_answer
goto USERVECT
@@ -308,39 +303,11 @@ cmd_w_flash
call send_answer
goto wait_new_cmd
- ;; ** read eeprom *******
-cmd_r_eeprom
- ;; call read_eeprom
- movlw E_ADDR_INVALID
- movwf combuff + .1
- movlw .2
- call send_answer
- goto wait_new_cmd
-
- ;; ** write eeprom *******
-cmd_w_eeprom
- btfss F_WEEP
- goto cmd_w_eeprom_len
- ;; call write_eeprom
- movlw E_ADDR_INVALID
- movwf combuff + .1
- movlw .2
- call send_answer
- goto wait_new_cmd
-
-cmd_w_eeprom_len
- movf combuff + .3,w
- movwf current_cmdlen
- bsf F_WEEP
- goto wait_cmd
-
;; ** not implemented commands *******
-cmd_reset
-cmd_r_config
-cmd_w_config
+cmd_not_impl
movlw E_NOT_IMPL
- movwf combuff + .1
- movlw .2
+ movwf combuff + .2
+ movlw .1
call send_answer
goto wait_new_cmd
@@ -352,7 +319,7 @@ read_flash_segment
movwf cnt1
movlw b'01011000'
movwf STATUS
- movlw combuff + .1
+ movlw combuff + .2
movwf FSR
movf INDF,w
movwf EEADR
@@ -379,8 +346,8 @@ read_flash_segment_next
decfsz cnt1,f
goto read_flash_segment_loop
bcf STATUS,RP1
- clrf combuff + .1 ; = E_OK
- retlw .2 + .2*FSS ; bytes to send
+ clrf combuff + .2 ; = E_OK
+ retlw .1 + .2*FSS ; bytes to send
;; flash write --------
write_flash_segment
@@ -388,7 +355,7 @@ write_flash_segment
movwf cnt1
movlw b'01011000'
movwf STATUS
- movlw combuff + .1
+ movlw combuff + .2
movwf FSR
movf INDF,w
movwf EEADR
@@ -397,7 +364,7 @@ write_flash_segment
movwf EEADRH
write_flash_segment_loop
- incf FSR,f ; load data into EEDAT:EEDATH
+ incf FSR,f ; load code word into EEDAT:EEDATH
movf INDF,w
movwf EEDAT
incf FSR,f
@@ -423,13 +390,13 @@ write_flash_segment_next
decfsz cnt1,f
goto write_flash_segment_loop
bsf STATUS,RP0
- clrw
+ clrw ; check if a write error occured
btfsc EECON1,WRERR
movlw E_FLASH_WERR
bcf STATUS,RP1
bcf STATUS,RP0
- movwf combuff + .1 ; = E_OK
- retlw .2 ; bytes to send
+ movwf combuff + .2 ; = E_OK
+ retlw .1 ; bytes to send
;; -------------------------------------
;; -------------------------------------
diff --git a/downloader/downloader.py b/downloader/downloader.py
index 9efb30e..f90eced 100755
--- a/downloader/downloader.py
+++ b/downloader/downloader.py
@@ -100,7 +100,7 @@ def calc_csum(str):
cs ^= c
return cs
-def exec_command(dev, cmd, answer):
+def exec_command(dev, cmd, param, answer):
import struct
return_codes = { 0: "OK", 1: "invalid command", 2: "bad checksum",
@@ -108,21 +108,22 @@ def exec_command(dev, cmd, answer):
5: "address invalid", 6: "address prohibited",
7: "value out of bounds" }
- cstr = bytearray(cmd)
+ cstr = bytearray(struct.pack('<BB', cmd, 0) + param)
cstr.extend(struct.pack("<B", calc_csum(cstr)))
+ cstr[1] = len(cstr)
dev.write(cstr)
astr = bytearray()
- astr += dev.read(3)
- if len(astr) < 3:
- print "ERROR: timeout while reading response header"
+ astr += dev.read(4)
+ if len(astr) < 4:
+ print "ERROR: timeout while reading response header (expected %d bytes, got %d)" % (4, len(astr))
sys.exit(4)
if astr[0] != cstr[0]:
print "ERROR: bootloader returned wrong command code"
sys.exit(4)
- ret = astr[1]
+ ret = astr[2]
if ret != 0:
rstr = "invalid return code"
try:
@@ -132,12 +133,16 @@ def exec_command(dev, cmd, answer):
print "ERROR: bootloader returned %d: %s" % (ret, rstr)
sys.exit(4)
- answer_len = struct.calcsize(answer)
+ answer_len = astr[1] - 4
+ if answer_len < struct.calcsize(answer):
+ print "ERROR: short answer %d bytes received: expected %s bytes" % (answer_len, struct.calcsize(answer))
+ sys.exit(4)
+
if answer_len > 0:
tmp = bytearray()
tmp += dev.read(answer_len)
if len(tmp) < answer_len:
- print "ERROR: timeout while reading response"
+ print "ERROR: timeout while reading response (expected %d bytes, got %d)" % (answer_len, len(tmp))
sys.exit(4)
astr += tmp
@@ -146,12 +151,12 @@ def exec_command(dev, cmd, answer):
print "ERROR: checksum error"
sys.exit(4)
- return struct.unpack_from(answer, astr, 2)
+ return struct.unpack_from(answer, astr, 3)
### Commands
def identify(dev):
- data = exec_command(dev, struct.pack('<B', 1), '<BB10sHBHH')
+ data = exec_command(dev, 1, '', '<BB10sHBBH')
id = { 'ver_min': data[0], 'ver_maj': data[1], 'name': data[2], 'devid': data[3],
'fss': data[4], 'mess': data[5], 'supported': data[6] }
@@ -166,35 +171,35 @@ def identify(dev):
return id
def boot(dev):
- exec_command(dev, struct.pack('<B', 2), '<')
+ exec_command(dev, 2, '', '<')
def reset(dev, id):
- exec_command(dev, struct.pack('<B', 3), '<')
+ exec_command(dev, 3, '', '<')
def read_flash_segment(dev, id, addr):
- cmd = struct.pack('<BH', 4, addr)
- return exec_command(dev, cmd, '<%dH' % id['fss'])
+ param = struct.pack('<H', addr)
+ return exec_command(dev, 4, param, '<%dH' % id['fss'])
def write_flash_segment(dev, id, addr, data):
- cmd = struct.pack('<BH%dH' % id['fss'], 5, addr, *data)
- return exec_command(dev, cmd, '<')
+ param = struct.pack('<H%dH' % id['fss'], addr, *data)
+ return exec_command(dev, 5, param, '<')
def read_eeprom(dev, id, addr, len):
- cmd = struct.pack('<BHH', 6, addr, len)
- return exec_command(dev, cmd, '<%dB' % len)
+ param = struct.pack('<HB', addr, len)
+ return exec_command(dev, 6, param, '<%dB' % len)
def write_eeprom(dev, id, addr, data):
- cmd = struct.pack('<BHH%dB' % len(data), 7, addr, len(data), *data)
- return exec_command(dev, cmd, '<')
+ param = struct.pack('<HB%dB' % len(data), addr, len(data), *data)
+ return exec_command(dev, 7, param, '<')
def read_config(dev, id, nr):
- cmd = struct.pack('<BB', 8, nr)
- data = exec_command(dev, cmd, '<H')
+ param = struct.pack('<B', nr)
+ data = exec_command(dev, 8, param, '<H')
return data[0]
def write_config(dev, id, nr, word):
- cmd = struct.pack('<BBH', 9, nr, word)
- return exec_command(dev, cmd, '<')
+ param = struct.pack('<BH', nr, word)
+ return exec_command(dev, 9, param, '<')
### Main
diff --git a/downloader/proto.txt b/downloader/proto.txt
index e85368e..17dec93 100644
--- a/downloader/proto.txt
+++ b/downloader/proto.txt
@@ -17,11 +17,13 @@ Command List:
Description:
------------
-Every command consits of one byte command code, a fixed number of bytes as
-arguments and ends with a XOR checksum over all bytes sent. All data is
+Every command consits of one byte command code, one byte length which counts all
+bytes of the command including the command code and checksum. The length is followed
+by zero or more data and a XOR checksum over all bytes sent. All data is
transferred LSB first (aka little endian). All addresses and words are 2bytes long.
-Every answer to a command starts with the command code. One byte return value,
-optionally some data and a checksum (XOR over all bytes received)
+Every answer to a command starts with the command code a length field which counts all
+bytes of the answer, one byte return value optionally some data and a checksum
+(XOR over all bytes received).
The return codes have the following meaning:
code | Error
@@ -38,10 +40,10 @@ The return codes have the following meaning:
identify:
~~~~~~~~~
command:
- 1 | <csum> (in this case <csum> will always be 1)
+ 1 | len=3 | <csum>
answer:
- 1 | <ret> | version | name | devid | fss | mess | supported | <csum>
+ 1 | len=22 | <ret> | version | name | devid | fss | mess | supported | <csum>
version:
2bytes, protocol version
@@ -64,7 +66,7 @@ identify:
operation first.
mess:
- 2bytes, maximum eeprom segment size
+ 1byte, maximum eeprom segment size
This represents the maximum number of eeprom bytes which may be written or
read at once. Unlike <fss> value it is ok to write or read less than <mess>
bytes.
@@ -89,10 +91,10 @@ boot:
~~~~~
command:
- 2 | <csum> (in this case <csum> will always be 2)
+ 2 | len=3 | <csum>
answer:
- 2 | <ret> | <csum>
+ 2 | len=4 | <ret> | <csum>
This instucts the bootloader to boot to the user application directly (no reset)
@@ -101,10 +103,10 @@ reset:
~~~~~~
command:
- 3 | <csum> (in this case <csum> will always be 3)
+ 3 | len=3 | <csum>
answer:
- 3 | <ret> | <csum>
+ 3 | len=4 | <ret> | <csum>
The device performs a reboot. If the boot condition (i.e.: port pin) is not met
this instructs the device to boot to the user application.
@@ -114,10 +116,10 @@ read flash:
~~~~~~~~~~~
command:
- 4 | addr | <csum>
+ 4 | len=5 | addr | <csum>
answer:
- 4 | <ret> | data | <csum>
+ 4 | len=4+2*<fss> | <ret> | data | <csum>
The bootloader reads <fss> words from flash address <addr> and returns it as
<data>.
@@ -127,10 +129,10 @@ write flash:
~~~~~~~~~~~~
command:
- 5 | addr | data | <csum>
+ 5 | len=5+2*<fss> | addr | data | <csum>
answer:
- 5 | <ret> | <csum>
+ 5 | len=4 | <ret> | <csum>
The bootloader writes <data> (which has to contain exactly <fss> words) to address
<addr> inside the flash. The start address has to be aligned to <fss> boundaries.
@@ -142,36 +144,36 @@ read eeprom:
~~~~~~~~~~~~
command:
- 6 | addr | len | <csum>
+ 6 | len=5 | addr | len | <csum>
answer:
- 6 | <ret> | data | <csum>
+ 6 | len=4+<len> | <ret> | data | <csum>
The bootloader reads <len> bytes from eeprom at address <addr> and returns it as
- <data>. len is 2bytes long.
+ <data>. len is 1byte long.
write eeprom:
~~~~~~~~~~~~~
command:
- 7 | addr | len | data | <csum>
+ 7 | len=4+2<len(data) | addr | data | <csum>
answer:
- 7 | <ret> | <csum>
+ 7 | len=4 | <ret> | <csum>
The bootloader writes <data> (which has to contain exactly <len> bytes) to address
- <addr> inside the eeprom. len is 2bytes long and the value must not exceed <mess> bytes.
+ <addr> inside the eeprom. len is 1byte long and the value must not exceed <mess> bytes.
read config:
~~~~~~~~~~~~
command:
- 8 | nr | <csum>
+ 8 | len=3 | nr | <csum>
answer:
- 8 | <ret> | word | <csum>
+ 8 | len=6 | <ret> | word | <csum>
The bootloader reads and returns the configuration word number <nr>. <nr> is one
byte long.
@@ -181,10 +183,10 @@ write config:
~~~~~~~~~~~~~
command:
- 9 | nr | word | <csum>
+ 9 | len=5 | nr | word | <csum>
answer:
- 9 | <ret> | <csum>
+ 9 | len=4 | <ret> | <csum>
The bootloader writes <word> onto configuration word number <nr>. <nr> is one
byte long.