;
		;**********************************************************************
		; i2ccmd.asm	- Polled and Interrupt based I2C and EEPROM routines
		;**********************************************************************
		;
		; John E. Andrews
		; April 3rd, 1998
		;
		; The following functions are included:
		;  InitI2C	; init the SSP peripheral and variables for I2C operation
		;  I2CRead	; read one byte from i2c address x
		;  I2CWrite	; write an x parameter to i2c addr x
		;  EERead	; read eeprom location x
		;  EEWrite	; write an x parameter into eeprom location x
		;  KickEERead	; read a string at eeprom location x via interrupts
		;  KickEEWrite	; write a string at eeprom location x via interrupts
		;  KickI2CRead	; read a string from an i2c slave via interrupts
		;  KickI2CWrt	; write reply addr, byte count and data to i2c addr 
		;  I2CIsr		; I2C interrupt service routine
		;
		; The init function and the routines to start i2c master data tranfers
		;  are called by inline code. The init function is called at reset and 
		;  the master data transfers are associated with PICos commands.
		; I2CIsr provides continuous interrupt based slave or master data
		;  transfers and is called from the peripheral interrupt vector. It is
		;  terminated by a return to the peripheral interrupt service routine
		;  which restores context and performs the retfie. 
		;
		; The default i2c slave address is defined here
	DfltSlvAddr	equ 0x23
		; This address is shifted 1 bit left and used to match the address
		;  supplied at the beginning of an i2c transfer. This makes the lsb
		;  a don't care which is used by i2c to provide Read/write info.
		; This address shouldn't be 0 since this is the general call address
		;  and it shouldn't be hex 50-5F since all 5x addresses are reserved 
		;  by eeprom devices. Valid addresses are from 1-4F and 60-7F.
		; This address can be changed at run time by the i2cAddr command.
		;
		; This data statement stores a constant ascii string in program 
		;  memory. Its copied to a ram buffer using the CpyTbl2Buf macro in
		;  InitI2C and is output during slave transmit by I2CIsr.
SlvRdD	; initial slave read data message
	data	"Va Tech Rules!",0
		;
		;**********************************************************************
InitI2C	; initialize I2C operation after device reset
		;**********************************************************************
		;
		; ***** Variables for I2C operation *****
		; 
	i2cRxBufferSize	equ 40			; size of buffer for slave Rx data
		;
	cblock							; declare bank 0 variables
		i2cState					; current I2C state
		i2cSlvAddr					; addr of i2c slave, 0-7F << 1, lsb=0
		; slave Rx buffer, allow extra char for 0 fill by command parser
		i2cRxBuffer:	i2cRxBufferSize+1
		i2cRxPtr					; pointer into Rx buffer used by inline code
		i2cIntRxPtr					; pointer into Rx buffer used by isr
		i2cDataPtr					; buffer pointer used for result output
		i2cAddr						; i2c addr for master transmit
		i2cRpyPend					; slave addr pending reply
		i2cRpyFncH					; function addr to involke on reply hi byte
		i2cRpyFncL					; function addr to involke on reply lo byte
		i2cByteCnt					; number of bytes in transfer packet
		i2cEEAddr					; addr in eeprom for current write cycle
		i2cFlags					; flag bits
		i2cSlvRdBuff:	20			; buffer holding data for slave read
		i2cSlvPtr					; isr pointer into i2cSlvRdBuff
	endc
		;
		; bit flag definitions for i2cFlags
	i2cRxRdy	equ	0
		;
		; ***** executable code to init I2C operation *****
		; 
		; This function label is called once after device reset
		movlw	DfltSlvAddr<<1		; load default i2c slave address
		movwf	i2cSlvAddr			;  into gpr storage location
		bcf		i2cSlvAddr, 0		; clear lsb for Read/write bit
		setf	i2cRpyPend			; init reply pending address to FF
		clrf	i2cFlags			; init all flags to off
		;
		; Init buffer to be transmitted on slave read
		CpyTbl2Buf	SlvRdD, i2cSlvRdBuff
		;
		; fall through to reset i2c to slave mode
		;
		;**********************************************************************
RstI2C	; reset the SSP peripheral and variables for I2C slave operation
		;**********************************************************************
		;
		; This function can be called by any routine wishing to reset the ssp
		;  to i2c slave operation. It sets up the SSP peripheral to provide 
		;  buffered, line based, interrupt driven i2c slave receive and polled
		;  and interrupt driven i2c master transmit. EEPROM write and read are
		;  also provided including interrupt state machine driven, buffered, 
		;  string input and output.
		;
		movlb	6					; select sfr bank for ssp
		movfp	i2cSlvAddr, WREG	; fetch i2c slave address and
		movwf	SSPADD				; load it into slave addr register
		movlw	0x36				; enable ssp, set CKP, select I2C slave
		movwf	SSPCON1				; in SSPCON1
		clrf	i2cState			; init i2c state to idle
		movlb	4					; select sfr bank for PIE2
		bcf		PIR2, SSPIF			; init interrupt flag
		bsf		PIE2, SSPIE			; enable SSP interrupts
		return
		;
		;*********************************************************************
		; i2c slave mode command functions
		;*********************************************************************
SetI2C	; load hexidecimal parameter into i2c slave address
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"I2CADDR=x\r", CmdPC, "Set I2C slave address = 0-7F\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		; copy hexidecimal parameter from buffer to SSPADD
		movlw	cmdPrmBuff			; load parameter buffer addr
		movwf	FSR1				; into FSR1
		movpf	INDF1, WREG			; copy parameter to W
		; shift address out of lsb which i2c uses for R/w bit
		rlncf	WREG				; shift address left 1` bit
		bcf		WREG, 0				; clear lsb
		movwf	i2cSlvAddr			; save in gpr
		call	RstI2C				; set i2c slave address in ssp
		; fall through to DspI2C
		;*********************************************************************
DspI2C	; create output string reporting i2c slave addr as a hex number
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"I2CADDR\r", CmdPC, "Display I2C slave address\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		; copy first part of output string into output buffer using FSR0
		CpyTbl2Out	SlvD
		; copy i2cSlvAddr value into output buffer as a hex number
		rrncf	i2cSlvAddr, W		; unshift i2c slave addr into W
		bcf		WREG, 7				; clear msb of unshifted addr
		movlb	1					; select SFR bank for PORTD
		movwf	PORTD				; display on portd LEDs
		call	Hex2Buf				; convert hex value into output buffer
		; copy hex = into same output buffer using FSR0
		CpyTbl2Out	HxEqD
		; display bits of address
		movlw	'0'					; load ascii 0 char into W
		btfsc	i2cSlvAddr, 7		; skip if msb is clear
		movlw	'1'					; load ascii 1 char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'0'					; load ascii 0 char into W
		btfsc	i2cSlvAddr, 6		; skip if nsb is clear
		movlw	'1'					; load ascii 1 char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'0'					; load ascii 0 char into W
		btfsc	i2cSlvAddr, 5		; skip if nsb is clear
		movlw	'1'					; load ascii 1 char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'0'					; load ascii 0 char into W
		btfsc	i2cSlvAddr, 4		; skip if nsb is clear
		movlw	'1'					; load ascii 1 char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	' '					; load ascii ' ' into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'0'					; load ascii 0 char into W
		btfsc	i2cSlvAddr, 3		; skip if nsb is clear
		movlw	'1'					; load ascii 1 char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'0'					; load ascii 0 char into W
		btfsc	i2cSlvAddr, 2		; skip if nsb is clear
		movlw	'1'					; load ascii 1 char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'0'					; load ascii 0 char into W
		btfsc	i2cSlvAddr, 1		; skip if lsb is clear
		movlw	'1'					; load ascii 1 char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'x'					; load ascii x char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'\n'				; load ascii LF char into W
		movwf	INDF0				; place char into output buffer
		incf	FSR0				; inc pointer to next char location
		movlw	'\r'				; load ascii CR into last location in buff
		movwf	INDF0				;  CR terminates cmd line when resubmited
		return						; return from Cmd
		; This is the end of the functions executable code
		;
		; These data statements store constant ascii output strings in program 
		;  memory. They're accessed using the CpyTbl2Out macro
SlvD	; constant string for slave addr display
	data	"\nI2C slave addr is ",0
HxEqD	; constant string for hex = display
	data	" hex = ",0
		;
		;*********************************************************************
		; i2c master mode data transfer command functions
		;*********************************************************************
Wait4SSPIF	macro	; this is equivalent to waiting for an ssp interrupt
		;*********************************************************************
		;
		; switch banks and wait for SSPIF, clear and switch back to ssp bank
		movlb	1					; select sfr bank for peripheral ints
		btfss	PIR1, SSPIF			; poll for interrupt flag
		goto	$-1					; until then wait
		bcf		PIR1, SSPIF			; s/w int flag clear
		movlb	6					; select sfr bank for ssp
	endm
		;
		;*********************************************************************
I2CRead	; read one byte from i2c address x
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"I2Cx\r", CmdPC, "Read byte at I2C addr x=0-7F\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		bsf		SSPCON2, SEN		; initiate a start condition
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		movlw	cmdPrmBuff			; load addr of parameter buffer
		movwf	FSR1				; into FSR1
		rlncf	INDF1, W			; read shifted i2c address into W
		bsf		WREG, 0				; set R/w bit for read
		movwf	SSPBUF				; output i2c addr parameter
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, RCEN		; start receiving data byte
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfss	SSPSTAT, BF			; skip once BF is set
		goto	$-1					; until then wait
		btfsc	SSPCON2, RCEN		; skip once RCEN is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, ACKDT		; generate nack to terminate read
		bsf		SSPCON2, ACKEN		; start nack sequence
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, ACKEN		; skip once ACKEN is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, PEN		; initiate a stop sequence
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		; create output string reporting value of data byte
		; copy first part of output string into output buffer using FSR0
		CpyTbl2Out	I2CD
		; copy i2c addr into output buffer as a hex number
		movfp	INDF1, WREG			; read ee memory addr into W
		call	Hex2Buf				; convert hex value into output buffer
		; copy = into same output buffer using FSR0
		CpyTbl2Out	EqD
		; copy data byte into output buffer as a hexidecimal number
		movfp	SSPBUF, WREG		; read data byte into W
		call	Hex2Buf				; convert hex value into output buffer
		; put a LF and CR after the data
		movlw	'\n'				; load LF char
		movwf	INDF0				; put it into the output string
		incf	FSR0				; point to next output char location
		movlw	'\r'				; load ascii CR into last location in buff
		movwf	INDF0				;  CR terminates cmd line when resubmited
		call	RstI2C				; reset to i2c slave operation
		return						; return from Cmd
		; This is the end of the functions executable code
		;
		; These data statements store constant ascii output strings in program 
		;  memory. They're accessed using the CpyTbl2Out macro.
I2CD		; constant string for i2c display
	data	"\nI2C addr ",0
EqD		; constant string for = display
	data	" = ",0
		;
		;*********************************************************************
I2CWrite	; write an x parameter to i2c addr x
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"I2Cx=x\r", CmdPC, "Write x at I2C addr x=0-7F\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		bsf		SSPCON2, SEN		; initiate a start condition
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		movlw	cmdPrmBuff			; load addr of start of parameter buffer
		movwf	FSR1				; into FSR1
		rlncf	INDF1, W			; read shifted i2c address into W
		bcf		WREG, 0				; clear R/w bit for write
		movwf	SSPBUF				; output i2c addr parameter
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	FSR1				; point to data parameter
		movpf	INDF1, SSPBUF		; write data parameter to i2c
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, PEN		; initiate a stop sequence
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		call	RstI2C				; reset to i2c slave operation
		return						; return null result string from Cmd
		;
		;*********************************************************************
EERead	; read eeprom location x
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"EEx\r", CmdPC, "Read byte at EEPROM addr x\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		movlw	cmdPrmBuff			; load addr of parameter buffer
		movwf	FSR1				; into FSR1
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		bsf		SSPCON2, SEN		; initiate a start condition
		Wait4SSPIF					; wait for SSPIF in PIR
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		movlw	0xA0				; load I2C addr parameter for ee write
		movwf	SSPBUF				; output I2C addr parameter for ee write
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		movpf	INDF1, SSPBUF		; output ee memory addr parameter  
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, RSEN		; initiate a restart condition
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, RSEN		; skip once RSEN is cleared
		goto	$-1					; until then wait
		movlw	0xA1				; load I2C addr parameter for ee read
		movwf	SSPBUF				; output I2C addr parameter for ee read
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, RCEN		; start receiving data byte
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfss	SSPSTAT, BF			; skip once BF is set
		goto	$-1					; until then wait
		btfsc	SSPCON2, RCEN		; skip once RCEN is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, ACKDT		; generate nack to terminate ee read
		bsf		SSPCON2, ACKEN		; start nack sequence
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, ACKEN		; skip once ACKEN is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, PEN		; initiate a stop sequence
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		; create output string reporting value of data byte
		; copy first part of output string into output buffer using FSR0
		CpyTbl2Out	EED
		; copy ee memory addr into output buffer as a hexidecimal number
		movfp	INDF1, WREG			; read ee memory addr into W
		call	Hex2Buf				; convert hex value into output buffer
		; copy = into same output buffer using FSR0
		CpyTbl2Out	EqD
		; copy data byte into output buffer as a hexidecimal number
		movfp	SSPBUF, WREG		; read data byte into W
		call	Hex2Buf				; convert hex value into output buffer
		; put a LF and CR after the data
		movlw	'\n'				; load LF char
		movwf	INDF0				; put it into the output string
		incf	FSR0				; point to next output char location
		movlw	'\r'				; load ascii CR into last location in buff
		movwf	INDF0				;  CR terminates cmd line when resubmited
		call	RstI2C				; reset to i2c slave operation
		return						; return from Cmd
		; This is the end of the functions executable code
		;
		; These data statements store constant ascii output strings in program 
		;  memory. They're accessed using the CpyTbl2Buf and CpyTblCont macros 
		;  with the addresses given by the labels.
EED		; constant string for ee display
	data	"\nEEPROM addr ",0
		;
		;*********************************************************************
EEWrite	; write an x parameter into eeprom location x
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"EEx=x\r", CmdPC, "Write x at EEPROM addr x\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		movlw	cmdPrmBuff			; load addr of start of parameter buffer
		movwf	FSR1				; into FSR1
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		bsf		SSPCON2, SEN		; initiate a start condition
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		movlw	0xA0				; load I2C addr parameter for ee write
		movwf	SSPBUF				; output I2C addr parameter for ee write
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		movpf	INDF1, SSPBUF		; output ee memory addr parameter  
		Wait4SSPIF					; wait for SSPIF in PIR1
		incf	FSR1				; point to data parameter
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		movpf	INDF1, SSPBUF		; write data parameter to ee
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		bsf		SSPCON2, PEN		; initiate a stop sequence
		Wait4SSPIF					; wait for SSPIF in PIR1
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		call	RstI2C				; reset to i2c slave operation
		return						; return null result string from Cmd
		;
		;*********************************************************************
KickEERead	; read a string starting at eeprom location x via interrupts
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"S@EEx\r", CmdPC, "Read string starting at EEPROM addr x\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		; Initialize flags and pointers for interrupt based I2C master read.
		;
		; wait for any ongoing buffered I2C activity to complete
		tstfsz	i2cState			; skip when I2C xfer complete
		goto	$-1					; until then wait
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		movlw	.10					; load value for EERdStart into W
		movwf	i2cState			; set I2C state to read start complete
		movlb	4					; select sfr bank for PIE2
		bcf		PIR2, SSPIF			; init interrupt flag
		bsf		PIE2, SSPIE			; enable SSP interrupts
		movlb	6					; select sfr bank for ssp
		bsf		SSPCON2, SEN		; initiate a start sequence
		; the resulting interrupt kicks off the i2c int based state machine
		; wait here until int based I2C read is complete
		tstfsz	i2cState			; skip once state is idle
		goto	$-1					; until then wait
		return						; return result string built by I2CIsr
		;
		;**********************************************************************
KickEEWrite	; write a string starting at eeprom location x via interrupts
		;**********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"S@EEx=s\r", CmdPC, "Write s starting at EEPROM addr x\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		; This function initiates an interrupt driven, buffered, i2c master 
		;  write to eeprom memory. The i2c bus addr and R/w bit are constant
		;  0xA1 and 0xA0 respectively. The starting eeprom memory addr is 
		;  provided by Cmd in cmdPrmBuff[0] and an ascii, 0 terminated, string
		;  parameter follows.
		; An 8 byte eeprom write buffer size is assumed. When the least 
		;  significant three bits of the just completed ee write addr = 7 then
		;  stop, start, i2c addr and R/w, and ee momory addr sequences are
		;  performed by succesive SSPIF interrupts. Then the data write 
		;  interrupt sequence continues until the 0 termination is reached.
		;
		; Initialize flags and pointers for interrupt based I2C master write.
		;
		; wait for any ongoing buffered I2C activity to complete
		tstfsz	i2cState			; skip when I2C xfer complete
		goto	$-1					; until then wait
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		; init ee memory addr and ptr to ee data parameters
		movlw	cmdPrmBuff			; load cmd parameter buffer addr
		movwf	FSR1				; into FSR1
		movpf	INDF1, i2cEEAddr	; save ee memory write addr parameter
		incf	FSR1				; inc pointer to first data value
		movpf	FSR1, i2cDataPtr	; save ptr into I2C master buffer ptr
		; init ssp peripheral to 100KHz i2c master @ 16MHz
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		incf	i2cState			; set I2C state for write start complete
		movlb	4					; select sfr bank for PIE2
		bcf		PIR2, SSPIF			; init interrupt flag
		bsf		PIE2, SSPIE			; enable SSP interrupts
		movlb	6					; select sfr bank for ssp
		bsf		SSPCON2, SEN		; initiate a start sequence
		; the resulting interrupt kicks off the i2c int based state machine
		; wait here until int based I2C write is complete to prevent buffer crash
		tstfsz	i2cState			; skip once state is idle
		goto	$-1					; until then wait
		return						; I2C start initiated, return from Cmd
		;
		;*********************************************************************
KickI2CRead	; read a string from an i2c slave via interrupts
		;*********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"I2Cx:\r", CmdPC, "Read string from i2c slave addr x\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		; Initialize flags and pointers for interrupt based I2C master read.
		;
		; wait for any ongoing buffered I2C activity to complete
		tstfsz	i2cState			; skip when I2C xfer complete
		goto	$-1					; until then wait
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		movlw	.24					; load value for MstrRdStart into W
		movwf	i2cState			; set I2C state to read start complete
		movlb	4					; select sfr bank for PIE2
		bcf		PIR2, SSPIF			; init interrupt flag
		bsf		PIE2, SSPIE			; enable SSP interrupts
		movlb	6					; select sfr bank for ssp
		bsf		SSPCON2, SEN		; initiate a start sequence
		; the resulting interrupt kicks off the i2c int based state machine
		; wait here until int based I2C read is complete
		tstfsz	i2cState			; skip once state is idle
		goto	$-1					; until then wait
		return						; return result string built by I2CIsr
		;
		;**********************************************************************
KickI2CWrt	; write reply addr, byte count and data to i2c addr via interrupts
		;**********************************************************************
		; install this command in the CmdMenu lookup table
	CmdPC = $						; save current inline assembly PC value
	org CurCmdMenuAdr				; set assembly PC to addr for new entry
	; CmdMenu table entry
	data	"I2Cx:s\r", CmdPC, "Xfer s to I2C addr x for execution\r\n"
	CurCmdMenuAdr = $				; set current CmdMenu addr for next entry
	org CmdPC						; begin cmd code gen at inline address
		;
		; This function initiates an interrupt driven, buffered, i2c master 
		;  write to an i2c slave. The i2c slave addr is provided by Cmd in 
		;  cmdPrmBuff[0] and an ascii, 0 terminated, string parameter follows.
		; The characters in the string are counted and transmitted until the
		;  byte count is exhausted.
		;
		; Initialize flags and pointers for interrupt based I2C master write.
		;
		; wait for any ongoing buffered I2C activity to complete
		tstfsz	i2cState			; skip when I2C xfer complete
		goto	$-1					; until then wait
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		; init i2c addr
		movlw	cmdPrmBuff			; load cmd parameter buffer addr
		movwf	FSR1				; into FSR1
		movpf	INDF1, i2cAddr		; save i2c addr parameter into addr gpr
		rlncf	i2cAddr				; shift i2c addr out of lsb
		bcf		i2cAddr, 0			; clear lsb for write
		movpf	FSR1, i2cDataPtr	; save ptr prestart into master buffer ptr
		clrf	i2cByteCnt			; init byte count
		; loop here to count chars until 0 termination
		incf	FSR1				; inc to next char
		incf	i2cByteCnt			; inc byte count
		tstfsz	INDF1				; skip if current char is 0
		goto	$-3					; otherwise test next char
		movlw	0x0D				; load ascii CR char
		movwf	INDF1				; replace 0 with CR for input termination
		; init ssp peripheral to 100KHz i2c master @ 16MHz
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		movlw	.19					; load state number for master transmit
		movwf	i2cState			; set I2C state for write start complete
		movlb	4					; select sfr bank for PIE2
		bcf		PIR2, SSPIF			; init interrupt flag
		bsf		PIE2, SSPIE			; enable SSP interrupts
		movlb	6					; select sfr bank for ssp
		bsf		SSPCON2, SEN		; initiate a start sequence
		; the resulting interrupt kicks off the i2c int based state machine
		clrf	cmdOutBuff			; prevent new cmd line prompt
		return						; I2C start initiated, return from Cmd
		;
		;**********************************************************************
KickI2CRpy	; send reply to device which submitted command via i2c
		;**********************************************************************
		;
		; This function initiates an interrupt driven, buffered, i2c master 
		;  write to an i2c slave. The i2c slave addr is provided by Cmd in 
		;  cmdPrmBuff[0] and an ascii, 0 terminated, string parameter follows.
		; The characters in the string are counted and transmitted until the
		;  byte count is exhausted.
		;
		; Initialize flags and pointers for interrupt based I2C master write.
		;
		; wait for any ongoing buffered I2C activity to complete
		tstfsz	i2cState			; skip when I2C xfer complete
		goto	$-1					; until then wait
		movlb	4					; select sfr bank for PIE2
		bcf		PIE2, SSPIE			; disable SSP interrupts
		; init i2c out pointer
		movlw	cmdOutBuff - 1		; load prestart of output buffer
		movwf	FSR1				;  into FSR1
		movwf	i2cDataPtr			;  and into master buffer ptr
		movlw	0x0D				; load ascii CR char into W
		clrf	i2cByteCnt			; init byte count
		; loop here to count chars until CR
		incf	FSR1				; inc to next char
		incf	i2cByteCnt			; inc byte count
		cpfseq	INDF1				; skip if current char is CR
		goto	$-3					; otherwise test next char
		; init ssp peripheral to 100KHz i2c master @ 16MHz
		movlb	6					; select sfr bank for ssp
		movlw	0x28				; enable ssp periph and select I2C Master
		movwf	SSPCON1				; in SSPCON1
		movlw	.19					; SSPBRG value for 16MHz and 100KHz
		movwf	SSPADD				; init baud rate generator reload value
		movlw	.19					; load state number for master transmit
		movwf	i2cState			; set I2C state for write start complete
		movlb	4					; select sfr bank for PIE2
		bcf		PIR2, SSPIF			; init interrupt flag
		bsf		PIE2, SSPIE			; enable SSP interrupts
		movlb	6					; select sfr bank for ssp
		bsf		SSPCON2, SEN		; initiate a start sequence
		; the resulting interrupt kicks off the i2c int based state machine
		return						; I2C start initiated, return from Cmd
		;
		;**********************************************************************
I2CIsr	; I2C interrupt service routine
		;**********************************************************************
		;
		; The following macro causes this function to be called from the 
		;  peripheral interrupt vector when the SSPIF flag and SSPIE interrupt
		;  enable are set. This macro must be placed immediately following the 
		;  label at the beginning of the isr function and prior to any 
		;  executable code. 
		;
		;  include bit testing at the peripheral int vector at assembly time
	InstallISR	4, PIR2, SSPIF		; install isr for ssp
		;
		; This function must be terminated by a return to the peripheral isr 
		;  which restores context and performs the retfie. 
		;
		; Each time this function is called it clears the interrupt flag, 
		;  initiates an action that will cause another interrupt to occur,
		;  and then returns. A state machine causes the correct action to be 
		;  initiated during processing of each sequential interrupt.
		;
		; clear interrupt flag
		movlb	4					; select sfr bank for PIE2
		bcf		PIR2, SSPIF			; s/w clear of interrupt flag
		movlb	6					; select sfr bank for ssp
		;
		; The sequence of control for the ssp peripheral, i2c protocol, and 
		;  i2c eeprom device is provided by a software state machine. This 
		;  state machine is implimented as a jump table in which a variable,
		;  i2cState, is added to the current PC. This redirects processor
		;  execution into a block of sequential goto instructions. These goto
		;  instructions jump to the code to be executed for this state of the
		;  sequence  This code can initiate an action that will cause another
		;  ssp interrupt. It also controls the value of i2cState vsriable 
		;  which controls which state code will be executed on the next ssp 
		;  interrupt.
		;
		; define mask that limits the range of value of the state variable
	i2cSizeMask	equ	0x3F		; allow 64 states, must be a power of 2
		; Note: Macro fills jump table to this many instructions preventing
		;       branching beyond the end.
		;
		; ***** Executable code for I2C isr *****
		;
		movlw	high (I2CJump)		; fetch upper byte of jump table address
		movwf	PCLATH				; load into upper PC latch
		movlw	i2cSizeMask			; load number of states
		andwf	i2cState, W			; load the masked state variable into W
		addlw	low (I2CJump) + 1	; calc state machine jump addr into W
		btfsc	ALUSTA, C			; skip if carry occured
		incf	PCLATH				; otherwise add carry
I2CJump	; address were jump table branch occurs, this addr also used in fill 
		movwf	PCL					; index into state machine jump table
		; jump to processing for each state		= i2cState value for each state
		goto	I2CIdle				; i2c idle							= 0
		; I2C master eeprom write state sequence w/ ack polling
		goto	EEWrtStart			; write start sequence completed	= 1
		goto	EEWrtCmd			; ee write command completed		= 2
		goto	EEWrtAddr			; ee memory address out completed	= 3
		goto	EEWrtData			; data out completed				= 4
		goto	EEWrtStop			; stop sequence completed			= 5
		goto	EEWrtBufFull		; eeprom write buffer full			= 6
		goto	EEWrtFullStop		; restart new write					= 7
		goto	EEWrtFullStart		; buff full start sequence complete	= 8
		goto	EEWrtRdCmd			; ack test write command completed	= 9
		; I2C master eeprom read state sequence
		goto	EERdStart			; read start sequence completed		= 10
		goto	EERdWrtCmd			; ee write command completed		= 11
		goto	EERdAddr			; ee memory addr out completed		= 12
		goto	EERdRestart			; restart sequence completed		= 13
		goto	EERdCmd				; ee read command completed			= 14
		goto	EERdData			; data read completed				= 15
		goto	EERdAck				; ack sequence completed		 	= 16
		goto	EERdNack			; nack sequence completed			= 17
		goto	EERdStop			; stop sequence completed			= 18
		; I2C master write state sequence
		goto	MstrWrtStart		; write start sequence completed	= 19
		goto	MstrWrtAddr			; i2c address out completed			= 20
		goto	MstrRpyAddr			; reply address out completed		= 21
		goto	MstrByteCnt			; byte count out completed			= 22
		goto	MstrDataTx			; data buffer out completed			= 23
		; I2C master read state sequence
		goto	MstrRdStart			; read start sequence completed		= 24
		goto	MstrRdAddr			; read address completed			= 25
		goto	MstrRdData			; data read completed				= 26
		goto	MstrRdAck			; ack sequence completed		 	= 27
		goto	MstrRdStop			; stop sequence completed			= 28
		; I2C slave write state sequence
		goto	SlavRpyAddr			; reply address received			= 29
		goto	SlavByteCnt			; byte count received				= 30
		goto	SlavDataRx			; data byte received				= 31
		; I2C slave read state sequence
		goto	SlavDataTx			; read data sequence completed		= 32
		; total range of jump table is set by i2cSizeMask
		; fill with return from here to end of maximum I2CJump table
	Fill (return),  I2CJump + i2cSizeMask - $
		;
I2CIdle								; i2c idle 							= 0
		btfsc	SSPCON1, 3			; skip if not in master mode
		goto	$					; otherwise muti-master error trap
		btfsc	SSPSTAT, D_A		; skip if address was received
		goto	$					; otherwise data error trap
		; i2c slave address match has occurred
		movfp	SSPBUF, WREG		; clear address from SSPBUF
		btfsc	SSPSTAT, R_W		; skip if operation is a write
		goto	SlvRd				; otherwise operation is a read
		movlw	i2cRxBuffer - 1		; load prestart of Rx buffer
		movwf	i2cIntRxPtr			;  into pointer for slave receive
		movlw	.29					; load value for SlavRpyAddr
		movwf	i2cState			;  into i2cState
		return						; return to restore context and exit isr
SlvRd	; slave transmission has been requested
		movlw	i2cSlvRdBuff		; load start of slave read string
		movwf	FSR1				;  into FSR1
		movpf	INDF1, SSPBUF		; load first char for transmission
		bsf		SSPCON1, CKP		; release SCL to allow transfer
		movpf	FSR1, i2cSlvPtr		; save pointer
		movlw	.32					; load value for SlavDataTx
		movwf	i2cState			;  into i2cState
		return						; return to restore context and exit isr
		;
		; ***** I2C master write state sequence *****
		;
EEWrtStart							; write start sequence completed	= 1
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; start complete increment I2C state
		movlw	0xA0				; load I2C addr command for ee write
		movwf	SSPBUF				; output I2C addr command for ee write
		return						; return to restore context and exit isr
		;
EEWrtCmd							; ee write command completed		= 2
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; cmd out complete increment I2C state
		movfp	i2cEEAddr, WREG		; fetch ee memory write addr
		movwf	SSPBUF				; output ee memory write addr
		return						; return to restore context and exit isr
		;
EEWrtAddr		; ee memory address output completed					= 3
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		; start write of data pointed to by i2cDataPtr
		movfp	i2cDataPtr, FSR1	; load buffer pointer into FSR1
		movpf	INDF1, SSPBUF		; output ee memory data parameter
		tstfsz	INDF1				; skip if last output value was zero
		goto	$+3					; otherwise point to next data parameter
		; last data output was 0, terminate write
		incf	i2cState			; output 0 terminated, increment I2C state
		return						; return to restore context and exit isr
		; last data output was not 0, test for ee buffer overflow
		incf	i2cDataPtr			; inc pointer to next data value
		incf	i2cEEAddr			; inc current ee write addr
		movlw	0x07				; load mask for 8 byte ee write buffer
		andwf	i2cEEAddr, W		; mask ee write addr into W
		tstfsz	WREG				; is next addr at start of ee write buffer?
		; if not return w/o changeing i2cState, this code again next int
		return						; return to restore context and exit int
		; otherwise stop and resend ee memory addr before ack polling
		movlw	6					; load numeric value for MstWrtBufFull
		movwf	i2cState			; into MstWrtData, making it the next state
		return						; return to restore context and exit isr
		;
EEWrtData							; data out completed				= 4
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; data out complete increment I2C state
		bsf		SSPCON2, PEN		; initiate a stop sequence
		return						; return to restore context and exit isr
		;
EEWrtStop							; stop sequence completed			= 5
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		call	RstI2C				; reset to i2c slave operation
		return						; return to restore context and exit isr
		;
EEWrtBufFull						; eeprom write buffer full			= 6
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; ee write buffer full inc I2C state 
		bsf		SSPCON2, PEN		; initiate a stop sequence
		return						; return to restore context and exit isr
		;
EEWrtFullStop						; buffer full stop sequence complete= 7
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; buffer full stop complete inc I2C state 
		bsf		SSPCON2, RSEN		; initiate a restart sequence
		return						; return to restore context and exit isr
		;
EEWrtFullStart						; buff full start sequence complete	= 8
		btfsc	SSPCON2, RSEN		; skip once RSEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; start complete, increment I2C state
		movlw	0xA0				; load command for ee write to test ack
		movwf	SSPBUF				; output I2C addr command for ee write
		return						; return to restore context and exit isr
		;
EEWrtRdCmd							; ack test write command completed	= 9
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		btfss	SSPCON2, ACKSTAT	; skip if no write ack
		goto	$+4					; otherwise ack received, cont write
		decf	i2cState			; no ack, decrement I2C state
		bsf		SSPCON2, RSEN		; initiate a restart sequence
		return						; return to restore context and exit isr
		; ack received, eeprom ready, write eeprom memory address
		movlw	3					; eeprom ready, load I2C state
		movwf	i2cState			; so next state is memory write complete
		movfp	i2cEEAddr, WREG		; fetch ee memory write addr
		movwf	SSPBUF				; output ee memory write addr
		return						; return to restore context and exit isr
		;
		; ***** I2C master read state sequence *****
		;
EERdStart							; read start sequence completed		= 10
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; start complete increment I2C state
		movlw	0xA0				; load I2C addr command for ee write
		movwf	SSPBUF				; output I2C addr command for ee write
		return						; return to restore context and exit isr
		;
EERdWrtCmd							; ee write command out completed	= 11
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; write cmd complete, increment I2C state
		movlw	cmdPrmBuff			; load addr of cmd parameter buffer start
		movwf	FSR1				; into FSR1
		movpf	INDF1, SSPBUF		; output ee memory address parameter
		return						; return to restore context and exit isr
		;
EERdAddr							; ee memory address out completed	= 12
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; ee addr out complete, increment I2C state
		bsf		SSPCON2, RSEN		; initiate a restart condition
		return						; return to restore context and exit isr
		;
EERdRestart							; restart sequence completed		= 13
		btfsc	SSPCON2, RSEN		; skip once RSEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; restart complete, increment I2C state
		movlw	0xA1				; load I2C addr command for ee read
		movwf	SSPBUF				; output I2C addr command for ee read
		return						; return to restore context and exit isr
		;
EERdCmd								; read command completed			= 14
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; read cmd complete increment I2C state
		movfp	cmdOutPtr, WREG		; load cmd output pointer into W
		incf	WREG				; point to next output buffer location
		movwf	i2cDataPtr			; save it into I2C master pointer
		bsf		SSPCON2, RCEN		; start receiving data byte
		return						; return to restore context and exit isr
		;
EERdData							; data read completed				= 15
		btfsc	SSPCON2, RCEN		; skip once RCEN is cleared
		goto	$-1					; until then wait
		btfss	SSPSTAT, BF			; skip once BF is set
		goto	$-1					; until then wait
		incf	i2cState			; data read complete increment I2C state
		movfp	i2cDataPtr, FSR1	; load buffer pointer into FSR1
		movfp	SSPBUF, INDF1		; copy ee data value into output buffer
		tstfsz	INDF1				; skip if last read value was zero
		goto	EERdNZ				; otherwise jump to test output addr
EERdZ	; last data read was zero, or buffer is full, send nack to end read
		movlw	'\n'				; load LF to replace last char so that
		movwf	INDF1				;  u1: will redraw cmd line prompt
		incf	FSR1				; point to next location
		movlw	'\r'				; load ascii CR into last location in buff
		movwf	INDF1				;  CR terminates cmd line when resubmited
		incf	i2cState			; all data read so inc I2C state again
		bsf		SSPCON2, ACKDT		; set nack to terminate ee read
		bsf		SSPCON2, ACKEN		; start nack sequence
		return						; return to restore context and exit isr
EERdNZ	; last data was not 0, if buffer full jump back to nack
		movlw	cmdOutBuff + cmdOutBuffSize - 2	; load end addr in cmdOutBuff
		cpfslt	i2cDataPtr			; skip if output buffer is not full
		goto	EERdZ				; otherwise buffer is full, send nack
		incf	i2cDataPtr			; inc pointer to next output location
		bcf		SSPCON2, ACKDT		; generate ack to continue ee read
		bsf		SSPCON2, ACKEN		; start ack sequence
		return						; return to restore context and exit isr
		;
EERdAck								; ack sequence completed			= 16
		btfsc	SSPCON2, ACKEN		; skip once ACKEN is cleared
		goto	$-1					; until then wait
		decf	i2cState			; ack complete decrement I2C state
		bsf		SSPCON2, RCEN		; start receiving data byte
		return						; return to restore context and exit isr
		;
EERdNack							; nack sequence completed			= 17
		btfsc	SSPCON2, ACKEN		; skip once ACKEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; nack complete increment I2C state
		bsf		SSPCON2, PEN		; initiate a stop sequence
		return						; return to restore context and exit isr
		;
EERdStop							; stop sequence completed			= 18
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		call	RstI2C				; reset to i2c slave operation
		return						; return to restore context and exit isr
		;
		; ***** I2C master write state sequence *****
		;
MstrWrtStart						; write start sequence completed	= 19
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; start complete increment I2C state
		movfp	i2cAddr, WREG		; load I2C addr
		movwf	SSPBUF				; output I2C addr command for ee write
		return						; return to restore context and exit isr
		;
MstrWrtAddr							; i2c address out completed			= 20
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		movfp	i2cAddr, WREG		; move the acknowledged i2c addr
		movwf	i2cRpyPend			;  into the pending reply gpr
		incf	i2cState			; data out complete, increment I2C state
		movfp	i2cSlvAddr, WREG	; load local slave address for reply
		movwf	SSPBUF				; output I2C addr command for ee write
		return						; return to restore context and exit isr
		;
MstrRpyAddr							; reply address out completed		= 21
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; reply out complete, increment I2C state
		movfp	i2cByteCnt, WREG	; load byte count
		movwf	SSPBUF				; output I2C addr command for ee write
		return						; return to restore context and exit isr
		;
MstrByteCnt							; byte count out completed			= 22
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cDataPtr			; point to new data location
		movfp	i2cDataPtr, FSR1	; load output buffer pointer into FSR1
		movpf	INDF1, SSPBUF		; put data value into buffer
		decfsz	i2cByteCnt			; decrement byte count and skip if 0
		return						; otherwise return to restore and exit isr
		incf	i2cState			; data out complete, increment I2C state
		bsf		SSPCON2, PEN		; initiate a stop sequence
		return						; return to restore context and exit isr
		;
MstrDataTx							; data buffer out completed			= 23
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		call	RstI2C				; reset to i2c slave operation
		return						; return to restore context and exit isr
		;
		; ***** I2C master read state sequence *****
		;
MstrRdStart							; read start sequence completed		= 24
		btfsc	SSPCON2, SEN		; skip once SEN is cleared
		goto	$-1					; until then wait
		incf	i2cState			; start complete, increment I2C state
		movlw	cmdPrmBuff			; load addr of cmd parameter buffer start
		movwf	FSR1				; into FSR
		movpf	INDF1, WREG			; fetch i2c address parameter into W
		rlncf	WREG				; shift i2c addr out of lsb
		bsf		WREG, 0				; set lsb for read
		movwf	SSPBUF				; output addr / command for i2c read
		return						; return to restore context and exit isr
		;
MstrRdAddr							; i2c address out completed			= 25
		btfsc	SSPSTAT, R_W		; skip once R/W is cleared
		goto	$-1					; until then wait
		incf	i2cState			; i2c addr out complete, increment state
		movfp	cmdOutPtr, WREG		; load cmd output pointer into W
		incf	WREG				; point to next location, keeping \n
		movwf	i2cDataPtr			; save it into I2C master pointer
		bsf		SSPCON2, RCEN		; start receiving data byte
		return						; return to restore context and exit isr
		;
MstrRdData							; data read completed				= 26
		btfsc	SSPCON2, RCEN		; skip once RCEN is cleared
		goto	$-1					; until then wait
		btfss	SSPSTAT, BF			; skip once BF is set
		goto	$-1					; until then wait
		incf	i2cState			; data read complete increment I2C state
		movfp	i2cDataPtr, FSR1	; load buffer pointer into FSR1
		movfp	SSPBUF, INDF1		; copy ee data value into output buffer
		tstfsz	INDF1				; skip if last read value was zero
		goto	MstrRdNZ			; otherwise jump to test output addr
MstrRdZ	; last data read was zero, or buffer is full, send nack to end read
		movlw	'\n'				; load LF to replace last char so that
		movwf	INDF1				;  u1: will redraw cmd line prompt
		incf	FSR1				; point to next location
		movlw	'\r'				; load ascii CR into last location in buff
		movwf	INDF1				;  CR terminates cmd line when resubmited
		incf	i2cState			; all data read so inc I2C state again
		bsf		SSPCON2, ACKDT		; set nack to terminate ee read
		bsf		SSPCON2, ACKEN		; start nack sequence
		return						; return to restore context and exit isr
MstrRdNZ	; last data was not 0, if buffer full jump back to nack
		movlw	cmdOutBuff + cmdOutBuffSize - 2	; load end addr in cmdOutBuff
		cpfslt	i2cDataPtr			; skip if output buffer is not full
		goto	MstrRdZ				; otherwise buffer is full, send nack
		incf	i2cDataPtr			; inc pointer to next output location
		bcf		SSPCON2, ACKDT		; generate ack to continue ee read
		bsf		SSPCON2, ACKEN		; start ack sequence
		return						; return to restore context and exit isr
		;
MstrRdAck							; ack sequence completed			= 27
		btfsc	SSPCON2, ACKEN		; skip once ACKEN is cleared
		goto	$-1					; until then wait
		decf	i2cState			; ack complete decrement I2C state
		bsf		SSPCON2, RCEN		; start receiving data byte
		return						; return to restore context and exit isr
		;
MstrRdStop							; stop sequence completed			= 28
		btfsc	SSPCON2, PEN		; skip once PEN is cleared
		goto	$-1					; until then wait
		call	RstI2C				; reset to i2c slave operation
		return						; return to restore context and exit isr
		;
		; ***** I2C slave write state sequence *****
		;
SlavRpyAddr							; reply address received			= 29
		movfp	SSPBUF, WREG		; receive reply addr into W
		movwf	i2cAddr				; store it in gpr
		incf	i2cState			; inc i2c state to receive byte count
		return						; return to restore context and exit isr
		;
SlavByteCnt							; byte count received				= 30
		movfp	SSPBUF, WREG		; receive byte count into W
		movwf	i2cByteCnt			; store it in gpr
		incf	i2cState			; inc i2c state to receive data
		return						; return to restore context and exit isr
		;
SlavDataRx							; data byte received				= 31
		incf	i2cIntRxPtr			; point to new data location
		movfp	i2cIntRxPtr, FSR1	; load slave write buffer pointer into FSR1
		movfp	SSPBUF, INDF1		; receive data value into buffer
		decfsz	i2cByteCnt			; decrement byte count and skip if 0
		return						; otherwise return to restore and exit isr
		bsf		i2cFlags, i2cRxRdy	; set flag indicating buffer is ready
		clrf	i2cState			; reset i2c state to idle
		return						; return to restore context and exit isr
		;
		; ***** I2C slave read state sequence *****
		;
SlavDataTx							; read data sequence completed		= 32
		btfss	SSPSTAT, R_W		; skip when ACK is sent
		goto	SlvNACK				; otherwise nack was received
		incf	i2cSlvPtr			; point to next char in read buffer
		movfp	i2cSlvPtr, FSR1		; load data read pointer into FSR1
		movpf	INDF1, SSPBUF		; load char for transmission
		bsf		SSPCON1, CKP		; release SCL to allow transfer
		return						; otherwise return to restore and exit isr
SlvNACK	; negative acknowledge has been sent, read is complete
		clrf	i2cState			; reset i2c state to idle
		return						; return to restore context and exit isr

;	movlb	1					; select portd bank
;	btg		PORTD, 7			; toggle debug bit
;	movlb	6					; select ssp bank

;	movfp	SSPSTAT, WREG		; fetch SSPSTAT into W
;	movlb	1					; select portd bank
;	movwf	PORTD				; display SSPSTAT on debug LEDs
;	movlb	6					; select ssp bank

; end of file i2ccmd.asm ******************************************************


Interested: