Bemix PIC code

From SlugWiki
Jump to: navigation, search

This is the first stable (2/4/05) version of the Bemix firmware. The latest version can be obtained from svn://bemix.mit.edu/var/svn/repos/bemix-pic/touchswitch.

The touch switches are polled in the main loop of the program. Each touch switch has a function that is called when it is touched. This makes it easy to change how each touch switch behaves (single shot, fast reapeat, slow repeat, etc).

The serial port is monitored by the interrupt. Each recieved byte is put in a buffer. The buffer is cleared whenever a packet header is recieved. Thus, when the end code is recieved, the buffer contains the entire packet (minus the header code). If the packet is addressed to this unit then rcvPacket is called to process the packet.

;;; =========================================
;;; BEMIX 3.0 PIC CODE
;;; version 1.0
;;; =========================================

	LIST p=16f627
	#include <P16F627.inc>

	errorlevel -302
	
	__CONFIG _BODEN_OFF & _CP_OFF & _DATA_CP_OFF & _PWRTE_OFF & _WDT_OFF & _LVP_OFF & _MCLRE_ON & _INTRC_OSC_NOCLKOUT

;;-------------------------------------------------------------------------------------------
;; Touch switch variables
;;
oldPortA	equ		0x20
portATemp	equ		0x21
portAChange	equ		0x22

TS_ENABLE	EQU		6					; on PORTA

	CBLOCK	0x23
		sw2count
		sw3count
;		sw4count:	2
;		sw5count:	2
	ENDC

;;-------------------------------------------------------------------------------------------
;; Serial port variables and constants
;;
SPBRG_VAL		EQU		.25				; 9600 at 4 MHz

ESC_CHAR		EQU		'\\'
HEADER_CHAR		EQU		'H'
END_CHAR		EQU		'E'

ADDRESS			EQU		'b'
SERVER_ADDRESS	EQU		0x01

DEBUG_PORT		EQU		.31
PING_PORT		EQU		.32
BEMIX_PORT		EQU		.64

TX_ENABLE		EQU		3				; on PORTB

RX_BUFFER_SIZE	EQU		.32
TX_BUFFER_SIZE	EQU		.32


	CBLOCK	0x31
		TxPtr
		TxEndPtr
		TxTemp
		TxHeader:	0x02
		TxPort
		TxBuffer: 	TX_BUFFER_SIZE
	ENDC

	CBLOCK	0xA0
		RxFlags
		RxPtr
		RxEndPtr
		RxTemp
		RxBuffer: 	RX_BUFFER_SIZE
	ENDC

; RxFlags
escRcv		equ		0					;last character revieved was the esc char
H			equ		1					;currently reading the header
toMe		equ		3					;transmission addressed to this unit


;;-------------------------------------------------------------------------------------------
;; Interrupt context saving
;;
	CBLOCK	0x70
		WREG_TEMP		
		STATUS_TEMP	
		PCLATH_TEMP
		FSR_TEMP
	ENDC

;; PUSH_MACRO
;; stores W, STATUS, PCLATH, FSR for context saving during interrupt
PUSH_MACRO 	MACRO 				
			movwf		WREG_TEMP	
			movf		STATUS,W	
			clrf		STATUS	
			movwf		STATUS_TEMP
			movf		PCLATH,W	
			movwf		PCLATH_TEMP
			clrf		PCLATH	
			movf		FSR,W	
			movwf		FSR_TEMP	
			ENDM 			

;; POP_MACRO
;; restores W, STATUS, PCLATH, FSR for context restoration during interrupt				
POP_MACRO 	MACRO 		
			clrf		STATUS		
			movf		FSR_TEMP,W	
			movwf		FSR			
			movf		PCLATH_TEMP,W	
			movwf		PCLATH		
			movf		STATUS_TEMP,W	
			movwf		STATUS
			swapf		WREG_TEMP,F
			swapf		WREG_TEMP,W
			ENDM 

;;-------------------------------------------------------------------------------------------
;; Serial Macros
;;

; transmit_macro
; transmits the entire TxBuffer to the specified destination and port
transmit_macro	MACRO	destination, port
	banksel	TxBuffer
	movlw	port
	movwf	TxPort
	movlw	destination
	call	transmit
	ENDM

; transmitByte_macro
; transmits the argument, bypassing the TxBuffer
transmitByte_macro	MACRO	byte
	movlw	byte
	call	transmitByte
	ENDM
					
; putTxBuffer_macro
; adds the argument to the end of the TxBuffer
putTxBuffer_macro	MACRO	byte
	movlw	byte
	call	putTxBuffer
	ENDM






;;-------------------------------------------------------------------------------------------
;; ORGs
;;
	org		0x000
	goto	start

	org		0x004
	goto	interrupt


;;-------------------------------------------------------------------------------------------
;; Main Program
;;

start:
	; initialize PORTA
	banksel		PORTA				
	clrf		PORTA
	banksel		CMCON
	movlw		0x07
	movwf		CMCON
	banksel		TRISA
	movlw		B'00111111'
	movwf		TRISA
	banksel		PORTA
	clrf		PORTA

	; initialize PORTB
	banksel		TRISB
	movlw		B'11000111'
	movwf		TRISB
	banksel		PORTB
	movlw		0xff
	movwf		PORTB
	

	; initialize USART
	banksel		SPBRG				; set baud rate
	movlw		SPBRG_VAL	
	movwf		SPBRG
	banksel		TXSTA				; enable transmission and high baud rate
	movlw		0x24		
	movwf		TXSTA
	banksel		RCSTA				; enable serial port and reception
	movlw		0x90			
	movwf		RCSTA

	; initialize interrupts
	movlw		0xc0				; enable global and peripheral ints
	movwf		INTCON
	banksel		PIE1				; enable Rx interrupt
	bsf			PIE1, RCIE

	; initilize touch switches
	banksel oldPortA
	clrf	oldPortA
	clrf	portAChange
	call	enableTouchSwitch

	; initialize Rx and Tx buffers
	call	resetTxBuffer
	call	resetRxBuffer
	banksel	RxFlags
	clrf	RxFlags

	; send test packet
	putTxBuffer_macro	'B'
	putTxBuffer_macro	'e'
	putTxBuffer_macro	'm'
	putTxBuffer_macro	'i'
	putTxBuffer_macro	'x'
	putTxBuffer_macro	' '
	putTxBuffer_macro	'v'
	putTxBuffer_macro	'3'
	putTxBuffer_macro	'.'
	putTxBuffer_macro	'0'
	transmit_macro		SERVER_ADDRESS, DEBUG_PORT

mainLoop:
	; poll touch switches
	banksel	PORTA
	movfw	PORTA
	movwf	portATemp
	xorwf	oldPortA, W
	andwf	PORTA, W
	movwf	portAChange
	movfw	portATemp
	movwf	oldPortA

	banksel	PORTA
	btfsc	PORTA,0
	call	btn1pushed

	banksel	PORTA
	btfsc	PORTA,1
	call	btn2pushed

	banksel	PORTA
	btfsc	PORTA,2
	call	btn3pushed

	banksel	PORTA
	btfsc	PORTA,3
	call	btn4pushed

	banksel	PORTA
	btfsc	PORTA,4
	call	btn5pushed

	goto	mainLoop

;;-------------------------------------------------------------------------------------------
;; Touch Switchs
;;

;; Touch Switch 1 - on/off
;; no repeat
btn1pushed:
	call	resetTxBuffer		; clear Tx buffer
	banksel	portAChange
	btfss	portAChange, 0		; test portAChange for switch 1
	return						; if change, transmit '1'
	putTxBuffer_macro	'1'								
	transmit_macro		SERVER_ADDRESS, BEMIX_PORT
	return

;; Touch Switch 2 - volume up
;; fast repeat
btn2pushed:
	call	resetTxBuffer		; clear Tx buffer
	banksel	portAChange
	btfsc	portAChange, 3		; clear sw2count when first touched
	clrf	sw2count
	incf	sw2count, F			; increment sw2count						
	btfss	STATUS, Z			; if sw2count rolled over, transmit '2'
	return
	putTxBuffer_macro	'2'
	transmit_macro		SERVER_ADDRESS, BEMIX_PORT
	return

;; Touch Switch 3 - volume down
;; fast repeat
btn3pushed:
	call	resetTxBuffer		
	banksel	portAChange
	btfsc	portAChange, 4	
	clrf	sw3count
	incf	sw3count, F					
	btfss	STATUS, Z
	return
	putTxBuffer_macro	'3'
	transmit_macro		SERVER_ADDRESS, BEMIX_PORT
	return

;; Touch Switch 4
;; no repeat
btn4pushed:
	call	resetTxBuffer	
	banksel	portAChange
	btfss	portAChange, 3	
	return
	putTxBuffer_macro	'4'								
	transmit_macro		SERVER_ADDRESS, BEMIX_PORT
	return

;; Touch Switch 5
;; no repeat
btn5pushed:
	call	resetTxBuffer	
	banksel	portAChange
	btfss	portAChange, 4	
	return				
	putTxBuffer_macro	'5'								
	transmit_macro		SERVER_ADDRESS, BEMIX_PORT
	return


	
;;-------------------------------------------------------------------------------------------
;; Interrupt/Reception
;;

; resetRxBuffer
; sets RxPtr and RxEndPtr to their starting locations
resetRxBuffer:
	banksel	RxBuffer
	movlw	RxBuffer
	movwf	RxPtr
	movwf	RxEndPtr
	return

; putRxBuffer
; adds contents of W to the end of RxBuffer and stores in RxTemp
; also handles RxPtr (increments, resets when out of range)
putRxBuffer:
	banksel	RxBuffer			; select memory bank
	bankisel RxBuffer
	movwf	RxTemp				; save W to RxTemp
	movfw	RxPtr				; load RxPtr to FSR
	movwf	FSR
	movfw	RxTemp				; copy RxTemp to INDF (RxBuffer at RxPtr)
	movwf	INDF
	incf	RxPtr, F			; increment RxPtr
	movfw	RxPtr				; reset RxPtr if out of range
	sublw	RxBuffer+RX_BUFFER_SIZE
	btfsc	STATUS, Z
	call	resetRxBuffer
	return	

;; interrupt service routine
;; recieves data, stores in RxBuffer, calls rcvPacket when a packet has been recieved
interrupt:
	PUSH_MACRO					; save context

	banksel	PIR1				; clear interrupt flag
	bcf		PIR1, RCIF

	banksel	RCREG				; read RCREG and buffer it
	movfw	RCREG
	call	putRxBuffer

	banksel	RxBuffer			; if previous character was escape, goto handleEsc
	movfw	RxTemp
	btfsc	RxFlags,escRcv
	goto	handleEsc	

	btfsc	RxFlags,H			; if this is the header, goto handleHdr
	goto	handleHdr

	xorlw	ESC_CHAR			; if current character is escape, set RxFlags, escRcv
	btfsc	STATUS, Z
	bsf		RxFlags, escRcv
	xorlw	ESC_CHAR

	goto	endInt

handleEsc:
	banksel	RxBuffer
	movfw	RxTemp
	xorlw	HEADER_CHAR			; header
	btfsc	STATUS, Z
	bsf		RxFlags, H
	btfsc	STATUS, Z
	call	resetRxBuffer
	xorlw	HEADER_CHAR

	banksel	RxBuffer
	movfw	RxTemp
	xorlw	END_CHAR			; end
	btfsc	STATUS, Z
	goto	endOfPacket
	xorlw	END_CHAR
	
	banksel	RxFlags
	bcf		RxFlags, escRcv		; second escape
	goto	endInt

endOfPacket:
	banksel	RxBuffer
	movfw	RxPtr
	movwf	RxEndPtr
	
	btfsc	RxFlags, toMe
	call	rcvPacket
	banksel	RxFlags
	clrf	RxFlags
	goto	endInt

handleHdr:
	banksel	RxBuffer			; load RxTemp to W
	movfw	RxTemp
	bcf		RxFlags, H			; clear header flag
	xorlw	ADDRESS
	btfsc	STATUS, Z			; check if address matches
	bsf		RxFlags, toMe
	xorlw	ADDRESS
	goto	endInt

endInt:		
	POP_MACRO
	retfie

;; rcvPacket
;; called when a packet addressed to this unit is recieved
;; determines packet type (by port number) and calls appropriate function

;
; BROKEN!!! (some of the time)
;

rcvPacket:
	banksel	RxBuffer
	movfw	RxBuffer+2				;port
	
	xorlw	PING_PORT
	btfsc	STATUS, Z
	call	pingPacket
	xorlw	PING_PORT

	xorlw	BEMIX_PORT
	btfsc	STATUS, Z
	call	bemixPacket
	xorlw	BEMIX_PORT

	return


pingPacket:
	banksel	TxBuffer
	movlw	PING_PORT
	movwf	TxPort
	banksel	RxBuffer
	movfw	RxBuffer+1			; source address
	call	transmit
	return

bemixPacket:
	movfw	RxBuffer+3
	xorlw	'E'
	btfsc	STATUS, Z
	call	enableTouchSwitch
	xorlw	'E'

	xorlw	'D'
	btfsc	STATUS, Z
	call	disableTouchSwitch
	xorlw	'D'
	return

enableTouchSwitch:
	banksel		PORTA
	bcf			PORTA, TS_ENABLE
	return
disableTouchSwitch
	banksel		PORTA
	bsf			PORTA, TS_ENABLE
	return

;;-------------------------------------------------------------------------------------------
;; TX functions
;;

;; putTxBuffer
;; adds a byte to the back of the TxBuffer, increments TxPtr and TxEndPtr,
;; also deals with ESC_CHAR
;; changes W, bank
putTxBuffer:	
	banksel		TxBuffer			; save value to be added in TxTemp
	bankisel	TxBuffer
	movwf		TxTemp			

	movfw		TxPtr				; move to end of TxBuffer
	movwf		FSR

	movfw		TxTemp				; load value and write to end of buffer
	movwf		INDF

	incf		TxPtr,F				; increment pointers
	incf		TxEndPtr,F

	xorlw		ESC_CHAR			; check if an escape character was written
	btfss		STATUS, Z
	return							; if not, don't do anything else
	incf		FSR, F				; otherwise, add a second escape character to TxBuffer
	movlw		ESC_CHAR
	movwf		INDF
	incf		TxPtr,F
	incf		TxEndPtr,F	

	; need to check if TxPtr is out of range

	return


; getTxData
; loads byte from the TxBuffer into W and increments TxPtr
; changes W and bank
getTxData:	MACRO
			banksel		TxBuffer
			movfw		TxPtr
			bankisel	TxBuffer
			movwf		FSR
			movfw		INDF
			incf		TxPtr,F
			ENDM


;; transmitxByte
;; transmits W
transmitByte:
	banksel		PIR1
	btfss		PIR1, TXIF
	goto		$-1					; wait until USART is ready for more TX data
	banksel		TXREG
	movwf		TXREG				; transmit W
	return	


; resetTxBuffer
; sets TxPtr and TxEndPtr to their starting locations
; changes W, bank
resetTxBuffer:
	banksel	TxBuffer
	movlw	TxBuffer
	movwf	TxPtr
	movwf	TxEndPtr
	return


;; transmit
;; adds a header and transmits contents of TxBuffer to address in W, on the port specified by TxPort
;; changes W, bank
transmit:
	banksel		PORTB				; RS485 out of tristate
	bsf			PORTB, TX_ENABLE

	banksel		TxBuffer			; prepare the header
	movwf		TxHeader
	movlw		ADDRESS
	movwf		TxHeader+1
	movfw		TxPort
	movwf		TxHeader+2

	transmitByte_macro	ESC_CHAR	; transmit header sequence
	transmitByte_macro	HEADER_CHAR

	banksel		TxBuffer
	movlw		TxHeader			; set TxPointer to the beginning of the header
	movwf		TxPtr

TxLoop:
	getTxData						; load data at TxPtr into W
	call		transmitByte		; transmit W
	banksel		TxBuffer
	movfw		TxEndPtr
	subwf		TxPtr,W				
	btfss		STATUS, Z			; loop until TxBuffer is empty
	goto		TxLoop

	transmitByte_macro	ESC_CHAR	; transmit end sequence
	transmitByte_macro	END_CHAR
	transmitByte_macro	0x0d		; transmit CR+LF
	transmitByte_macro	0x0a

	banksel		PORTB				; RS485 into tristate
	bcf			PORTB, TX_ENABLE			

	call		resetTxBuffer

	return



	end