summaryrefslogtreecommitdiff
path: root/software/pic.bootloader
diff options
context:
space:
mode:
authorChristian Pointner <equinox@mur.at>2013-07-10 03:57:48 +0000
committerChristian Pointner <equinox@mur.at>2013-07-10 03:57:48 +0000
commit297ac49867b750bfeeeca3a354619c527468cc41 (patch)
tree25a2964671a5fa0a273dc56c5b9ac30ec0e28d17 /software/pic.bootloader
parentfixed comment (diff)
added bootloader for IHU
git-svn-id: https://svn.spreadspace.org/mur.sat@807 7de4ea59-55d0-425e-a1af-a3118ea81d4c
Diffstat (limited to 'software/pic.bootloader')
-rw-r--r--software/pic.bootloader/Makefile31
-rw-r--r--software/pic.bootloader/Makefile-IHU26
-rw-r--r--software/pic.bootloader/bootloader-IHU.asm96
-rw-r--r--software/pic.bootloader/cmds-16f887.inc117
-rw-r--r--software/pic.bootloader/com-16f887-uart.inc75
-rwxr-xr-xsoftware/pic.bootloader/downloader.py339
-rw-r--r--software/pic.bootloader/generic-defines.inc50
-rw-r--r--software/pic.bootloader/generic-init.inc61
-rw-r--r--software/pic.bootloader/generic-mainloop.inc174
-rw-r--r--software/pic.bootloader/ihexpic.py405
-rw-r--r--software/pic.bootloader/proto.txt200
11 files changed, 1574 insertions, 0 deletions
diff --git a/software/pic.bootloader/Makefile b/software/pic.bootloader/Makefile
new file mode 100644
index 0000000..fb91150
--- /dev/null
+++ b/software/pic.bootloader/Makefile
@@ -0,0 +1,31 @@
+##
+## spreadspace pic utils
+##
+##
+## Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+##
+## This file is part of spreadspace pic utils.
+##
+## spreadspace pic utils is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## any later version.
+##
+## spreadspace pic utils is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+ifndef TARGET
+$(error You need to specify a target, call make with TARGET=xyz)
+endif
+
+all:
+ $(MAKE) -f Makefile-$(TARGET) $@
+
+%:
+ $(MAKE) -f Makefile-$(TARGET) $@
diff --git a/software/pic.bootloader/Makefile-IHU b/software/pic.bootloader/Makefile-IHU
new file mode 100644
index 0000000..4689f83
--- /dev/null
+++ b/software/pic.bootloader/Makefile-IHU
@@ -0,0 +1,26 @@
+##
+## spreadspace pic utils
+##
+##
+## Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+##
+## This file is part of spreadspace pic utils.
+##
+## spreadspace pic utils is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## any later version.
+##
+## spreadspace pic utils is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+##
+
+PROJECT := bootloader-IHU
+PROC_TYPE := 16F887
+
+include ../pic.include.mk
diff --git a/software/pic.bootloader/bootloader-IHU.asm b/software/pic.bootloader/bootloader-IHU.asm
new file mode 100644
index 0000000..bdf56f8
--- /dev/null
+++ b/software/pic.bootloader/bootloader-IHU.asm
@@ -0,0 +1,96 @@
+ ;;
+ ;; spreadspace pic utils
+ ;;
+ ;;
+ ;; Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+ ;;
+ ;; This file is part of spreadspace pic utils.
+ ;;
+ ;; spreadspace pic utils is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation, either version 3 of the License, or
+ ;; any later version.
+ ;;
+ ;; spreadspace pic utils is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ;; GNU General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+ ;;
+ ;; -------------------------------------
+ ;; PREAMBLE
+
+ LIST p=16F887
+ include "p16f887.inc"
+ __config _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_NSLEEP & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC
+ __config _CONFIG2, _BOR21V & _WRT_256
+
+ ;; -------------------------------------
+ ;; DEFINES (chip/com specific)
+#define BOOTPIN PORTA,4
+USERVECT EQU H'100'
+ISRVECT EQU USERVECT + H'4'
+FLASH_BOUNDARY EQU b'00001111' ; flash write boundary is at 16 bytes boundaries
+
+VERSION_MAJ EQU .0
+VERSION_MIN EQU .1
+NAME_0 EQU 'I'
+NAME_1 EQU 'H'
+NAME_2 EQU 'U'
+DEVID_L EQU H'82'
+DEVID_H EQU H'20'
+FLASH_SIZE_L EQU H'00'
+FLASH_SIZE_H EQU H'20' ; 0x2000 -> 8192 Words of Flash
+FSS EQU .16 ; writing is done 8 words at a time but 16 words get erased
+EEPROM_SIZE_L EQU H'00'
+EEPROM_SIZE_H EQU H'01' ; 0x0100 -> 256 Bytes of EEPROM
+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'00000110' ; only read/write flash is supported by now
+
+#define HOOK_CMD_RESET cmd_not_impl
+#define HOOK_CMD_R_FLASH cmd_r_flash
+#define HOOK_CMD_W_FLASH cmd_w_flash
+#define HOOK_CMD_R_EEPROM cmd_not_impl
+#define HOOK_CMD_W_EEPROM cmd_not_impl
+#define HOOK_CMD_R_CONFIG cmd_not_impl
+#define HOOK_CMD_W_CONFIG cmd_not_impl
+
+ ;; Variables
+combuff EQU H'0020'
+current_cmdlen EQU H'0070'
+csum EQU H'0071'
+flags EQU H'007D'
+cnt EQU H'007F'
+
+ ;; -------------------------------------
+ ;; DEFINES (defines)
+#include "generic-defines.inc"
+
+ ;; -------------------------------------
+ ;; Bootloader init
+#include "generic-init.inc"
+
+ ;; -------------------------------------
+ ;; Bootloader (com specific subroutines and init)
+#include "com-16f887-uart.inc"
+
+ ;; -------------------------------------
+ ;; Bootloader (generic init/body)
+#include "generic-mainloop.inc"
+
+ ;; -------------------------------------
+ ;; chip specific commands
+#include "cmds-16f887.inc"
+
+ ;; -------------------------------------
+ ;; -------------------------------------
+ ;; dummy user code
+ org USERVECT
+ goto USERVECT
+
+ ;; -------------------------------------
+ ;; END
+ end
diff --git a/software/pic.bootloader/cmds-16f887.inc b/software/pic.bootloader/cmds-16f887.inc
new file mode 100644
index 0000000..144150e
--- /dev/null
+++ b/software/pic.bootloader/cmds-16f887.inc
@@ -0,0 +1,117 @@
+ ;;
+ ;; spreadspace pic utils
+ ;;
+ ;;
+ ;; Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+ ;;
+ ;; This file is part of spreadspace pic utils.
+ ;;
+ ;; spreadspace pic utils is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation, either version 3 of the License, or
+ ;; any later version.
+ ;;
+ ;; spreadspace pic utils is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ;; GNU General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+ ;;
+
+ ;; flash read --------
+cmd_r_flash
+ movlw FSS ; initialize EEADR:EEADRH and FSR
+ movwf cnt
+ movlw b'01011000'
+ movwf STATUS
+ movlw combuff + .2
+ movwf FSR
+ movf INDF,w
+ movwf EEADR
+ incf FSR,f
+ movf INDF,w
+ movwf EEADRH
+read_flash_segment_loop
+ bsf STATUS,RP0 ; perform the actual read
+ bsf EECON1,EEPGD
+ bsf EECON1,RD
+ nop
+ nop
+ bcf STATUS,RP0
+ movf EEDAT,w ; load code word from EEDAT:EEDATH to combuff
+ movwf INDF
+ incf FSR,f
+ movf EEDATH,w
+ movwf INDF
+ incf FSR,f
+ incfsz EEADR,f ; increment flash address
+ goto read_flash_segment_next
+ incf EEADRH,f
+read_flash_segment_next
+ decfsz cnt,f
+ goto read_flash_segment_loop
+ bcf STATUS,RP1
+ clrf combuff + .2 ; = E_OK
+ movlw .1 + .2*FSS ; bytes to send
+ call send_answer
+ goto wait_new_cmd
+
+ ;; flash write --------
+cmd_w_flash
+ movf combuff + .3,f ; if addr[15:8] == 0 -> boot loader section
+ btfsc STATUS,Z
+ goto address_prohibited
+ movlw FLASH_BOUNDARY ; addr on boundary?
+ andwf combuff + .2,w
+ btfss STATUS,Z
+ goto address_invalid
+ movlw FSS ; initialize EEADR:EEADRH and FSR
+ movwf cnt
+ movlw b'01011000'
+ movwf STATUS
+ movlw combuff + .2
+ movwf FSR
+ movf INDF,w
+ movwf EEADR
+ incf FSR,f
+ movf INDF,w
+ movwf EEADRH
+
+write_flash_segment_loop
+ incf FSR,f ; load code word into EEDAT:EEDATH
+ movf INDF,w
+ movwf EEDAT
+ incf FSR,f
+ movf INDF,w
+ movwf EEDATH
+
+ bsf STATUS,RP0 ; now start the acutal write sequence
+ bsf EECON1,EEPGD
+ bsf EECON1,WREN
+ movlw H'55'
+ movwf EECON2
+ movlw H'AA'
+ movwf EECON2
+ bsf EECON1,WR
+ nop
+ nop
+ bcf EECON1,WREN
+ bcf STATUS,RP0
+ incfsz EEADR,f ; increment flash address
+ goto write_flash_segment_next
+ incf EEADRH,f
+write_flash_segment_next
+ decfsz cnt,f
+ goto write_flash_segment_loop
+ bsf STATUS,RP0
+ clrw ; check if a write error occured
+ btfsc EECON1,WRERR
+ movlw E_FLASH_WERR
+ bcf STATUS,RP1
+ bcf STATUS,RP0
+ movwf combuff + .2 ; = E_OK
+ movlw .1 ; bytes to send
+ call send_answer
+ goto wait_new_cmd
diff --git a/software/pic.bootloader/com-16f887-uart.inc b/software/pic.bootloader/com-16f887-uart.inc
new file mode 100644
index 0000000..b2b6812
--- /dev/null
+++ b/software/pic.bootloader/com-16f887-uart.inc
@@ -0,0 +1,75 @@
+ ;;
+ ;; spreadspace pic utils
+ ;;
+ ;;
+ ;; Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+ ;;
+ ;; This file is part of spreadspace pic utils.
+ ;;
+ ;; spreadspace pic utils is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation, either version 3 of the License, or
+ ;; any later version.
+ ;;
+ ;; spreadspace pic utils is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ;; GNU General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+ ;;
+
+ ;; --- transmit byte and add it to csum
+com_tx_byte
+ btfss PIR1,TXIF
+ goto com_tx_byte
+ movwf TXREG
+ xorwf csum,f
+ return
+
+ ;; ---- wait for byte to be received
+com_rx_byte
+ btfsc RCSTA,OERR
+ goto uart_rx_oe
+ btfss PIR1,RCIF
+ goto com_rx_byte
+ btfsc RCSTA,FERR
+ goto uart_rx_fe
+ movf RCREG,w
+ return
+
+uart_rx_oe ; recover from overflow
+ bcf RCSTA,CREN
+ bsf RCSTA,CREN
+ goto com_rx_byte
+
+uart_rx_fe ; recover from framing error
+ movf RCREG,w
+ goto com_rx_byte
+
+ ;; ----- initialize com (not a subroutine, com_init is called by generic_init
+com_init
+ ;; bank 3
+ bsf STATUS,RP0
+ bsf STATUS,RP1
+ ;;movlw b'00001000' ; TX non-inverted, 16bit Baudrate, no auto baud detect
+ movlw b'00011000' ; TX inverted, 16bit Baudrate, no auto baud detect
+ movwf BAUDCTL
+
+ ;; bank 1
+ bcf STATUS,RP1
+ movlw b'01110000' ; set internal OSC to 8MHz
+ movwf OSCCON
+ movlw b'00100100' ; Baudrate = High Speed, async mode, transmit enabled, 8bit
+ movwf TXSTA
+ movlw .34 ; Baudrate = 57600 (@ 8MHz) -> -0,79 % Error
+ ;; movlw .51 ; Baudrate = 38400 (@ 8MHz) -> -0,002 % Error
+ ;; movlw .103 ; Baudrate = 19200 (@ 8MHz) -> 0,16 % Error
+ movwf SPBRG
+ clrf SPBRGH
+
+ ;; bank 0
+ bcf STATUS,RP0
+ movlw b'10010000' ; enable Serial Port, 8bit, enable continues receive, disable address detection
+ movwf RCSTA
diff --git a/software/pic.bootloader/downloader.py b/software/pic.bootloader/downloader.py
new file mode 100755
index 0000000..27b15c3
--- /dev/null
+++ b/software/pic.bootloader/downloader.py
@@ -0,0 +1,339 @@
+#!/usr/bin/python
+#
+# spreadspace pic utils
+#
+#
+# Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+#
+# This file is part of spreadspace pic utils.
+#
+# spreadspace pic utils is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# any later version.
+#
+# spreadspace pic utils is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+#
+
+'''spreadspace simple pic downloader.'''
+
+VERSION_MAJ = 0
+VERSION_MIN = 1
+
+### HEX File Magic
+
+def load_hex(file):
+ from ihexpic import IHexPic
+
+ fin = file
+ if fin == '-':
+ fin = sys.stdin
+ elif not os.path.isfile(fin):
+ print >> sys.stderr, "ERROR: File not found: %s" % fin
+ sys.exit(1)
+
+ hexdata = IHexPic()
+ hexdata.load_from_file(fin)
+ return hexdata
+
+def write_hex(file, codedata):
+ from ihexpic import IHexPic
+
+ fout = file
+ if fout == '-':
+ fout = sys.stdout
+
+ hexdata = IHexPic()
+ hexdata.load_from_dict(codedata)
+ hexdata.write_to_file(fout)
+
+def get_lowest_flash_addr(hexdata, fss):
+ lowest_code_addr = hexdata.get_lowest_addr()
+ return lowest_code_addr - (lowest_code_addr%fss)
+
+def get_highest_flash_addr(hexdata, fss):
+ highest_code_addr = hexdata.get_highest_addr()
+ return highest_code_addr + (fss - highest_code_addr%fss)
+
+def create_flash_image(hexdata, fss, sa, ea):
+ img = ( sa, [0xFFFF]*(ea-sa) )
+ for a,d in hexdata.items():
+ if a < ea:
+ img[1][a-sa] = d
+ return img
+
+def create_flash_segments(hexdata, fs, fss):
+ sa = get_lowest_flash_addr(hexdata, fss)
+ ea = get_highest_flash_addr(hexdata, fss)
+ if ea >= fs:
+ print >> sys.stderr, "WARNING: the hex file contains data after end of flash, these words will be ignored"
+ ea = fs
+
+ img = create_flash_image(hexdata, fss, sa, ea)
+ for i in xrange(0, ea, fss):
+ slice = tuple(img[1][i:i+fss])
+ if not all( (elem == 0xFFFF) for elem in slice):
+ yield (i + img[0], slice)
+
+
+### Interface to Bootloader
+
+def open_serial(device, baud):
+ import os
+ import tty
+ import termios
+ import serial
+
+ print >> sys.stderr, "opening %s (%s Baud)" % (device, baud)
+
+ try:
+ dev = serial.Serial(port=device, baudrate=baud, timeout=3)
+ dev.flushInput()
+ dev.flushOutput()
+ return dev
+
+ except (ValueError, serial.SerialException), msg:
+ print >> sys.stderr, "ERROR: opening serial device: %s" % msg
+ sys.exit(3)
+
+def calc_csum(str):
+ cs = 0
+ for c in str:
+ cs ^= c
+ return cs
+
+def exec_command(dev, cmd, param, answer):
+ import struct
+
+ return_codes = { 0: "OK", 1: "invalid command", 2: "bad checksum",
+ 3: "not implemented", 4: "flash write error",
+ 5: "address invalid", 6: "address prohibited",
+ 7: "value out of bounds" }
+
+ dev.flushInput()
+ dev.flushOutput()
+
+ cstr = bytearray(struct.pack('<BB', cmd, len(param)+3) + param)
+ cstr.extend(struct.pack("<B", calc_csum(cstr)))
+ dev.write(cstr)
+
+ astr = bytearray()
+ astr += dev.read(4)
+ if len(astr) < 4:
+ print >> sys.stderr, "ERROR: timeout while reading response header (expected %d bytes, got %d)" % (4, len(astr))
+ sys.exit(4)
+
+ if astr[0] != cstr[0]:
+ print >> sys.stderr, "ERROR: bootloader returned wrong command code"
+ sys.exit(4)
+
+ ret = astr[2]
+ if ret != 0:
+ rstr = "invalid return code"
+ try:
+ rstr = return_codes[ret]
+ except KeyError:
+ pass
+ print >> sys.stderr, "ERROR: bootloader returned %d: %s" % (ret, rstr)
+ sys.exit(4)
+
+ answer_len = astr[1] - 4
+ if answer_len < struct.calcsize(answer):
+ print >> sys.stderr, "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 >> sys.stderr, "ERROR: timeout while reading response (expected %d bytes, got %d)" % (answer_len, len(tmp))
+ sys.exit(4)
+
+ astr += tmp
+
+ if 0 != calc_csum(astr):
+ print >> sys.stderr, "ERROR: checksum error"
+ sys.exit(4)
+
+ return struct.unpack_from(answer, astr, 3)
+
+### low level commands
+
+def cmd_identify(dev, name):
+ data = exec_command(dev, 1, '', '<BB3sHHBHBH')
+ id = { 'ver_min': data[0], 'ver_maj': data[1], 'name': data[2], 'devid': data[3],
+ 'fs': data[4], 'fss': data[5], 'es': data[6], 'mess': data[7], 'supported': data[8] }
+
+ if id['ver_maj'] != VERSION_MAJ:
+ print >> sys.stderr, "incompatible protocol version, expected: %d, got: %d" % (VERSION_MAJ, id['ver_maj'])
+ sys.exit(4)
+ if name and id['name'] != name:
+ print >> sys.stderr, "ERROR: the bootloaders name '%s' differs from the one supplied via" % id['name']
+ print >> sys.stderr, " command line option '%s'. Are sure you are connected to the" % name
+ print >> sys.stderr, " right device?"
+ sys.exit(4)
+
+ print >> sys.stderr, "connected with Bootloader '%s' Version %d.%d, (ID=%04X, %d words Flash, FSS=%d, %d bytes EEPROM, MESS=%d)" % \
+ (id['name'], id['ver_maj'], id['ver_min'], id['devid'], id['fs'], id['fss'], id['es'], id['mess'])
+ return id
+
+def cmd_boot(dev):
+ exec_command(dev, 2, '', '<')
+
+def cmd_reset(dev, id):
+ exec_command(dev, 3, '', '<')
+
+def cmd_read_flash_segment(dev, id, addr):
+ param = struct.pack('<H', addr)
+ return exec_command(dev, 4, param, '<%dH' % id['fss'])
+
+def cmd_write_flash_segment(dev, id, addr, data):
+ param = struct.pack('<H%dH' % id['fss'], addr, *data)
+ return exec_command(dev, 5, param, '<')
+
+def cmd_read_eeprom(dev, id, addr, len):
+ param = struct.pack('<HB', addr, len)
+ return exec_command(dev, 6, param, '<%dB' % len)
+
+def cmd_write_eeprom(dev, id, addr, data):
+ param = struct.pack('<HB%dB' % len(data), addr, len(data), *data)
+ return exec_command(dev, 7, param, '<')
+
+def cmd_read_config(dev, id, nr):
+ param = struct.pack('<B', nr)
+ data = exec_command(dev, 8, param, '<H')
+ return data[0]
+
+def cmd_write_config(dev, id, nr, word):
+ param = struct.pack('<BH', nr, word)
+ return exec_command(dev, 9, param, '<')
+
+
+### commands
+def boot(dev, id, file):
+ cmd_boot(dev)
+
+def write_flash(dev, id, file):
+ hexdata = load_hex(file)
+ for segment in create_flash_segments(hexdata, id['fs'], id['fss']):
+# print >> sys.stderr, "%05X: %s" % (segment[0], ''.join('%04X '%i for i in segment[1]))
+ cmd_write_flash_segment(dev, id, segment[0], segment[1])
+
+def read_flash(dev, id, file):
+ codedata = {}
+ for addr in xrange(0, id['fs'], id['fss']):
+ data = cmd_read_flash_segment(dev, id, addr)
+# print >> sys.stderr, "%05X: %s" % (addr, ''.join('%04X '%i for i in data))
+ a = addr
+ for d in data:
+ if d != 0x3FFF:
+ codedata[a] = d
+ a += 1
+ write_hex(file, codedata)
+
+def verify_flash(dev, id, file):
+ hexdata = load_hex(file)
+ err = 0
+ for segment in create_flash_segments(hexdata, id['fs'], id['fss']):
+ flashdata = cmd_read_flash_segment(dev, id, segment[0])
+ for file,flash in zip(segment[1] , flashdata):
+ if flash == 0x3FFF:
+ flash = 0xFFFF
+ if flash != file:
+ err = 1
+ break
+
+ if err !=0:
+ break
+
+ if err != 0:
+ print >> sys.stderr, "ERROR: verify failed!"
+ sys.exit(-1)
+ else:
+ print >> sys.stderr, "verify ok!"
+ sys.exit(0)
+
+commands = {
+ 'boot': boot,
+ 'write': write_flash,
+ 'read': read_flash,
+ 'verify': verify_flash
+}
+
+### Main
+
+if __name__ == '__main__':
+ import getopt
+ import sys
+ import os
+ import struct
+
+ usage = '''spreadspace simple pic downloader.
+Usage:
+ python downloader.py [options] INFILE
+
+Arguments:
+ INFILE name of hex file for downloading.
+ Use '-' for reading from stdin.
+
+Options:
+ -h, --help this help message.
+ -v, --version version info.
+ --cmd=N the command to execute, one out of: "boot,read,write,verify"
+ --device=N the serial port to use (default: /dev/ttyUSB0).
+ --baud=N baudrate to use (default: 57600).
+ --name=N the expected name of the bootloader.
+'''
+
+ device = "/dev/ttyUSB0"
+ baudrate = 57600
+ name = None
+ cmd = None
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hv",
+ ["help", "version", "cmd=", "device=", "baud=", "name="])
+
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ print >> sys.stderr, usage
+ sys.exit(0)
+ elif o in ("-v", "--version"):
+ print >> sys.stderr, "Version %d.%d" % (VERSION_MAJ, VERSION_MIN)
+ sys.exit(0)
+ elif o in ("--cmd"):
+ cmd = a
+ elif o in ("--device"):
+ device = a
+ elif o in ("--baud"):
+ baudrate = a
+ elif o in ("--name"):
+ name = a
+
+ if not args:
+ raise getopt.GetoptError('Hex file is not specified')
+
+ if len(args) > 1:
+ raise getopt.GetoptError('Too many arguments')
+
+ if not cmd:
+ raise getopt.GetoptError('You have to supply a command (boot,read,write,verify)')
+
+ except getopt.GetoptError, msg:
+ print >> sys.stderr, "ERROR: %s" % msg
+ print >> sys.stderr, usage
+ sys.exit(2)
+
+ dev = open_serial(device, baudrate)
+ id = cmd_identify(dev, name)
+
+ try:
+ commands[cmd](dev, id, args[0])
+ except KeyError:
+ print >> sys.stderr, "ERROR: unkown command '%s'" % cmd
diff --git a/software/pic.bootloader/generic-defines.inc b/software/pic.bootloader/generic-defines.inc
new file mode 100644
index 0000000..54ca01b
--- /dev/null
+++ b/software/pic.bootloader/generic-defines.inc
@@ -0,0 +1,50 @@
+ ;;
+ ;; spreadspace pic utils
+ ;;
+ ;;
+ ;; Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+ ;;
+ ;; This file is part of spreadspace pic utils.
+ ;;
+ ;; spreadspace pic utils is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation, either version 3 of the License, or
+ ;; any later version.
+ ;;
+ ;; spreadspace pic utils is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ;; GNU General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+ ;;
+
+ ;; ERROR codes
+E_OK EQU .0
+E_INV_CMD EQU .1
+E_BAD_CSUM EQU .2
+E_NOT_IMPL EQU .3
+E_FLASH_WERR EQU .4
+E_ADDR_INVALID EQU .5
+E_ADDR_PROHIB EQU .6
+E_VALUE_OOB EQU .7
+
+ ;; CMD codes
+CMD_INVALID EQU .0
+
+CMD_IDENTIFY EQU .1
+CMD_BOOT EQU .2
+CMD_RESET EQU .3
+CMD_R_FLASH EQU .4
+CMD_W_FLASH EQU .5
+CMD_R_EEPROM EQU .6
+CMD_W_EEPROM EQU .7
+CMD_R_CONFIG EQU .8
+CMD_W_CONFIG EQU .9
+
+CMD_MAX EQU .9
+CMD_MIN_LEN EQU .3
+
+ ;; Flags
+#define F_CMD_STARTED flags,0
diff --git a/software/pic.bootloader/generic-init.inc b/software/pic.bootloader/generic-init.inc
new file mode 100644
index 0000000..4c51fa9
--- /dev/null
+++ b/software/pic.bootloader/generic-init.inc
@@ -0,0 +1,61 @@
+ ;;
+ ;; spreadspace pic utils
+ ;;
+ ;;
+ ;; Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+ ;;
+ ;; This file is part of spreadspace pic utils.
+ ;;
+ ;; spreadspace pic utils is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation, either version 3 of the License, or
+ ;; any later version.
+ ;;
+ ;; spreadspace pic utils is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ;; GNU General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+ ;;
+
+ org .0
+ btfsc BOOTPIN
+ goto USERVECT
+ goto com_init
+
+ ;; -------------------------------------
+ ;; goto user ISR
+ org .4
+isr
+ goto ISRVECT
+
+ ;; -------------------------------------
+ ;; Bootloader (Generic Subroutines)
+send_answer ; generic answer message, leave len of data in W
+ addlw .3
+ movwf combuff + .1
+ decf combuff + .1,w
+ movwf cnt
+ movlw combuff
+ movwf FSR
+ clrf csum
+send_answer_next
+ movf INDF,w
+ call com_tx_byte
+ incf FSR,f
+ decfsz cnt,f
+ goto send_answer_next
+
+ movf csum,w
+ call com_tx_byte
+ return
+
+ ;; ------------------
+ack_cmd ; short answers which only contain return code
+ movwf combuff + .2
+ movlw .1
+ call send_answer
+ return
+
diff --git a/software/pic.bootloader/generic-mainloop.inc b/software/pic.bootloader/generic-mainloop.inc
new file mode 100644
index 0000000..1e93648
--- /dev/null
+++ b/software/pic.bootloader/generic-mainloop.inc
@@ -0,0 +1,174 @@
+ ;;
+ ;; spreadspace pic utils
+ ;;
+ ;;
+ ;; Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+ ;;
+ ;; This file is part of spreadspace pic utils.
+ ;;
+ ;; spreadspace pic utils is free software: you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation, either version 3 of the License, or
+ ;; any later version.
+ ;;
+ ;; spreadspace pic utils is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ;; GNU General Public License for more details.
+ ;;
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+ ;;
+
+wait_new_cmd
+ movlw combuff
+ movwf FSR
+ clrf combuff
+ clrf current_cmdlen
+ clrf flags
+
+wait_cmd
+ call com_rx_byte
+ movwf INDF ; process received byte
+ incf FSR,f
+ btfss F_CMD_STARTED
+ goto wait_cmd_len
+ movf current_cmdlen,f
+ btfsc STATUS,Z
+ goto new_cmd
+ decfsz current_cmdlen,f
+ goto wait_cmd
+ goto exec_cmd
+
+wait_cmd_len ; command code received, now wait for length
+ bsf F_CMD_STARTED
+ goto wait_cmd
+
+new_cmd ; got new command code and length -> check it
+ movf combuff,w
+ sublw CMD_MAX
+ btfss STATUS,C
+ goto invalid_cmd
+ movlw CMD_MIN_LEN ; check for minimum command len
+ subwf combuff + .1,w
+ btfss STATUS,C
+ goto invalid_cmd
+ movlw .2 ; 2 bytes already received
+ subwf combuff + .1,w
+ movwf current_cmdlen
+ goto wait_cmd
+
+exec_cmd ; command is complete -> check csum
+ movlw combuff
+ movwf FSR
+ movf combuff + .1,w
+ movwf cnt
+ clrf csum
+exec_cmd_check_csum
+ movf INDF,w
+ xorwf csum,f
+ incf FSR,f
+ decfsz cnt,f
+ goto exec_cmd_check_csum
+ movf csum,f
+ btfss STATUS,Z
+ goto csum_error
+
+ movf combuff,w ; command is correct and complete -> dispatch
+ addwf PCL,f
+ goto wait_new_cmd
+ goto cmd_identify ; identify
+ goto cmd_boot ; boot
+ goto HOOK_CMD_RESET ; reset
+ goto HOOK_CMD_R_FLASH ; read flash segment
+ goto HOOK_CMD_W_FLASH ; write flash segment
+ goto HOOK_CMD_R_EEPROM ; read eeprom
+ goto HOOK_CMD_W_EEPROM ; write eeprom
+ goto HOOK_CMD_R_CONFIG ; read config
+ goto HOOK_CMD_R_CONFIG ; write config
+
+ ;; ** generic error messages *******
+invalid_cmd ; received command code is not known or len is bogus
+ movlw E_INV_CMD
+ call ack_cmd
+ goto wait_new_cmd
+
+csum_error ; received command has an invalid check sum
+ movlw E_BAD_CSUM
+ call ack_cmd
+ goto wait_new_cmd
+
+address_invalid ; received command uses invalid address (i.e. not aligned to 16bytes)
+ movlw E_ADDR_INVALID
+ call ack_cmd
+ goto wait_new_cmd
+
+address_prohibited ; received command uses prohibited address (i.e. FLASH < 0x100)
+ movlw E_ADDR_PROHIB
+ call ack_cmd
+ goto wait_new_cmd
+
+ ;; ** generic command handlers ************
+ ;; ** identify *******
+cmd_identify
+ clrf csum
+ movf combuff,w
+ call com_tx_byte
+
+ movlw .19
+ call com_tx_byte
+
+ movlw E_OK
+ call com_tx_byte
+
+ movlw VERSION_MIN
+ call com_tx_byte
+ movlw VERSION_MAJ
+ call com_tx_byte
+
+ movlw NAME_0
+ call com_tx_byte
+ movlw NAME_1
+ call com_tx_byte
+ movlw NAME_2
+ call com_tx_byte
+
+ movlw DEVID_L
+ call com_tx_byte
+ movlw DEVID_H
+ call com_tx_byte
+
+ movlw FLASH_SIZE_L
+ call com_tx_byte
+ movlw FLASH_SIZE_H
+ call com_tx_byte
+ movlw FSS
+ call com_tx_byte
+
+ movlw EEPROM_SIZE_L
+ call com_tx_byte
+ movlw EEPROM_SIZE_H
+ call com_tx_byte
+ movlw MESS
+ call com_tx_byte
+
+ movlw SUPPORTED_L
+ call com_tx_byte
+ movlw SUPPORTED_H
+ call com_tx_byte
+
+ movf csum,w
+ call com_tx_byte
+ goto wait_new_cmd
+
+ ;; ** boot *******
+cmd_boot
+ movlw E_OK
+ call ack_cmd
+ goto USERVECT
+
+ ;; ** not implemented commands *******
+cmd_not_impl
+ movlw E_NOT_IMPL
+ call ack_cmd
+ goto wait_new_cmd
diff --git a/software/pic.bootloader/ihexpic.py b/software/pic.bootloader/ihexpic.py
new file mode 100644
index 0000000..e30204c
--- /dev/null
+++ b/software/pic.bootloader/ihexpic.py
@@ -0,0 +1,405 @@
+# spreadspace pic utils
+#
+#
+# Copyright (C) 2011 Christian Pointner <equinox@spreadspace.org>
+#
+# This file is part of spreadspace pic utils.
+#
+# spreadspace pic utils is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# any later version.
+#
+# spreadspace pic utils is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with spreadspace pic utils. If not, see <http://www.gnu.org/licenses/>.
+#
+#*********************************************************************
+# This is based on IntelHex 1.4
+# which can be found at: http://www.bialix.com/intelhex/
+#
+#
+# Copyright (c) 2005-2012, Alexander Belchenko
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms,
+# with or without modification, are permitted provided
+# that the following conditions are met:
+#
+# * Redistributions of source code must retain
+# the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce
+# the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the author nor the names
+# of its contributors may be used to endorse
+# or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#*********************************************************************
+
+'''Intel HEX file format reader and writer for PIC Microcontroller.'''
+
+
+from array import array
+from binascii import hexlify, unhexlify
+from bisect import bisect_right
+import sys
+
+
+class IHexPic(object):
+ ''' Intel HEX file reader for PIC Microcontroller. '''
+
+ def __init__(self):
+ # private members
+ self._buf = {}
+ self._offset = 0
+
+ def _decode_record(self, s, line=0):
+ '''Decode one record of HEX file.
+
+ @param s line with HEX record.
+ @param line line number (for error messages).
+
+ @raise EndOfFile if EOF record encountered.
+ '''
+ s = s.rstrip('\r\n')
+ if not s:
+ return # empty line
+
+ if s[0] == ':':
+ try:
+ bin = array('B', unhexlify(str(s[1:])))
+ except (TypeError, ValueError):
+ # this might be raised by unhexlify when odd hexascii digits
+ raise HexRecordError(line=line)
+ length = len(bin)
+ if length < 5:
+ raise HexRecordError(line=line)
+ else:
+ raise HexRecordError(line=line)
+
+ record_length = bin[0]
+ if length != (5 + record_length):
+ raise RecordLengthError(line=line)
+ if record_length%2 != 0:
+ raise RecordLengthError(line=line)
+
+ addr = bin[1]*256 + bin[2]
+ if addr%2 != 0:
+ raise RecordAlignmentError(line=line)
+
+ record_type = bin[3]
+ if not (0 <= record_type <= 5):
+ raise RecordTypeError(line=line)
+
+ crc = sum(bin)
+ crc &= 0x0FF
+ if crc != 0:
+ raise RecordChecksumError(line=line)
+
+ if record_type == 0:
+ # data record
+ addr += self._offset
+ for i in xrange(4, 4+record_length, 2):
+ addr16 = addr/2
+ if not self._buf.get(addr16, None) is None:
+ raise AddressOverlapError(address=addr16, line=line)
+ self._buf[addr16] = bin[i] + (bin[i+1]<<8)
+ addr += 2 # FIXME: addr should be wrapped
+ # BUT after 02 record (at 64K boundary)
+ # and after 04 record (at 4G boundary)
+
+ elif record_type == 1:
+ # end of file record
+ if record_length != 0:
+ raise EOFRecordError(line=line)
+ raise _EndOfFile
+
+ elif record_type == 2:
+ # Extended 8086 Segment Record
+ if record_length != 2 or addr != 0:
+ raise ExtendedSegmentAddressRecordError(line=line)
+ self._offset = (bin[4]*256 + bin[5]) * 16
+
+ elif record_type == 4:
+ # Extended Linear Address Record
+ if record_length != 2 or addr != 0:
+ raise ExtendedLinearAddressRecordError(line=line)
+ self._offset = (bin[4]*256 + bin[5]) * 65536
+
+ else:
+ raise UnsupportedRecordTypeError(type=record_type, line=line)
+
+
+ def load_from_file(self, fobj):
+ """Load hex file into internal buffer.
+
+ @param fobj file name or file-like object
+ """
+ if getattr(fobj, "read", None) is None:
+ fobj = open(fobj, "r")
+ fclose = fobj.close
+ else:
+ fclose = None
+
+ line = 0
+
+ try:
+ decode = self._decode_record
+ try:
+ for s in fobj:
+ line += 1
+ decode(s, line)
+ except _EndOfFile:
+ pass
+ finally:
+ if fclose:
+ fclose()
+
+ def load_from_dict(self, dikt):
+ """Load data from dictionary. Dictionary should contain int keys
+ representing addresses. Values should be the data to be stored in
+ those addresses in unsigned char form (i.e. not strings).
+
+ The contents of the dict will be merged with this object and will
+ overwrite any conflicts.
+ """
+ s = dikt.copy()
+ for k in s.keys():
+ if type(k) not in (int, long) or k < 0:
+ raise ValueError('Source dictionary should have only int keys')
+ self._buf.update(s)
+
+ def write_to_file(self, f):
+ """Write data to file f in HEX format.
+
+ @param f filename or file-like object for writing
+ """
+ fwrite = getattr(f, "write", None)
+ if fwrite:
+ fobj = f
+ fclose = None
+ else:
+ fobj = file(f, 'w')
+ fwrite = fobj.write
+ fclose = fobj.close
+
+ # Translation table for uppercasing hex ascii string.
+ # timeit shows that using hexstr.translate(table)
+ # is faster than hexstr.upper():
+ # 0.452ms vs. 0.652ms (translate vs. upper)
+ if sys.version_info[0] >= 3:
+ table = bytes(range(256)).upper()
+ else:
+ table = ''.join(chr(i).upper() for i in range(256))
+
+
+ # data
+ addresses = self._buf.keys()
+ addresses.sort()
+ addr_len = len(addresses)
+ if addr_len:
+ minaddr = addresses[0]
+ maxaddr = addresses[-1]
+
+ if maxaddr > 65535/2:
+ need_offset_record = True
+ else:
+ need_offset_record = False
+ high_ofs = 0
+
+ cur_addr = minaddr
+ cur_ix = 0
+
+ while cur_addr <= maxaddr:
+ if need_offset_record:
+ bin = array('B', str('\0'*7))
+ bin[0] = 2 # reclen
+ bin[1] = 0 # offset msb
+ bin[2] = 0 # offset lsb
+ bin[3] = 4 # rectype
+ high_ofs = int(cur_addr>>16)
+ b = divmod(high_ofs*2, 256)
+ bin[4] = b[0] # msb of high_ofs
+ bin[5] = b[1] # lsb of high_ofs
+ bin[6] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ str(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+
+ while True:
+ # produce one record
+ low_addr = cur_addr & 0x0FFFF
+ # chain_len off by 1
+ chain_len = min(7, 65535-low_addr, maxaddr-cur_addr)
+
+ # search continuous chain
+ stop_addr = cur_addr + chain_len
+ if chain_len:
+ ix = bisect_right(addresses, stop_addr,
+ cur_ix,
+ min(cur_ix+chain_len+1, addr_len))
+ chain_len = ix - cur_ix # real chain_len
+ # there could be small holes in the chain
+ # but we will catch them by try-except later
+ # so for big continuous files we will work
+ # at maximum possible speed
+ else:
+ chain_len = 1 # real chain_len
+
+ bin = array('B', str('\0'*(5+(chain_len*2))))
+ b = divmod(low_addr*2, 256)
+ bin[1] = b[0] # msb of low_addr
+ bin[2] = b[1] # lsb of low_addr
+ bin[3] = 0 # rectype
+ try: # if there is small holes we'll catch them
+ for i in range(chain_len):
+ bin[4+(i*2)] = self._buf[cur_addr+i] & 0x00FF
+ bin[4+(i*2)+1] = self._buf[cur_addr+i] >> 8
+ except KeyError:
+ # we catch a hole so we should shrink the chain
+ chain_len = i
+ bin = bin[:5+(i*2)]
+ bin[0] = chain_len*2
+ bin[4+(chain_len*2)] = (-sum(bin)) & 0x0FF # chksum
+ fwrite(':' +
+ str(hexlify(bin.tostring()).translate(table)) +
+ '\n')
+
+ # adjust cur_addr/cur_ix
+ cur_ix += chain_len
+ if cur_ix < addr_len:
+ cur_addr = addresses[cur_ix]
+ else:
+ cur_addr = maxaddr + 1
+ break
+ high_addr = int(cur_addr>>16)
+ if high_addr > high_ofs:
+ break
+
+ # end-of-file record
+ fwrite(":00000001FF\n")
+ if fclose:
+ fclose()
+
+ def get_lowest_addr(self):
+ return sorted(self._buf.keys())[0]
+
+ def get_highest_addr(self):
+ return sorted(self._buf.keys())[-1]
+
+ def items(self):
+ return self._buf.items()
+
+ def __getitem__(self, addr):
+ t = type(addr)
+ if t in (int, long):
+ if addr < 0:
+ raise TypeError('Address should be >= 0.')
+ return self._buf(addr, 0xFFFF)
+ else:
+ raise TypeError('Address has unsupported type: %s' % t)
+
+
+##
+# IHexPic Errors Hierarchy:
+#
+# IHexPicError - basic error
+# HexReaderError - general hex reader error
+# AddressOverlapError - data for the same address overlap
+# HexRecordError - hex record decoder base error
+# RecordLengthError - record has invalid length
+# RecordTypeError - record has invalid type (RECTYP)
+# RecordChecksumError - record checksum mismatch
+# EOFRecordError - invalid EOF record (type 01)
+# ExtendedAddressRecordError - extended address record base error
+# ExtendedSegmentAddressRecordError - invalid extended segment address record (type 02)
+# ExtendedLinearAddressRecordError - invalid extended linear address record (type 04)
+# UnsupportedRecordError - invalid/unsupported record type
+# _EndOfFile - it's not real error, used internally by hex reader as signal that EOF record found
+
+class IHexPicError(Exception):
+ '''Base Exception class for IHexPic module'''
+
+ _fmt = 'IHexPic base error' #: format string
+
+ def __init__(self, msg=None, **kw):
+ """Initialize the Exception with the given message.
+ """
+ self.msg = msg
+ for key, value in kw.items():
+ setattr(self, key, value)
+
+ def __str__(self):
+ """Return the message in this Exception."""
+ if self.msg:
+ return self.msg
+ try:
+ return self._fmt % self.__dict__
+ except (NameError, ValueError, KeyError), e:
+ return 'Unprintable exception %s: %s' \
+ % (repr(e), str(e))
+
+class _EndOfFile(IHexPicError):
+ """Used for internal needs only."""
+ _fmt = 'EOF record reached -- signal to stop read file'
+
+
+class HexReaderError(IHexPicError):
+ _fmt = 'Hex reader base error'
+
+class AddressOverlapError(HexReaderError):
+ _fmt = 'Hex file has data overlap at address 0x%(address)X on line %(line)d'
+
+
+class HexRecordError(HexReaderError):
+ _fmt = 'Hex file contains invalid record at line %(line)d'
+
+
+class RecordLengthError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid length'
+
+class RecordAlignmentError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid adress (not 16bit aligned)'
+
+class RecordTypeError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid record type'
+
+class RecordChecksumError(HexRecordError):
+ _fmt = 'Record at line %(line)d has invalid checksum'
+
+class EOFRecordError(HexRecordError):
+ _fmt = 'File has invalid End-of-File record'
+
+class UnsupportedRecordError(HexRecordError):
+ _fmt = 'File has unsupported record type %(type)d at line %(line)d'
+
+
+class ExtendedAddressRecordError(HexRecordError):
+ _fmt = 'Base class for extended address exceptions'
+
+class ExtendedSegmentAddressRecordError(ExtendedAddressRecordError):
+ _fmt = 'Invalid Extended Segment Address Record at line %(line)d'
+
+class ExtendedLinearAddressRecordError(ExtendedAddressRecordError):
+ _fmt = 'Invalid Extended Linear Address Record at line %(line)d'
diff --git a/software/pic.bootloader/proto.txt b/software/pic.bootloader/proto.txt
new file mode 100644
index 0000000..0e35e1e
--- /dev/null
+++ b/software/pic.bootloader/proto.txt
@@ -0,0 +1,200 @@
+Command List:
+=============
+
+ code | command
+ ------+------------
+ 1 | identify
+ 2 | boot
+ 3 | reset
+ 4 | read flash
+ 5 | write flash
+ 6 | read eeprom
+ 7 | write eeprom
+ 8 | read config
+ 9 | write config
+
+
+Description:
+------------
+
+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 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
+ ------+-------------
+ 0 | OK
+ 1 | invalid command
+ 2 | bad checksum
+ 3 | not implemented
+ 4 | flash write error
+ 5 | address invalid
+ 6 | address prohibited
+ 5 | value out of bounds
+
+identify:
+~~~~~~~~~
+ command:
+ 1 | len=3 | <csum>
+
+ answer:
+ 1 | len=19 | <ret> | version | name | devid | fs | fss | es | mess | supported | <csum>
+
+ version:
+ 2bytes, protocol version
+ It is an error if the major version (MSB) is different (hence any
+ protocol update must change the major version of the bootloader).
+
+ name:
+ 3bytes, a descriptive name of the device.
+ The downloader has to compare this name with the device name supplied
+ via commandline and stop in case they don't match
+
+ devid:
+ 2bytes, device id of the PIC
+ The downlaoder may use this id to check if it talks to the right bootloader
+
+ fs:
+ 2bytes, flash size
+ The size of the flash in code words.
+
+ fss:
+ 1byte, flash segment size
+ The number of words of one flash segment which has to be written at once.
+ If less than <fss> should be updated the downloader has to perform a read
+ operation first.
+
+ es:
+ 2bytes, eeprom size
+ The size of the eeprom in bytes.
+
+ mess:
+ 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.
+
+ supported:
+ 2bytes, a bitmap showing supported commands
+ The commands 'identify' and 'boot' are always supported by the bootloader,
+ others may not (i.e.: not all PICs allow to update the configurtion words)
+
+ bit | command
+ -----+----------
+ 0 | reset
+ 1 | read flash
+ 2 | write flash
+ 3 | read eeprom
+ 4 | write eeprom
+ 5 | read config
+ 6 | write config
+
+
+boot:
+~~~~~
+
+ command:
+ 2 | len=3 | <csum>
+
+ answer:
+ 2 | len=4 | <ret> | <csum>
+
+ This instucts the bootloader to boot to the user application directly (no reset)
+
+
+reset:
+~~~~~~
+
+ command:
+ 3 | len=3 | <csum>
+
+ answer:
+ 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.
+
+
+read flash:
+~~~~~~~~~~~
+
+ command:
+ 4 | len=5 | addr | <csum>
+
+ answer:
+ 4 | len=4+2*<fss> | <ret> | data | <csum>
+
+ The bootloader reads <fss> words from flash address <addr> and returns it as
+ <data>.
+
+
+write flash:
+~~~~~~~~~~~~
+
+ command:
+ 5 | len=5+2*<fss> | addr | data | <csum>
+
+ answer:
+ 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.
+ Before writing the memory region will be erased. If there are words which shouldn't
+ be altered the downloader has to read these words first and reprogram the whole segment.
+
+
+read eeprom:
+~~~~~~~~~~~~
+
+ command:
+ 6 | len=5 | addr | len | <csum>
+
+ answer:
+ 6 | len=4+<len> | <ret> | data | <csum>
+
+ The bootloader reads <len> bytes from eeprom at address <addr> and returns it as
+ <data>. len is 1byte long.
+
+
+write eeprom:
+~~~~~~~~~~~~~
+
+ command:
+ 7 | len=4+len(data) | addr | data | <csum>
+
+ answer:
+ 7 | len=4 | <ret> | <csum>
+
+ The bootloader writes <data> (which has to contain exactly <len>-4 bytes) to address
+ <addr> inside the eeprom. len is 1byte long and the value must not exceed <mess> bytes.
+
+
+read config:
+~~~~~~~~~~~~
+
+ command:
+ 8 | len=3 | nr | <csum>
+
+ answer:
+ 8 | len=6 | <ret> | word | <csum>
+
+ The bootloader reads and returns the configuration word number <nr>. <nr> is one
+ byte long.
+
+
+write config:
+~~~~~~~~~~~~~
+
+ command:
+ 9 | len=5 | nr | word | <csum>
+
+ answer:
+ 9 | len=4 | <ret> | <csum>
+
+ The bootloader writes <word> onto configuration word number <nr>. <nr> is one
+ byte long.