summaryrefslogtreecommitdiffstats
path: root/boiler-monster/pic
diff options
context:
space:
mode:
authorfishsoupisgood <github@madingley.org>2020-09-09 11:53:37 +0100
committerfishsoupisgood <github@madingley.org>2020-09-09 11:53:37 +0100
commit9d87c925a9eaa4fc256be3173c14a20d1469472d (patch)
tree50d63f87a47a0eac3f5b8058850184bcd4e6ee95 /boiler-monster/pic
parentdafd8cf2fdcdd637cc06f760d318cf8391b1a294 (diff)
downloadheating-9d87c925a9eaa4fc256be3173c14a20d1469472d.tar.gz
heating-9d87c925a9eaa4fc256be3173c14a20d1469472d.tar.bz2
heating-9d87c925a9eaa4fc256be3173c14a20d1469472d.zip
everything, mostly, working
Diffstat (limited to 'boiler-monster/pic')
-rw-r--r--boiler-monster/pic/.gitignore8
-rw-r--r--boiler-monster/pic/16f88.lkr76
-rw-r--r--boiler-monster/pic/Makefile22
-rw-r--r--boiler-monster/pic/build.asm2
-rw-r--r--boiler-monster/pic/docs/otgw-big-sch.pngbin0 -> 77271 bytes
-rw-r--r--boiler-monster/pic/docs/pinout.txt33
-rw-r--r--boiler-monster/pic/gateway.asm296
-rw-r--r--boiler-monster/pic/selfprog.asm391
8 files changed, 828 insertions, 0 deletions
diff --git a/boiler-monster/pic/.gitignore b/boiler-monster/pic/.gitignore
new file mode 100644
index 0000000..f8ab154
--- /dev/null
+++ b/boiler-monster/pic/.gitignore
@@ -0,0 +1,8 @@
+*.err
+*.swp
+*.swo
+*.lst
+*.o
+*.hex
+*.map
+*.cod
diff --git a/boiler-monster/pic/16f88.lkr b/boiler-monster/pic/16f88.lkr
new file mode 100644
index 0000000..b2b3e95
--- /dev/null
+++ b/boiler-monster/pic/16f88.lkr
@@ -0,0 +1,76 @@
+// File: 16F88_g.lkr
+// Generic linker script for the PIC16F88 processor
+
+#IFDEF _DEBUG
+
+LIBPATH .
+
+CODEPAGE NAME=page0 START=0x0 END=0x7FF
+CODEPAGE NAME=page1 START=0x800 END=0xEFF
+CODEPAGE NAME=debug START=0xF00 END=0xFFF PROTECTED
+CODEPAGE NAME=.idlocs START=0x2000 END=0x2003 PROTECTED
+CODEPAGE NAME=.device_id START=0x2006 END=0x2006 PROTECTED
+CODEPAGE NAME=.config START=0x2007 END=0x2009 PROTECTED
+CODEPAGE NAME=eedata START=0x2100 END=0x21FF PROTECTED
+
+DATABANK NAME=sfr0 START=0x0 END=0x1F PROTECTED
+DATABANK NAME=sfr1 START=0x80 END=0x9F PROTECTED
+DATABANK NAME=sfr2 START=0x100 END=0x10F PROTECTED
+DATABANK NAME=sfr3 START=0x180 END=0x18F PROTECTED
+
+SHAREBANK NAME=dbgnobnk START=0x70 END=0x70 PROTECTED
+SHAREBANK NAME=dbgnobnk START=0xF0 END=0xF0 PROTECTED
+SHAREBANK NAME=dbgnobnk START=0x170 END=0x170 PROTECTED
+SHAREBANK NAME=dbgnobnk START=0x1F0 END=0x1F0 PROTECTED
+
+SHAREBANK NAME=sfrnobnk START=0x71 END=0x7F
+SHAREBANK NAME=sfrnobnk START=0xF1 END=0xFF PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x171 END=0x17F PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x1F1 END=0x1FF PROTECTED
+
+DATABANK NAME=gpr0 START=0x20 END=0x6F
+DATABANK NAME=gpr1 START=0xA0 END=0xEF
+DATABANK NAME=gpr2 START=0x110 END=0x16F
+DATABANK NAME=gpr3 START=0x190 END=0x1E4
+DATABANK NAME=dbg3 START=0x1E5 END=0x1EF PROTECTED
+
+SECTION NAME=PROG0 ROM=page0 // ROM code space
+SECTION NAME=PROG1 ROM=page1 // ROM code space
+SECTION NAME=DEBUG ROM=debug // ICD debug executive
+SECTION NAME=IDLOCS ROM=.idlocs // ID locations
+SECTION NAME=DEVICEID ROM=.device_id // Device ID
+SECTION NAME=DEEPROM ROM=eedata // Data EEPROM
+
+#ELSE
+
+LIBPATH .
+
+CODEPAGE NAME=page0 START=0x0 END=0x7FF
+CODEPAGE NAME=page1 START=0x800 END=0xFFF
+CODEPAGE NAME=.idlocs START=0x2000 END=0x2003 PROTECTED
+CODEPAGE NAME=.device_id START=0x2006 END=0x2006 PROTECTED
+CODEPAGE NAME=.config START=0x2007 END=0x2009 PROTECTED
+CODEPAGE NAME=eedata START=0x2100 END=0x21FF PROTECTED
+
+DATABANK NAME=sfr0 START=0x0 END=0x1F PROTECTED
+DATABANK NAME=sfr1 START=0x80 END=0x9F PROTECTED
+DATABANK NAME=sfr2 START=0x100 END=0x10F PROTECTED
+DATABANK NAME=sfr3 START=0x180 END=0x18F PROTECTED
+
+SHAREBANK NAME=sfrnobnk START=0x70 END=0x7F
+SHAREBANK NAME=sfrnobnk START=0xF0 END=0xFF PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x170 END=0x17F PROTECTED
+SHAREBANK NAME=sfrnobnk START=0x1F0 END=0x1FF PROTECTED
+
+DATABANK NAME=gpr0 START=0x20 END=0x6F
+DATABANK NAME=gpr1 START=0xA0 END=0xEF
+DATABANK NAME=gpr2 START=0x110 END=0x16F
+DATABANK NAME=gpr3 START=0x190 END=0x1EF
+
+SECTION NAME=PROG0 ROM=page0 // ROM code space
+SECTION NAME=PROG1 ROM=page1 // ROM code space
+SECTION NAME=IDLOCS ROM=.idlocs // ID locations
+SECTION NAME=DEVICEID ROM=.device_id // Device ID
+SECTION NAME=DEEPROM ROM=eedata // Data EEPROM
+
+#FI
diff --git a/boiler-monster/pic/Makefile b/boiler-monster/pic/Makefile
new file mode 100644
index 0000000..31ab11c
--- /dev/null
+++ b/boiler-monster/pic/Makefile
@@ -0,0 +1,22 @@
+AFLAGS=-k -p 16F88 -k
+LDFLAGS=-m -s 16f88.lkr
+
+PROG=gateway
+ASRCS=${PROG}.asm selfprog.asm
+OBJS=${ASRCS:%.asm=%.o}
+LSTS=${ASRCS:%.asm=%.err}
+ERRS=${ASRCS:%.asm=%.lst}
+
+default:${PROG}.hex
+
+%.o:%.asm
+ gpasm ${AFLAGS} -c -o $@ $<
+
+${PROG}.hex:${OBJS}
+ gplink ${LDFLAGS} -o $@ ${OBJS}
+
+
+clean:
+ /bin/rm -f ${PROG}.hex ${PROG}.map ${PROG}.cod ${OBJS} ${LSTS} ${ERRS}
+
+
diff --git a/boiler-monster/pic/build.asm b/boiler-monster/pic/build.asm
new file mode 100644
index 0000000..67d0747
--- /dev/null
+++ b/boiler-monster/pic/build.asm
@@ -0,0 +1,2 @@
+#define build "1"
+#define tstamp "17:59 20-10-2015"
diff --git a/boiler-monster/pic/docs/otgw-big-sch.png b/boiler-monster/pic/docs/otgw-big-sch.png
new file mode 100644
index 0000000..114e65b
--- /dev/null
+++ b/boiler-monster/pic/docs/otgw-big-sch.png
Binary files differ
diff --git a/boiler-monster/pic/docs/pinout.txt b/boiler-monster/pic/docs/pinout.txt
new file mode 100644
index 0000000..a3db674
--- /dev/null
+++ b/boiler-monster/pic/docs/pinout.txt
@@ -0,0 +1,33 @@
+
+headers:
+
+left
+
+GND - STM32
+GPIO_B <- STM32 B9
+GPIO_A <- STM32 B8
+5V -> STM32
+LED_D -> STM32 B7
+LED_C -> STM32 B6
+LED_B -> NC
+LED_A -> NC
+
+
+middle
+
+GND - NC
+NC - NC
+NC -
+PIC RX <- STM32 B10
+PIC TX -> STM32 B11
+*RESET <- STM32 B1
+
+
+right
+
+5V -> MR3020
+NC
+GND - MR3020
+
+
+
diff --git a/boiler-monster/pic/gateway.asm b/boiler-monster/pic/gateway.asm
new file mode 100644
index 0000000..b1c6324
--- /dev/null
+++ b/boiler-monster/pic/gateway.asm
@@ -0,0 +1,296 @@
+ title "OpenTherm Gateway"
+ list p=16F88, b=8, r=dec
+
+;Copyright (c) 2009 Schelte Bron
+
+#define version "4.2"
+#define phase "." ;a=alpha, b=beta, .=production
+#define patch "5" ;Comment out when not applicable
+;#define bugfix "1" ;Comment out when not applicable
+#include build.asm
+
+;See the file "license.txt" for information on usage and redistribution of
+;this file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+#ifndef LVP
+ __config H'2007', B'10111101110100'
+#else
+ __config H'2007', B'10111111110100'
+#endif
+ __config H'2008', B'11111111111111'
+
+ errorlevel -302
+
+;#######################################################################
+;Comparator 1 is used for requests. The input is connected to the thermostat.
+;In monitor mode, the output is connected to the boiler.
+;Comparator 2 is used for responses. The input is connected to the Boiler.
+;In monitor mode, the output is connected to the thermostat.
+
+;The AUSART is configured for full duplex asynchronous serial communication at
+;9600 baud, 8 bits, no parity. It is used for reporting about opentherm messages
+;and receiving commands.
+
+;Analog input 0 is used to measure the voltage level on the opentherm line to
+;the thermostat. This way the code can distinguish between a real opentherm
+;thermostat and a simple on/off thermostat. An opentherm thermostat will keep
+;the line at a few volts (low) or between 15 and 18 volts (high). An on/off
+;thermostat will either short-circuit the line (0 volts) or leave the line open
+;(20+ volts).
+
+#include "p16f88.inc"
+
+;Define the speed of the PIC clock
+#define mhzstr "4"
+
+;BAUD contains the SPBRG value for 9600 baud
+ constant BAUD=25
+
+ extern SelfProg
+
+;Variables accessible from all RAM banks
+ UDATA_SHR
+loopcounter res 1
+
+Bank0data UDATA 0x20
+rxbuffer res 16 ;Serial receive buffer
+
+;Variables for longer lasting storage
+rxpointer res 1
+txpointer res 1
+
+temp res 1
+
+Bank1data UDATA 0xA0
+
+Bank1values UDATA 0xE0
+
+Bank2data UDATA 0x110
+Bank2values UDATA 0x160
+
+Bank3data UDATA 0x190
+;Use all available RAM in bank 3 for the transmit buffer
+ constant TXBUFSIZE=80
+txbuffer res TXBUFSIZE
+Bank3values UDATA 0x1E0
+
+;I/O map
+#define MasterIn CMCON,C1OUT
+#define SlaveIn CMCON,C2OUT
+#define SlaveOut PORTA,3
+#define MasterOut PORTA,4
+#define RXD PORTB,2
+#define TXD PORTB,5
+#define CCP1 PORTB,0
+#define LED_A PORTB,3
+#define LED_B PORTB,4
+#define LED_C PORTB,6
+#define LED_D PORTB,7
+#define RSET PORTB,1 ;Used by self-programming
+
+#define SlaveMask b'00001000'
+#define MasterMask b'00010000'
+
+package macro pkg
+pkg code
+pkg
+ endm
+
+pcall macro rtn
+ lcall rtn
+ pagesel $
+ endm
+
+;Skip the next instruction (bit 7 of PCLATH is always 0)
+skip macro
+ btfsc PCLATH,7
+ endm
+
+;Get the output of the active comparator into the carry bit
+getcompout macro
+ bsf STATUS,RP0
+ rlf CMCON,W ;Get the output of comparator 2
+ bcf STATUS,RP0
+ btfsc Request ;A request goes through comparator 1
+ addlw b'10000000' ;Cause a carry if C1OUT is high
+ endm
+
+;The first thing to do upon a reset is to allow the firmware to be updated.
+;So no matter how buggy freshly loaded firmware is, if the first two command
+;have not been messed up, the device can always be recovered without the need
+;for a PIC programmer. The self-programming code times out and returns after
+;a second when no firmware update is performed.
+;
+
+ResetVector code 0x0000
+ lcall SelfProg ;Always allow a firmware update on boot
+ lgoto Start ;Start the opentherm gateway program
+
+InterruptVector code 0x0004
+ retfie ;End of interrupt routine
+
+ package Interrupt
+
+;########################################################################
+; Main program
+;########################################################################
+
+ package Main
+Break tstf RCREG ;Clear the RCIF interrupt flag
+ bcf STATUS,RP1
+ bcf STATUS,RP0 ;bank 0
+ movlw 128
+ call Pause
+ pcall SelfProg ;Jump to the self-programming code
+Start bcf STATUS,RP1
+ bcf STATUS,RP0 ;bank 0
+ clrf PORTB ;Flash the LED's on startup
+ bsf STATUS,RP0
+ movlw b'01100000' ;Internal oscillator set to 4MHz
+ movwf OSCCON ;Configure the oscillator
+
+ ;Configure I/O pins
+ ;Power on defaults all pins to inputs
+ ;Port A
+ ;Pins 0 and 1 are used as comparator inputs
+ ;Pin 2 is used as VREF (must be configured as input!)
+ ;Pins 3 and 4 are (comparator) ouputs
+ ;Pin 5 is master reset input
+ ;Pins 6 and 7 are GPIO
+ movlw b'11100111'
+ movwf TRISA
+
+ ;Port B
+ ;Pins 2 and 5 are used by the USART and don't need to be configured
+ ;Pins 3, 4, 6, and 7 are used to indicate events for debugging
+#ifndef LVP
+ movlw b'00100111'
+#else
+ ;Can't use RB3 if LVP is enabled
+ movlw b'00101111'
+#endif
+ movwf TRISB
+
+ movlw b'11'
+ movwf PCON
+
+ ;Configure Timer 0 & Watchdog Timer
+ ;Bit 7 RBPU = 1 - Port B pull up disabled
+ ;Bit 6 INTEDG = 1 - Interrupt on rising edge
+ ;Bit 5 T0CS = 0 - Internal clock
+ ;Bit 4 T0SE = 1 - High to low transition
+ ;Bit 3 PSA = 0 - Prescaler assigned to Timer 0
+ ;Bit 2-0 PS = 5 - 1:64 Prescaler
+ movlw b'11010101'
+ movwf OPTION_REG
+
+
+ ;Configure comparator module
+ ;Bit 7 C2OUT = R/O
+ ;Bit 6 C1OUT = R/O
+ ;Bit 5 C2INV = 0 - Not inverted
+ ;Bit 4 C1INV = 0 - Not inverted
+ ;Bit 3 CIS = 0 - Irrelevant
+ ;Bit 2-0 = 3 - Common reference / 6 - with outputs
+ movlw b'00000011' ;Common reference mode
+ movwf CMCON
+
+ movlw b'00000111' ;A0 through A2 are used for analog I/O
+ movwf ANSEL
+
+ ;Configure the serial interface
+ movlw BAUD
+ movwf SPBRG
+ bsf TXSTA,BRGH ;9600 baud
+ bcf TXSTA,SYNC ;Asynchronous
+ bsf TXSTA,TXEN ;Enable transmit
+ bcf STATUS,RP0
+ bsf RCSTA,SPEN ;Enable serial port
+ bsf RCSTA,CREN ;Enable receive
+
+ ;Configure A/D converter
+ movlw b'01000001' ;A/D on, channel 0, Fosc/8
+ movwf ADCON0
+
+ ;Configure the voltage reference module
+ ;The reference voltage must be set to 1.3V
+ ;Bit 7 VREN = 1 - VREF Enabled
+ ;Bit 6 VROE = 1 - Output on pin RA2
+ ;Bit 5 VRR = 1 - Low range
+ ;Bit 3-0 VR = 6 - 1.25V (7 - 1.46V)
+ movlw b'11100110'
+ bsf STATUS,RP0
+ movwf CVRCON ;Set the reference voltage
+
+
+ clrf STATUS
+ bcf PIR2,CMIF ;Clear any comparator interrupt
+
+ movlw 0x41
+ movwf TXREG
+
+
+
+
+MainLoop clrwdt
+
+ ; Copy CMCON bits 7 and 6 from to PORTB bits 7 and 6 (comparitor outputs to LED_C and LED_D pins)
+ bsf STATUS,RP0
+ movfw CMCON
+ bcf STATUS,RP0
+
+ andlw b'11000000'
+ iorwf PORTB,F
+ iorlw b'00111111'
+ andwf PORTB,F
+
+ ; Copy PORTA bits 7 and 6 to PORTA bits 4 and 3 (GPIO inputs to transmitter outputs)
+ rrf PORTA,W
+ movwf temp
+ rrf temp,F
+ rrf temp,W
+
+ andlw b'00011000'
+ iorwf PORTA,F
+ iorlw b'11100111'
+ andwf PORTA,F
+
+ ; And port B bits 4 and 3 (LED_A and LED_B)
+
+ andlw b'00011000'
+ iorwf PORTB,F
+ iorlw b'11100111'
+ andwf PORTB,F
+
+
+ btfss PIR1,RCIF ;Activity on the serial receiver?
+ goto MainLoop
+ tstf RCREG
+
+ ;FERR is only relevant if RCIF is set
+ btfsc RCSTA,FERR ;Check for framing error (break)
+ goto Break
+ btfss RCSTA,OERR ;Check for overrun error
+ goto serial_recv
+ bcf RCSTA,CREN ;Procedure to clear an overrun error
+ bsf RCSTA,CREN ;Re-enable the serial interface
+serial_recv movfw RCREG
+ ;movwf TXREG
+ xorlw 0x4
+ skpnz
+ goto Break
+ goto MainLoop
+
+Pause clrwdt
+ btfsc PIR1,RCIF
+ return
+ btfss INTCON,TMR0IF
+ goto Pause
+ bcf INTCON,TMR0IF
+ addlw -1
+ skpz
+ goto Pause
+ return
+
+
+ end
diff --git a/boiler-monster/pic/selfprog.asm b/boiler-monster/pic/selfprog.asm
new file mode 100644
index 0000000..9e18769
--- /dev/null
+++ b/boiler-monster/pic/selfprog.asm
@@ -0,0 +1,391 @@
+ title "Self Programming"
+ list b=8, r=dec
+
+;########################################################################
+; Self programming, based on Microchip AN851
+;########################################################################
+; This code has been optimized for size so it would fit in 0x100 code words.
+; To achieve this, some special tricks had to be used. As a result the code
+; may be a little hard to read
+;
+; The functionality differs from that described in AN851 in the following
+; respects:
+; 1. No auto baud detection. Communication must take place at 9600 baud.
+; 2. Dropped the first <STX> that was used for auto baud detection.
+; 3. Dropped the third address byte as it would always be 0.
+; 4. The code does not check the last byte of EEPROM data memory to enter boot
+; mode. Instead it transmits a <ETX> character and waits up to 1 second for
+; a <STX> character.
+; 5. The code is designed to be placed in the highest part of memory. That way
+; it doesn't interfere with the interrupt code address. It does rely on the
+; main program to call the self-program code at an appropriate time.
+; 6. Due to the location of the boot loader code, it cannot be protected using
+; the code protection bits in the configuration word. This means that the
+; boot loader code can also be updated, if necessary.
+; 7. The Erase Flash command has been implemented for the PIC16F device.
+; 8. The device reset command is 0x08, not any command with a 0 length.
+; 9. The version command can be called with a data length of 1-3 words. It will
+; report the following information:
+; 1. Version
+; 2. Boot loader start address
+; 3. Boot loader end address
+; The software used to reflash the device can use the last two pieces of
+; information to determine which part of memory should not be touched.
+
+#include "p16f88.inc"
+
+ errorlevel -302, -306
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 1
+
+#define STX 0x0F
+#define ETX 0x04
+#define DLE 0x05
+
+CHKSUM equ 0x70
+COUNTER equ 0x71
+RXDATA equ 0x72
+TXDATA equ 0x73
+TEMP equ 0x74
+
+DATA_BUFF equ 0x10 ;Start of receive buffer
+COMMAND equ 0x10 ;Data mapped in receive buffer
+DATA_COUNT equ 0x11
+ADDRESS_L equ 0x12
+ADDRESS_H equ 0x13
+PACKET_DATA equ 0x14
+
+#define SELFRESET PORTB,1
+#define RX PORTB,2
+#define TX PORTB,5
+
+#ifdef SELFPROGNEW
+ #define SELFPROG SelfProgNew
+ #define STARTADDRESS 0x0700
+#else
+ #define SELFPROG SelfProg
+ #define STARTADDRESS 0x0f00
+#endif
+
+ global SELFPROG
+SELFPROG code STARTADDRESS
+ ;Do not go into selfprog mode after a watchdog timeout reset
+SELFPROG btfss STATUS,NOT_TO
+ return ;Let the main code handle a timeout
+
+ bcf INTCON,GIE ;Ignore interrupts
+
+ banksel OSCCON
+ movlw b'01100000' ;Internal oscillator set to 4MHz
+ movwf OSCCON ;Configure the oscillator
+
+ ;Set the LEDS as outputs
+#ifndef LVP
+ movlw b'00100111'
+#else
+ movlw b'00101111'
+#endif
+ movwf TRISB
+
+ ;Configure the comparators and voltage reference
+ ;Allow communication between thermostat and boiler to continue
+ ;while reprogramming the device
+ movlw b'11100111' ;Pins 3 and 4 are digital ouputs
+ movwf TRISA
+ movlw b'00000111' ;A0 through A2 are used for analog I/O
+ movwf ANSEL
+ movlw b'11100110' ;Voltage reference at 1.25V
+ movwf CVRCON
+ movlw b'00000110' ;Two common reference comps with output
+ movwf CMCON
+
+ ;Configure Timer 0 & Watchdog Timer
+ ;Bit 7 RBPU = 1 - Port B pull up disabled
+ ;Bit 6 INTEDG = 1 - Interrupt on rising edge
+ ;Bit 5 T0CS = 0 - Internal clock
+ ;Bit 4 T0SE = 1 - High to low transition
+ ;Bit 3 PSA = 0 - Prescaler assigned to Timer 0
+ ;Bit 2-0 PS = 7 - 1:256 Prescaler
+ movlw b'11010111'
+ movwf OPTION_REG
+
+ movlw 25 ;9600 baud
+ movwf SPBRG
+ movlw b'00100110'
+ movwf TXSTA ;High speed, Asynchronous, Enabled
+ bcf STATUS,RP0
+ bsf RCSTA,SPEN ;Enable serial port
+ bsf RCSTA,CREN ;Enable receive
+
+ ;Clear the LEDS
+ movlw b'11111111'
+ movwf PORTB
+
+ clrf TMR0
+ movlw 1
+ call Pause
+;Notify the external programming software (Pause returns <ETX>)
+ call WrRS232
+;Programmer should react within 1 second
+ movlw 16
+ call Pause
+ btfss PIR1,RCIF
+;No data received, resume the normal program
+ return
+;Check that the received character is <STX>
+ call RdRS232
+ skpz
+;Other serial data received, resume normal program
+ return
+
+ bsf STATUS,IRP
+ReSync movlw DATA_BUFF
+ movwf FSR
+ clrf CHKSUM
+GetNextDat call RdRS232 ;Get the data
+ skpnz
+ goto ReSync ;Found unprotected STX
+ xorlw STX ^ ETX ;Check for ETX
+ skpnz
+ goto CheckSum ;Yes, examine checksum
+ xorlw ETX ^ DLE ;Check for DLE
+ skpnz
+ call RdRS232 ;Yes, get the next byte
+ movfw RXDATA
+ movwf INDF ;Store the data
+ addwf CHKSUM,F ;Get sum
+ incf FSR,F
+ goto GetNextDat
+
+CheckSum tstf CHKSUM
+ skpz
+ goto StartOfLine
+ bsf STATUS,RP1
+ movfw ADDRESS_L
+ movwf EEADR
+ movfw ADDRESS_H
+ movwf EEADRH
+ movlw PACKET_DATA
+ movwf FSR
+ movfw DATA_COUNT
+ movwf COUNTER
+CheckCommand
+#ifdef SELFPROGNEW
+ movlw high ($ + 0x800)
+#else
+ movlw high $
+#endif
+ movwf PCLATH
+ movfw COMMAND
+ sublw 8
+ sublw 8
+ skpc
+ goto StartOfLine
+ addwf PCL,F
+ goto ReadVersion ;0 Read Version Information
+ goto ReadProgMem ;1 Read Program Memory
+ goto WriteProgMem ;2 Write Program Memory
+ goto EraseProgMem ;3 Erase Program Memory
+ goto ReadEE ;4 Read EEDATA Memory
+ goto WriteEE ;5 Write EEDATA Memory
+ goto StartOfLine ;6 Read Config Memory
+ goto StartOfLine ;7 Write Config Memory
+ goto VReset ;8 Reset
+
+VersionData data (MAJOR_VERSION << 8) | MINOR_VERSION
+#ifdef SELFPROGNEW
+ data SELFPROG + 0x800, SelfProgEnd + 0x800
+#else
+ data SELFPROG, SelfProgEnd
+#endif
+
+ReadVersion movlw low VersionData
+ movwf EEADR
+#ifdef SELFPROGNEW
+ movlw high (VersionData + 0x800)
+#else
+ movlw high VersionData
+#endif
+ movwf EEADRH
+ movlw DATA_BUFF + 2
+ movwf FSR
+ReadProgMem bsf STATUS,RP0
+ bsf EECON1,EEPGD
+ bsf EECON1,RD
+ nop
+ nop
+ bcf STATUS,RP0
+ movfw EEDATA
+ movwf INDF
+ incf FSR,F
+ movfw EEDATH
+ movwf INDF
+ incf FSR,F
+ incf EEADR,F
+ skpnz
+ incf EEADRH,F
+ decfsz COUNTER,F
+ goto ReadProgMem
+WritePacket movlw DATA_BUFF
+ subwf FSR,W
+WritePacketJ1 movwf COUNTER
+ movlw STX
+ call WrRS232
+ clrf CHKSUM
+ movlw DATA_BUFF
+ movwf FSR
+SendNext movfw INDF
+ addwf CHKSUM,F
+ incf FSR,F
+ call WrData
+ decfsz COUNTER,F
+ goto SendNext
+ comf CHKSUM,W
+ addlw 1
+ call WrData ;WrData returns <ETX>
+ call WrRS232
+StartOfLine bcf STATUS,RP1
+ call RdRS232 ;Look for a start of line
+ skpnz
+ goto ReSync
+ goto StartOfLine
+
+WriteProgMem movlw b'10000100'
+ call LoadEECon1
+ movlw b'11111100'
+ andwf EEADR,F
+ movlw 4
+ movwf TEMP
+Lp1 movfw INDF
+ movwf EEDATA
+ incf FSR,F
+ movfw INDF
+ movwf EEDATH
+ incf FSR,F
+ call StartWrite
+ decfsz TEMP,F
+ goto Lp1
+ decfsz COUNTER,F
+ goto WriteProgMem
+ goto WritePacketJ1
+
+EraseProgMem movlw b'10010100'
+ call LoadEECon1
+ movlw 0x1F
+ iorwf EEADR,F
+ call StartWrite
+ decfsz COUNTER,F
+ goto EraseProgMem
+ goto WritePacketJ1
+
+ReadEE bsf STATUS,RP0
+ clrf EECON1
+ bsf EECON1,RD
+ bcf STATUS,RP0
+ movfw EEDATA
+ movwf INDF
+ incf FSR,F
+ incf EEADR,F
+ decfsz COUNTER,F
+ goto ReadEE
+ goto WritePacket
+
+WriteEE movlw b'00000100'
+ call LoadEECon1
+ movfw INDF
+ movwf EEDATA
+ incf FSR,F
+ call StartWrite
+ decfsz COUNTER,F
+ goto WriteEE
+ goto WritePacketJ1
+
+WrData movwf TXDATA
+ xorlw STX
+ skpnz
+ goto WrDLE
+ xorlw STX ^ ETX
+ skpnz
+ goto WrDLE
+ xorlw ETX ^ DLE
+ skpz
+ goto WrNext
+WrDLE movlw DLE
+ call WrRS232
+WrNext movfw TXDATA
+WrRS232 clrwdt
+ bcf STATUS,RP1
+WaitTxEmpty btfss PIR1,TXIF
+ goto WaitTxEmpty
+ movwf TXREG
+ retlw ETX
+
+RdRS232 btfsc RCSTA,OERR
+ goto VReset
+RdLp1 clrwdt
+ btfss PIR1,RCIF
+ goto RdLp1
+ movfw RCREG
+ movwf RXDATA
+ xorlw STX
+ return
+
+LoadEECon1 bsf STATUS,RP0
+ movwf EECON1
+ bcf STATUS,RP0
+ return
+
+StartWrite clrwdt
+ bsf STATUS,RP0
+ movlw 0x55
+ movwf EECON2
+ movlw 0xAA
+ movwf EECON2
+ bsf EECON1,WR
+WaitEEWrite btfsc EECON1,WR ;Skipped when writing program memory
+ goto WaitEEWrite ;Skipped when writing program memory
+ bcf STATUS,RP0
+ incf EEADR,F
+ skpnz
+ incf EEADRH,F
+ retlw 1 ;Return length of acknowledgement
+
+Pause clrwdt
+ btfsc PIR1,RCIF
+ return
+ btfss INTCON,TMR0IF
+ goto Pause
+ bcf INTCON,TMR0IF
+ addlw -1
+ skpz
+ goto Pause
+ retlw ETX
+
+;Reset the device via an external connection from an I/O pin to the reset pin.
+VReset bcf STATUS,RP1
+ bcf SELFRESET ;Prepare the output latch
+ bsf STATUS,RP0
+ bcf SELFRESET ;Switch the pin to output
+
+;If resetting via the output pin doesn't work, restore all used registers to
+;their power-on defaults and jump to address 0.
+;Do not simply return because the code that called this routine may have been
+;wiped and reprogrammed to something completely different.
+ movlw b'11111111'
+ movwf TRISA
+ movwf TRISB
+ movwf OPTION_REG
+ movwf ANSEL
+ movlw b'00000111'
+ movwf CMCON
+ clrf TXSTA
+ clrf SPBRG
+ clrf STATUS
+ clrf RCSTA
+ clrf INTCON
+ clrf PCLATH
+ clrwdt
+SelfProgEnd goto 0
+
+ end