--- /dev/null
+; wispcarb.asm\r
+; David Rowe June 2009\r
+;\r
+; WISPCAR modified for EV battery testing. When watchdog fires PowerSwitch\r
+; (pin 6) stays off until the host sends a "w". This switches off current\r
+; to the battery under test if the host side dies. This mod is just a hack\r
+; for now.\r
+;\r
+;\r
+; PIC12F510 Assembler program, MPLAB V8.10 IDE used to build.\r
+;\r
+; ********************************************************\r
+; * Wifi Station Power Controller And Reporter - WiSPCaR *\r
+; ********************************************************\r
+;\r
+;---------------------------------------------------------------------\r
+; Copyright (C) 2008 David Rowe\r
+;\r
+; This program is free software; you can redistribute it and/or modify\r
+; it under the terms of the GNU General Public License as published by\r
+; the Free Software Foundation; either version 2 of the License, or\r
+; (at your option) any later version.\r
+;\r
+; This program is distributed in the hope that it will be useful,\r
+; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+; GNU General Public License for more details.\r
+;\r
+; You should have received a copy of the GNU General Public License\r
+; along with this program; if not, write to the Free Software\r
+; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 \r
+; USA\r
+;---------------------------------------------------------------------\r
+;\r
+; FUNCTIONS\r
+; =========\r
+;\r
+; 1/ Monitor Voltage\r
+; 2/ Monitor Current\r
+; 3/ Watchdog timer\r
+; 4/ Sleep timer\r
+;\r
+;\r
+; PINOUT\r
+; ======\r
+; ____ ____\r
+; | \/ | \r
+; Vcc --| 1 8 |-- GND\r
+; | |\r
+; Spare I/O --| 2 7 |-- Vsense (in)\r
+; | |\r
+; RS232 Tx (out) --| 3 6 |-- PowerSwitch (out)\r
+; | |\r
+; RS232 Rx (in) --| 4 5 |-- Isense (in)\r
+; |__________|\r
+;\r
+;\r
+; Pin | Function | PIC Name\r
+; -----|-------------|---------\r
+; 2 | Spare I/O | GP5 \r
+; 3 | RS232 Tx | GP4\r
+; 4 | RS232 Rx | GP3\r
+; 5 | Isense | AN2\r
+; 6 | PowerSwitch | GP1\r
+; 7 | Vsense | AN0\r
+;\r
+; \r
+; PIC PROGRAMMING OPTIONS\r
+; =======================\r
+;\r
+; 8MHz clock, MCLRE=I/O, INTOSC\r
+;\r
+;\r
+; 4800 BAUD RS232 OUTPUT\r
+; ======================\r
+; \r
+; The following line is printed every time you send 'w' or '.', if you\r
+; send nothing to wispcar it will remain silent. The specific chars\r
+; minimise the chance of wispcar interfering with your boot loader.\r
+;\r
+; Name of script on host that parses this line\r
+; | Vsense\r
+; | | Isense\r
+; | | | char received (ASCII)\r
+; | | | | Last char received (decimal)\r
+; | | | | | Watchdog timeout counter\r
+; | | | | | | Watchdog fire counter\r
+; | | | | | | | Sleep state machine state\r
+; | | | | | | | | Sleep timeout counter\r
+; | | | | | | | | | \r
+; wispcar 040 031 - 032 012 000 0 000 w---reason for last restart\r
+; b - Wispcar (re)booted \r
+; w - watchdog timer fired \r
+; s - we went to sleep\r
+; - - restart flag reset\r
+;\r
+; COMMANDS\r
+; ========\r
+;\r
+; 1/ Send a 'w' every WD_TIMEOUT seconds to prevent Watchdog timer\r
+; firing and cutting power.\r
+;\r
+; 2/ Send a '.' to report status without resetting watchdog.\r
+;\r
+; 3/ Send the string 'sleepxyz' to cut the power for xyz seconds,\r
+; where x,y and z are digits in the range 0-9. If any part of the\r
+; string is invalid it will be ignored. Wait 5 seconds and start\r
+; again.\r
+;\r
+; 4/ Wispcar cannot rx and tx RS232 at the same time. Wait until after\r
+; the current output has finished to send the next command. It is best to\r
+; wait until just after the output line is received by the host, then\r
+; send your command. If the command (such as sleep) gets messed up,\r
+; just wait 5 seconds and wispcar will reset it's internal state\r
+; machine. You can then try again.\r
+;\r
+; 4/ The final field is reset to a space when a 'w' is sent to\r
+; Wispcar. This field lets the host know just _why_ it was rebooted.\r
+\r
+\r
+#include <p12f510.inc>\r
+\r
+; VARIABLES ---------------------------------------------------------------------\r
+\r
+TEMP equ 0x10\r
+SERBUF equ 0x11 ; RS232 char to transmit\r
+count equ 0x12 ; temp reg used by "BIN2BCD" and "baud" routines\r
+BIN equ 0x13 \r
+huns equ 0x14\r
+tens equ 0x15\r
+ones equ 0x16\r
+thirty equ 0x17 ; constant set to (guess what) 30\r
+SERBUFI equ 0x18 ; last RS232 character we received\r
+wd_timeout equ 0x19 ; current watchdog timer value (in secs)\r
+ ; when this hits zero we turn the power off\r
+wd_fire equ 0x1a ; count down timer when watchdog fires (in secs)\r
+restart_flag equ 0x1b ; tells host why we just restarted (WD or sleep)\r
+\r
+sleep_state equ 0x1c\r
+sleep_timeout equ 0x1d ; current value of sleep time out (in secs)\r
+ ; measures time between rx-ed chars in\r
+ ; s-l-e-e-p-x-y-z sequence.\r
+ ; If this hits zero (like s-l- (BIG GAP))\r
+ ; we assume sleep command\r
+ ; was invalid and we reset the input state machine\r
+\r
+ ; three digit sleep time (up to 999 secs)\r
+ ; these count down to zero while we are sleeping\r
+ ; when count down hits 0 power is switched back on\r
+\r
+sleeping equ 0x1e ; asserted if we are sleeping (power off)\r
+\r
+; following variables are in bank1, which makes life difficult....\r
+\r
+d1 equ 0x10\r
+d2 equ 0x11\r
+d3 equ 0x12\r
+\r
+x equ 0x13 ; sleep time (hundreds of secs)\r
+y equ 0x14 ; sleep time (tens of secs)\r
+z equ 0x15 ; sleep time (secs)\r
+\r
+; CONSTANTS ---------------------------------------------------------------------\r
+\r
+WD_TIMEOUT equ d'18' ; watchdog timeout in seconds\r
+WD_FIRE equ d'5' ; watchdog firing time in seconds\r
+ ; how long power is cut off to host\r
+\r
+SLEEP_TIMEOUT equ d'5' ; timeout between rx-ed chars in sleep input\r
+ ; sequence.\r
+\r
+; Values for restart_flag - tell host why we just cut power after we woke up\r
+\r
+BOOT_FLAG equ 'b' ; Wispcar just rebooted\r
+WD_FLAG equ 'w' ; Watchdog fired\r
+SLEEP_FLAG equ 's' ; We slept\r
+\r
+; START PROGRAM ----------------------------------------------------------------\r
+\r
+; set up osc cal (temp code just for experimenting)\r
+; TODO - FIX ME for general case\r
+\r
+ movlw 16\r
+ movwf OSCCAL\r
+\r
+; configure AN[1:0] as analog inputs\r
+\r
+ movlw b'10110001'\r
+ movwf ADCON0 \r
+\r
+; configure GP[3] as digital input (RS232 RX)\r
+; configure GP[4] as digital output (RS232 TX)\r
+; configure GP[1] as digital output (PowerSwitch)\r
+\r
+; disble the comparitor so we can use GP[1]\r
+\r
+ bcf CM1CON0,3\r
+\r
+ ; set up GPIO directions\r
+\r
+ movlw b'00001101'\r
+ tris GPIO\r
+\r
+; turn on PowerSwitch \r
+\r
+ bsf GPIO,1 \r
+\r
+; set up a convenient constant\r
+\r
+ movlw h'30'\r
+ movwf thirty\r
+\r
+; init watchdog \r
+\r
+ movlw WD_TIMEOUT\r
+ movwf wd_timeout\r
+ clrf wd_fire\r
+\r
+; init sleep\r
+\r
+ clrf sleep_state\r
+ clrf sleeping \r
+ clrf sleep_timeout \r
+ bsf FSR,5 ; x,y,z are in bank 1 (grumble)\r
+ clrf x\r
+ clrf y\r
+ clrf z\r
+ bcf FSR,5 ; x,y,z are in bank 1 (grumble)\r
+\r
+; init restart_flag\r
+\r
+ movlw BOOT_FLAG\r
+ movwf restart_flag\r
+\r
+ goto main\r
+\r
+; START FUNCTIONS ------------------------------------------------------------\r
+\r
+; BIN2BCD\r
+;\r
+; Convert 8 bit value in BIN to a 3 digit decimal value.\r
+;\r
+; in.......: BIN\r
+; out......: huns, tens, ones\r
+; Reference: http://www.piclist.com/techref/microchip/math/radix/b2a-8b3d-ab.htm\r
+;\r
+; Uses temp reg 'count'\r
+\r
+; uses ADD-3 algorithm\r
+\r
+BIN2BCD\r
+ movlw 8\r
+ movwf count\r
+ clrf huns\r
+ clrf tens\r
+ clrf ones\r
+BCDADD3\r
+ movlw 5\r
+ subwf huns, 0\r
+ btfsc STATUS, C\r
+ CALL ADD3HUNS\r
+\r
+ movlw 5\r
+ subwf tens, 0\r
+ btfsc STATUS, C\r
+ CALL ADD3TENS\r
+\r
+ movlw 5\r
+ subwf ones, 0\r
+ btfsc STATUS, C\r
+ CALL ADD3ONES\r
+\r
+ decf count, 1\r
+ bcf STATUS, C\r
+ rlf BIN, 1\r
+ rlf ones, 1\r
+ btfsc ones,4 ; \r
+ CALL CARRYONES\r
+ rlf tens, 1\r
+\r
+ btfsc tens,4 ; \r
+ CALL CARRYTENS\r
+ rlf huns,1\r
+ bcf STATUS, C\r
+\r
+ movf count, 0\r
+ btfss STATUS, Z\r
+ GOTO BCDADD3\r
+\r
+ movf huns, 0 ; add ASCII Offset\r
+ addwf thirty, 0\r
+ movwf huns\r
+\r
+ movf tens, 0 ; add ASCII Offset\r
+ addwf thirty, 0\r
+ movwf tens\r
+\r
+ movf ones, 0 ; add ASCII Offset\r
+ addwf thirty, 0\r
+ movwf ones\r
+\r
+ retlw 0\r
+\r
+ADD3HUNS\r
+ movlw 3\r
+ addwf huns,1\r
+ retlw 0\r
+\r
+ADD3TENS\r
+ movlw 3\r
+ addwf tens,1\r
+ retlw 0\r
+\r
+ADD3ONES\r
+ movlw 3\r
+ addwf ones,1\r
+ retlw 0\r
+\r
+CARRYONES\r
+ bcf ones, 4\r
+ bsf STATUS, C\r
+ retlw 0\r
+\r
+CARRYTENS\r
+ bcf tens, 4\r
+ bsf STATUS, C\r
+ retlw 0 \r
+\r
+; INCH_N is from "PIC Software UART Routines"\r
+; John Massa, Datadog Systems (C) 2005\r
+\r
+; ********************************************************************\r
+; INCH_N\r
+; THIS ROUTINE INPUTS RS232 DATA USING AN INVERTER, LIKE THE MAX232.\r
+; THIS ROUTINE USES A 8-DATA BIT PER CHARACTER PROTOCOL\r
+; GPIO,0 = RX (MARK = 1, SPACE = 0).\r
+; TO RECIEVE A CHARACTER, CALL inch_n, THE RECEIVED CHARACTER IS PLACED\r
+; IN THE REG 'W' AND IN THE REG 'SERBUF'.\r
+; THE RECEIVED CHARACTER WILL ECHO IF 'RETLW 0' IS REM-ED OUT.\r
+; VARIABLES USED: REG 'TEMP' AND REG 'SERBUF' BOTH VARIABLES ARE\r
+; SHARED WITH THE 'outch_n' ROUTINE.\r
+; ROUTINES CALLED: 'half_baud'AND 'baud' TO SET THE BAUD-RATE\r
+; ********************************************************************\r
+\r
+; Modified by David Rowe May 2008 to combine a 1 second delay with\r
+; character reception.\r
+\r
+inch_n_delay\r
+\r
+ ; clear previous rx char\r
+\r
+ movlw '-'\r
+ movwf SERBUFI\r
+\r
+ ; init delay loop for 1999996 cycles\r
+\r
+ bsf FSR,5 ; d1, d2, d3 in Bank 1 (groan)\r
+ movlw 0x11\r
+ movwf d1\r
+ movlw 0x5D\r
+ movwf d2\r
+ movlw 0x05\r
+ movwf d3\r
+\r
+wait_for_start\r
+ bcf FSR,5 ; just in case goto below fires\r
+ btfss GPIO,3 ; SKIP UNLESS WE GET A START BIT = 1 (A "MARK")\r
+ goto start_serial ; start bit - process character\r
+\r
+ ; process delay loop while we look for start bit\r
+\r
+ bsf FSR,5\r
+ decfsz d1, f\r
+ goto $+2\r
+ decfsz d2, f\r
+ goto $+2\r
+ decfsz d3, f\r
+ goto wait_for_start\r
+\r
+ ; delay finished\r
+\r
+ bcf FSR,5 \r
+ retlw 0\r
+ \r
+start_serial\r
+ bsf GPIO,5\r
+ bcf GPIO,5\r
+\r
+ movlw 8 ; START SERIAL INPUT SEQUENCE\r
+ movwf TEMP ; COLLECT 8 DATA BITS\r
+ clrf SERBUFI ; CLEAR SERIAL CHARACTER BUFFER\r
+ call half_baud ; DELAY FOR ONE HALF BAUD TIME\r
+ btfsc GPIO,3 ; FALL THRU IF START BIT STILL = 1 (A "MARK")\r
+ goto wait_for_start ; ELSE IT WAS JUST A NOISE SPIKE, KEEP LOOKING\r
+inch_n1\r
+ call baud ; DELAY ONE BAUD-BIT TIME ( = 1/BAUD-RATE)\r
+ bcf STATUS,0 ; CLEAR THE CARRY BIT\r
+ rrf SERBUFI,F ; ROTATE CRY -> MSB, ROTATE MSB RIGHT\r
+ btfsc GPIO,3 ; IS IT A "MARK" ?\r
+ bsf SERBUFI,7 ; ...SKIP IF YES, ELSE SET BIT TO LOGIC '1'\r
+ decfsz TEMP,F ; EIGHT COUNTS YET?\r
+ goto inch_n1 ; ...NO, GET ANOTHER BIT\r
+ call baud ; DELAY FOR THE STOP BIT\r
+ movf SERBUFI,W ; PUT THE RECEIVED CHARACTER IN REG 'W'\r
+\r
+ ; process received character, this can be considered an "event\r
+ ; handler" for rx-chars. We expect either a 'w' to reset the\r
+ ; watchdog or a tightly defined sequence of sleep characters.\r
+\r
+ movlw 'w' \r
+ subwf SERBUFI,0 ; is it a 'w' for watchdog reset?\r
+ btfss STATUS,Z ; skip if received char matches\r
+ goto handle_sleepin ; only process sleep input if not a 'w'\r
+\r
+ ; handle 'w' input \r
+ \r
+ ; Note if we are sleeping or WD is firing we will keep power\r
+ ; off and receiving 'w' will have no effect. Unlikely unless\r
+ ; device sending rx chars is powered indepednantly (ie during\r
+ ; testing).\r
+\r
+ movlw WD_TIMEOUT ; reset watchdog timer\r
+ movwf wd_timeout\r
+\r
+ ; DR June 2009 - mods\r
+ bsf GPIO,1\r
+\r
+ movlw '-' ; clear reboot flag\r
+ movwf restart_flag\r
+\r
+ clrf sleep_state ; reset sleep state machine for good measure\r
+ clrf sleep_timeout ; just in case we get s-l-w-e-e-p or something\r
+\r
+ goto wait_for_start\r
+\r
+handle_sleepin\r
+ call sleep_input\r
+ goto wait_for_start\r
+\r
+; OUTCH_N and BAUD are from "PIC Software UART Routines"\r
+; John Massa, Datadog Systems (C) 2005\r
+\r
+;*********************************************************************\r
+; OUTCH_N\r
+; THIS ROUTINE OUTPUTS RS232 DATA THROUGH AN INVERTER.\r
+; THIS ROUTINE USES AN 8-DATA BIT PER CHARACTER PROTOCOL.\r
+; TO PRINT A CHARACTER, LOAD BYTE INTO REG 'W' AND CALL outch_n.\r
+; GPIO,1 = TX (MARK = 1, SPACE = 0) ; USE INVERTER ON THE OUTPUT\r
+; VARIABLES USED: REG 'TEMP' AND SHARE REG 'SERBUF' WITH THE ROUTINE\r
+; 'inch_n'\r
+; CALLS THE ROUTINE 'baud' TO SET THE BAUD-RATE TIMING.\r
+;*********************************************************************\r
+\r
+outch_n ; THIS ROUTINE USES 8 DATA BITS\r
+ movwf SERBUF ; SERBUF CONTAINS CHARACTER TO XMT\r
+ movlw 8 ; THE CHARACTER HAS 8 BITS\r
+ movwf TEMP\r
+ bcf GPIO,4 ; SET START-BIT TO A "SPACE"\r
+ call baud ; WAIT ONE BAUD TIME\r
+outch_n1\r
+ rrf SERBUF,F ; ROTATE THE FIRST BIT INTO CARRY\r
+ btfss STATUS,0 ; TEST THE CARRY BIT\r
+ bcf GPIO,4 ; IF BIT IS 0 SET OUTPUT PIN TO A "0" (SPACE)\r
+ btfsc STATUS,0 ; TEST THE CARRY BIT AGAIN\r
+ bsf GPIO,4 ; IF BIT IS 1 SET OUTPUT PIN TO A "1" (MARK)\r
+ call baud ; ONE BAUD-BIT DELAY\r
+ decfsz TEMP,F ; IF COUNT IS ZERO THEN XMIT A STOP BIT\r
+ goto outch_n1 ; ...ELSE XMIT NEXT BIT\r
+ rrf SERBUF,F ; ROTATE CARRY, GET THE MSB BACK INTO BIT 7\r
+ bsf GPIO,4 ; SET PIN TO A 1 (A "MARK") FOR THE STOP BIT\r
+ call baud ; FIRST BAUD-BIT DELAY\r
+ call baud ; SECOND BAUD-BIT DELAY\r
+ retlw 0 ; RETURN WITH THE CHARACTER IN SERBUF\r
+ \r
+; ********************************************************************\r
+; BAUD ROUTINE @ 4 MHz\r
+; BAUD RATE: CONSTANT:\r
+; 1200 Baud D'137'\r
+; 2400 Baud D'68'\r
+; 4800 Baud D'34'\r
+; 9600 Baud D'16'\r
+; 19200 Baud D'8'\r
+; 38400 Baud and up - use 'NOP' delays\r
+; VARIABLES USED: REG 'count'\r
+; ROUTINES CALLED: NONE\r
+; ********************************************************************\r
+\r
+baud ; AT 2400 BAUD THE PERIOD IS 416.6 US\r
+ ; CLK = 4MHz\r
+ movlw D'68' ; 1 US (BAUD RATE CONSTANT)\r
+ movwf count ; 1 US\r
+baud1\r
+ decfsz count,F ; 1 US (+ 1 US MORE IF SKIP)\r
+ goto baud1 ; 2 US\r
+ ; FALL THRU...AFTER 1+1+3x68+1 = 207 US\r
+half_baud\r
+ movlw D'68' ; 1 US\r
+ movwf count ; 1 US\r
+hbaud1\r
+ decfsz count,F ; 1 US (+ 1 US MORE IF SKIP)\r
+ goto hbaud1 ; 2 US\r
+ retlw 0 ; ...AFTER 1+1+3x68+1 = 207 US (X2=414 US)\r
+\r
+; http://www.piclist.com/techref/piclist/codegen/delay.htm\r
+; Delay = 1 seconds\r
+; Clock frequency = 8 MHz\r
+\r
+; Actual delay = 1 seconds = 2000000 cycles\r
+; Error = 0 %\r
+\r
+delay\r
+ ;1999996 cycles\r
+ bsf FSR,5\r
+ movlw 0x11\r
+ movwf d1\r
+ movlw 0x5D\r
+ movwf d2\r
+ movlw 0x05\r
+ movwf d3\r
+Delay_0\r
+ decfsz d1, f\r
+ goto $+2\r
+ decfsz d2, f\r
+ goto $+2\r
+ decfsz d3, f\r
+ goto Delay_0\r
+\r
+ ;4 cycles\r
+ goto $+1\r
+ goto $+1\r
+\r
+ bcf FSR,5\r
+ retlw 0\r
+\r
+; sleep input state machine\r
+; \r
+; we expect the chars s-l-e-e-p-x-y-z where xyz are digits\r
+; if wrong char received reset\r
+; if 5 sec timout between chars reset\r
+; if xyz are not digits reset\r
+\r
+sleep_input\r
+\r
+ ; big case statement to work out what state we are in\r
+\r
+ movlw 0\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 's'\r
+ goto sleep_state_s\r
+ movlw 1\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 'l'\r
+ goto sleep_state_l\r
+ movlw 2\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 'e1'\r
+ goto sleep_state_e1\r
+ movlw 3\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 'e2'\r
+ goto sleep_state_e2\r
+ movlw 4\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 'p'\r
+ goto sleep_state_p\r
+ movlw 5\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 'x'\r
+ goto sleep_state_x\r
+ movlw 6\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 'y'\r
+ goto sleep_state_y\r
+ movlw 7\r
+ subwf sleep_state,0\r
+ btfsc STATUS,Z ; Z set if in state 'z'\r
+ goto sleep_state_z\r
+\r
+ ; should never get here but just in case\r
+\r
+ goto sleep_reset\r
+\r
+ ; if we have rx-ed a 's' continue to next state\r
+sleep_state_s\r
+ movlw 's'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,Z ; Z set if we received a 's'\r
+ goto sleep_reset\r
+ goto sleep_cont\r
+\r
+ ; if we have rx-ed a 'l' continue to next state\r
+sleep_state_l\r
+ movlw 'l'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,Z ; Z set if we received a 'l'\r
+ goto sleep_reset\r
+ goto sleep_cont\r
+\r
+ ; if we have rx-ed a 'e' continue to next state\r
+sleep_state_e1\r
+ movlw 'e'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,Z ; Z set if we received a 'e'\r
+ goto sleep_reset\r
+ goto sleep_cont\r
+\r
+ ; if we have rx-ed a 'e' continue to next state\r
+sleep_state_e2\r
+ movlw 'e'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,Z ; Z set if we received a 'e'\r
+ goto sleep_reset\r
+ goto sleep_cont\r
+\r
+ ; if we have rx-ed a 'p' continue to next state\r
+sleep_state_p\r
+ movlw 'p'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,Z ; Z set if we received a 'p'\r
+ goto sleep_reset\r
+ goto sleep_cont\r
+\r
+ ; if we have rx-ed a digit 0-9 continue to next state\r
+sleep_state_x\r
+\r
+ ; check if >= '0'\r
+ movlw '0'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,C ; C set if valid\r
+ goto sleep_reset\r
+\r
+ ; check if x <= 9\r
+ bsf FSR,5 ; x is in bank 1\r
+ movwf x\r
+ movlw d'10'\r
+ subwf x,0\r
+ bcf FSR,5\r
+ btfsc STATUS,C ; C reset if valid\r
+ goto sleep_reset\r
+ goto sleep_cont\r
+\r
+ ; if we have rx-ed a digit 0-9 continue to next state\r
+sleep_state_y\r
+\r
+ ; check if >= '0'\r
+ movlw '0'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,C ; C set if valid\r
+ goto sleep_reset\r
+\r
+ ; check if y <= 9\r
+ bsf FSR,5 ; y is in bank 1\r
+ movwf y\r
+ movlw d'10'\r
+ subwf y,0\r
+ bcf FSR,5\r
+ btfsc STATUS,C ; C reset if valid\r
+ goto sleep_reset\r
+ goto sleep_cont\r
+\r
+ ; if we have rx-ed a digit 0-9 continue to next state\r
+sleep_state_z\r
+\r
+ ; check if >= '0'\r
+ movlw '0'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,C ; C set if valid\r
+ goto sleep_reset\r
+\r
+ ; check if z <= 9\r
+ bsf FSR,5 ; z is in bank 1\r
+ movwf z\r
+ movlw d'10'\r
+ subwf z,0\r
+ bcf FSR,5\r
+ btfsc STATUS,C ; C reset if valid\r
+ goto sleep_reset\r
+\r
+ ; OK we made it! Lets go to SLEEP, ZZZZZzzzzzzzzzz\r
+\r
+ clrf sleep_state\r
+ clrf sleep_timeout\r
+ movlw 1\r
+ movwf sleeping\r
+ bcf GPIO,1 ; power switch off\r
+\r
+ retlw 0\r
+\r
+ ; we bombed out in rx-ing sleep string\r
+sleep_reset\r
+ clrf sleep_state\r
+ clrf sleep_timeout\r
+ retlw 0\r
+ \r
+ ; increment to next state, and reset sleep timeout\r
+sleep_cont\r
+ incf sleep_state,1\r
+ movlw SLEEP_TIMEOUT\r
+ movwf sleep_timeout\r
+ retlw 0\r
+\r
+; START MAIN LOOP -----------------------------------------------\r
+\r
+main \r
+ call inch_n_delay ; RS232 RX and 1 second delay\r
+\r
+ ; sample V, I, and print if we received a 'w' or a ' '\r
+\r
+ movlw 'w'\r
+ subwf SERBUFI,0\r
+ btfsc STATUS,Z ; skip if SERBUFI != 'w'\r
+ goto sample \r
+\r
+ movlw '.'\r
+ subwf SERBUFI,0\r
+ btfss STATUS,Z ; skip if SERBUFI == ' '\r
+ goto no_print \r
+\r
+ ; sample AN[0] (voltage)\r
+sample\r
+ movlw b'10110001'\r
+ movwf ADCON0 \r
+ bsf ADCON0,1 ; start A/D conversion\r
+wait_adc_v\r
+ btfsc ADCON0,1 ; skip if A/D conversion finished\r
+ goto wait_adc_v\r
+\r
+ ; print 'wispcar' to get host to call script called wispcar.\r
+ ; This script can then parse wispcar output\r
+\r
+ movlw 'w'\r
+ call outch_n\r
+ movlw 'i'\r
+ call outch_n\r
+ movlw 's'\r
+ call outch_n\r
+ movlw 'p'\r
+ call outch_n\r
+ movlw 'c'\r
+ call outch_n\r
+ movlw 'a'\r
+ call outch_n\r
+ movlw 'r'\r
+ call outch_n\r
+ movlw ' '\r
+ call outch_n\r
+\r
+ ; print voltage to RS232\r
+\r
+ movf ADRES, 0\r
+ movwf BIN\r
+ call BIN2BCD ; convert voltage to decimal ASCII \r
+\r
+ movf huns, 0 \r
+ call outch_n\r
+ movf tens, 0\r
+ call outch_n\r
+ movf ones, 0\r
+ call outch_n\r
+\r
+ ; print space\r
+\r
+ movlw ' '\r
+ call outch_n\r
+\r
+ ; sample AN[1] (current)\r
+\r
+ movlw b'10111001'\r
+ movwf ADCON0 \r
+ bsf ADCON0,1 ; start A/D conversion\r
+wait_adc_i\r
+ btfsc ADCON0,1 ; skip if A/D conversion finished\r
+ goto wait_adc_i\r
+\r
+ ; print current to RS232\r
+\r
+ movf ADRES, 0\r
+ movwf BIN\r
+ call BIN2BCD ; convert current to decimal & ASCII \r
+\r
+ movf huns, 0 \r
+ call outch_n\r
+ movf tens, 0\r
+ call outch_n\r
+ movf ones, 0\r
+ call outch_n\r
+\r
+ ; print rx char\r
+\r
+ movlw ' '\r
+ call outch_n\r
+ movf SERBUFI, 0\r
+ call outch_n\r
+\r
+ ; print rx char in dec\r
+\r
+ movlw ' '\r
+ call outch_n\r
+ movf SERBUFI, 0\r
+ movwf BIN\r
+ call BIN2BCD ; convert rx char to decimal & ASCII \r
+\r
+ movf huns, 0 \r
+ call outch_n\r
+ movf tens, 0\r
+ call outch_n\r
+ movf ones, 0\r
+ call outch_n\r
+\r
+ ; print wd_timeout in dec\r
+\r
+ movlw ' '\r
+ call outch_n\r
+ movf wd_timeout, 0\r
+ movwf BIN\r
+ call BIN2BCD \r
+\r
+ movf huns, 0 \r
+ call outch_n\r
+ movf tens, 0\r
+ call outch_n\r
+ movf ones, 0\r
+ call outch_n\r
+\r
+ ; print wd_fire in dec\r
+\r
+ movlw ' '\r
+ call outch_n\r
+ movf wd_fire, 0\r
+ movwf BIN\r
+ call BIN2BCD \r
+\r
+ movf huns, 0 \r
+ call outch_n\r
+ movf tens, 0\r
+ call outch_n\r
+ movf ones, 0\r
+ call outch_n\r
+\r
+ ; print sleep_state \r
+\r
+ movlw ' '\r
+ call outch_n\r
+ movlw '0' \r
+ addwf sleep_state,0\r
+ call outch_n\r
+\r
+ ; print sleep timer in dec\r
+\r
+ movlw ' '\r
+ call outch_n\r
+ movlw '0' ; print x\r
+ bsf FSR,5\r
+ addwf x,0\r
+ bcf FSR,5\r
+ call outch_n\r
+ movlw '0' ; print y\r
+ bsf FSR,5\r
+ addwf y,0\r
+ bcf FSR,5\r
+ call outch_n\r
+ movlw '0' ; print z\r
+ bsf FSR,5\r
+ addwf z,0\r
+ bcf FSR,5\r
+ call outch_n\r
+\r
+ ; print restart_flag\r
+\r
+ movlw ' '\r
+ call outch_n\r
+ movf restart_flag, 0\r
+ call outch_n\r
+\r
+ ; print CR-LF\r
+\r
+ movlw '\r'\r
+ call outch_n\r
+ movlw '\n'\r
+ call outch_n\r
+\r
+no_print\r
+ ; has watchdog fired (wd_timeout == 0) ?\r
+\r
+ movf wd_timeout,1\r
+ btfsc STATUS,Z ; skip if not fired\r
+ goto watchdog_firing ; Yes? Then goto watchdog firing code\r
+ \r
+ ; are we sleeping (sleeping == 1)?\r
+\r
+ movf sleeping,1\r
+ btfss STATUS,Z ; skip if not sleeping\r
+ goto snooze ; Yes? Then goto sleeping code\r
+\r
+ ; No? Then count down watchdog\r
+\r
+ movlw 1\r
+ subwf wd_timeout,1\r
+\r
+ ; Has watchdog just fired (wd_timeout == 0)?\r
+\r
+ btfss STATUS,Z ; skip if wd_countdown is zero\r
+ goto dec_sleeptimeout ; No - continue\r
+\r
+ ; Yes - start watchdog firing code\r
+\r
+ bcf GPIO,1 ; PowerSwitch Off\r
+ movlw WD_FIRE\r
+ movwf wd_fire\r
+ goto main\r
+\r
+dec_sleeptimeout\r
+ ; has sleep state machine accepted a rx char?\r
+\r
+ movf sleep_state,1\r
+ btfsc STATUS,Z \r
+ goto main ; No? Then continue processing\r
+\r
+ decfsz sleep_timeout,1\r
+ goto main\r
+\r
+ ; sleep state machine timeout, reset state machine\r
+ clrf sleep_state\r
+ goto main\r
+\r
+ ; watchdog firing code\r
+\r
+watchdog_firing\r
+\r
+ movlw 1\r
+\r
+ ; DR June 2009 - make watchdog fire forerver, cutting power\r
+ ; from battery indefinately until host returns\r
+ subwf wd_fire,0\r
+\r
+ ; watchdog firing complete? (wd_fire == 0)?\r
+\r
+ btfss STATUS,Z ; skip if wd_fire is zero\r
+ goto main ; No - continue\r
+\r
+ ; Yes - reset watchdog\r
+\r
+ bsf GPIO,1 ; PowerSwitch On\r
+ movlw WD_TIMEOUT\r
+ movwf wd_timeout\r
+\r
+ ; Indicate WD has fired since last 'w' sent by host. A rx of\r
+ ; 'w' resets this flag.\r
+ \r
+ movlw WD_FLAG\r
+ movwf restart_flag\r
+ \r
+ goto main\r
+\r
+ ; sleeping code\r
+ ; sleep for xyz seconds, need to count down in decimal\r
+snooze\r
+ ; 3 digit decimal count down timer xyz, e.g. 999, 998,...001,000\r
+ ; it's time's like these I wonder why I volunteered for this project!! :-)\r
+ ; see countdown.c for C version of this algorithm\r
+\r
+ bsf FSR,5\r
+ movf z,1\r
+ btfss STATUS,Z\r
+ goto z_not_zero\r
+ movf y,1\r
+ btfss STATUS,Z\r
+ goto y_not_zero\r
+ movf x,1\r
+ btfss STATUS,Z\r
+ goto x_not_zero\r
+ \r
+ ; x=y=z=0 so we are finished\r
+\r
+ bcf FSR,5\r
+ goto sleep_finished\r
+\r
+z_not_zero\r
+ decf z,1\r
+ goto continue_sleep\r
+\r
+y_not_zero\r
+ decf y,1\r
+ movlw 9\r
+ movwf z\r
+ goto continue_sleep\r
+\r
+x_not_zero\r
+ decf x,1\r
+ movlw 9\r
+ movwf y\r
+ movwf z\r
+ goto continue_sleep\r
+\r
+ ; sleep finished\r
+\r
+sleep_finished\r
+ bsf GPIO,1 ; PowerSwitch On\r
+ movlw WD_TIMEOUT ; reset watchdog for good measure\r
+ movwf wd_timeout\r
+ clrf wd_fire\r
+ clrf sleep_timeout ; clear sleep timeout counter\r
+ clrf sleeping ; clear sleep flag\r
+ \r
+ ; Indicate we have just woken up from a sleep. A rx of 'w'\r
+ ; resets this.\r
+ \r
+ movlw SLEEP_FLAG \r
+ movwf restart_flag\r
+ goto main\r
+ \r
+continue_sleep\r
+ bcf FSR,5\r
+ goto main\r
+ \r
+; END MAIN LOOP -----------------------------------------------\r
+\r
+ end\r
+\r
+\r