TITLE "WORKIDREAD"
LIST C=120, b=4
LIST P=12C509
ERRORLEVEL -305 ; Suppress "Using default
INDF EQU 0x00
TMR0 EQU 0x01
Pc EQU 0x02
STATUS EQU 0x03
FSR EQU 0x04
OSCCAL EQU 0x05
GPIO EQU 0x06 ; lower 5 bits only
GP0 EQU 0x00
GP1 EQU 0x01
GP2 EQU 0x02 ; Shared with T0CKI
GP3 EQU 0x03 ; Always input, shared with MCLR, Vpp
GP4 EQU 0x04 ; Shared with OSC2
GP5 EQU 0x05 ; Shared with OSC1, clkin
C EQU 0x00 ; Carry flag
DC EQU 0x01 ; Digit carry flag
Z EQU 0x02 ; Zero flag
PD EQU 0x03 ; Power down flag
TO EQU 0x04 ; WDT timeout flag
PA0 EQU 0x05 ; Program page select
GPWUF EQU 0x07 ; GPIO reset bit
RP0 EQU 0x05 ; Register page select
LSB EQU 0x00
MSB EQU 0x07
#DEFINE IFSET BTFSC
#DEFINE IFCLR BTFSS
#DEFINE IFZ SKPNZ
#DEFINE IFNZ SKPZ
#DEFINE IFC SKPNC
#DEFINE IFNC SKPC
#DEFINE SKPSET BTFSS
#DEFINE SKPCLR BTFSC
start_code EQU ; Start Sentinel bit pattern,
end_code EQU ; End Sentinel bit pattern,
buf_ptr EQU 0x07 ; card data buffer pointer (nibbles)
num_chr EQU 0x08 ; Number of characters read from card
count EQU 0x09 ; General 8 bit counter
flag EQU 0x0A ; Control flags
char_buf EQU 0x0B ; Character buffer, input and serial output
parityLRC EQU 0x0C ; Parity/LRC workspace
temp EQU 0x0D ; Temporary workspace
lo_mem EQU 0x10 ; Memory buffer start address:
hi_mem EQU 0x33 ; Memory buffer end
if lo_mem > 0x1F
ERROR "Buffer start address (lo_mem) must be in Bank 0"
endif
if hi_mem > 0x1F && hi_mem < 0x30
ERROR "Buffer end address (hi_mem) must be in upper half of Bank 1"
endif
if hi_mem <= 0x1F
buf_sz EQU ((hi_mem - lo_mem) + 1) * 2
else
buf_sz EQU ((hi_mem - lo_mem) - .15) * 2
endif
found_start EQU 0
found_end EQU 1
bad_parity EQU 2
bad_LRC EQU 3
buf_end EQU 4
read_buf EQU 5
ser_out EQU GP0 ; serial TxD pin to host
card EQU GP1 ; ^CLD signal (low when card present)
clock EQU GP2 ; ^RCL signal (low when data valid)
signal EQU GP3 ; ^RDT signal from magstripe
invert_tx EQU 0 ; 0 = Idle (logical ’1’) is 0V
ORG 0x00
MOVWF OSCCAL
GOTO start
send_char
MOVWF char_buf ; Store the character code (in W)
MOVLW .10 ; Set the number of bits (including
MOVWF count ; start and stop bits) in count
CLRC ; Clear carry because the start bit
bit_loop
IFNC ; serial pin logic ’0’
if invert_tx
BCF GPIO,ser_out
else
BSF GPIO,ser_out
endif
IFC ; serial pin logic ’1’
if invert_tx
BSF GPIO,ser_out
else
BCF GPIO,ser_out
endif
CALL bit_delay ; Make up the bit time to 833us
RRF char_buf ; Roll LSB of char_buf into carry,
DECFSZ count ; Loop until all bits have been
GOTO bit_loop ; shifted out.
RETLW 0
bit_delay
MOVLW .52 ; Initialise temp
MOVWF temp
MOVLW .1 ; Put 1 in W for incrementing temp
GOTO $+1 ; Waste 2 cycles
NOP ; Waste 1 cycle
delay_loop
ADDWF temp ; Increment temp 1
IFNC ; Did it overflow? 1
GOTO delay_loop ; No: go round again 2
RETLW 0 ; Yes: return
get_put_char
RRF buf_ptr,W ; load W with buf_ptr/2. Carry
MOVWF FSR ; and use the FSR to point to it
MOVLW lo_mem ; add the buffer start address
ADDWF FSR ; to get the physical address to
IFSET FSR,RP0 ; Check for overflow into the
BSF FSR ,4 ; second register page and set
IFSET flag,read_buf ; check whether this is a read
GOTO get_char ; or write operation
put_char
MOVF char_buf,W ; Move the character (in high
IFCLR buf_ptr,LSB ; except if LSB of buf_ptr is ’0’
SWAPF char_buf,W ; then the destination is an even
IORWF INDF ; since the buffer was cleared
MOVLW buf_sz + 1 ; set limit for ’put’ operation
GOTO get_put_done
get_char
MOVF INDF,W ; Fetch data from buffer to W
IFSET buf_ptr,LSB ; if LSB of buf_ptr is set the
SWAPF INDF,W ; desired character is an odd
ANDLW 0x0F ; mask off upper nibble
MOVWF char_buf ; move it to the character buffer
MOVF num_chr,W ; set limit for ’get’ operation
get_put_done
INCF buf_ptr ; increment memory pointer.
XORWF buf_ptr,W ; check if this was the last
IFZ ; if it was,
BSF flag,buf_end ; then set a flag
RETLW 0
start
CLRF STATUS
MOVLW B’11000000’ ; Disable GPIO pull-ups and wake
OPTION
MOVLW B’00001110’ ; Set GPIO <1:3> as inputs...
TRIS GPIO ; Note: GP3 is always input
CLRF GPIO ; GPIO outputs all 0
if invert_tx
BSF GPIO,ser_out ; except for invert_tx condition
endif
MOVLW 0x07 ; Load start address (0x07) into
MOVWF FSR ; the FSR
clrloop
CLRF INDF ; Clear the RAM location FSR is
INCF FSR ; Increment FSR to next location
MOVF FSR,W ; Check if FSR is pointing past
XORLW 0x10 | 0xC0 ; its end point. Remember MSBs
IFNZ ; If counter was not 0x10
GOTO clrloop ; then loop again
main_loop
MOVLW lo_mem ; Fetch buffer start address
MOVWF FSR
clr_buf _loop
CLRF INDF
INCF FSR
IFSET FSR,RP0 ; If FSR points to register page 1
BSF FSR,4 ; set bit 4 to move into 0x3n
MOVF FSR,W ; Check for buffer end address.
XORLW (hi_mem + 1) | 0xC0
IFNZ ; If not end then loop around
GOTO clr_buf_loop
CLRF buf_ptr ; Initialise buffer pointer to 0
MOVLW buf_sz ; Initialise the number of
MOVWF num_chr ; characters read to the maximum
MOVLW start_code ; Initialise the LRC to the start
MOVWF parityLRC ; sentinel code.
CLRF flag ; Initialise control flags to
BSF flag ,bad_LRC ; zero then set the bad_LRC
MOVLW ’R’ ; Send "Ready" from serial port
CALL send_char
MOVLW ’e’
CALL send_char
MOVLW ’a’
CALL send_char
MOVLW ’d’
CALL send_char
MOVLW ’y’
CALL send_char
MOVLW .13 ; Send CR LF from serial port
CALL send_char
MOVLW .10
CALL send_char
CLRF char_buf ; Clear character input buffer
wait_card
IFSET GPIO,card ; Check ^CARD line
GOTO wait_card ; if it’s high then keep waiting
wt_clk_lo
IFSET GPIO,clock ; Check ^CLK line
GOTO wt_clk_lo ; If it’s high then keep waiting
chk_data
IFSET GPIO,signal ; Check ^DATA
GOTO data_0 ; If it’s high, data bit is ’0’
data_1
BSF STATUS,C ; Otherwise it’s low so data bit
MOVLW 0x80 ; and toggle parity bit in
XORWF parityLRC ; parityLRC register
BTFSS STATUS,C ; Use that fact that carry is
data_0
BCF STATUS,C ; bit is ’0’, so clear carry
store_bit
RRF char_buf ; shift data bit in carry flag
IFC ; So, check the carry flag
GOTO got_char
IFSET flag,found_start; Has the start code been seen?
GOTO wt_clk_hi ; Yes, so wait for ^CLK to go
MOVLW B’11111000’ ; The start code is five bits
ANDWF char_buf ; bits in the buffer (which are
MOVLW start_code ; and compare start_code
XORWF char_buf,W ; to the buffer
IFNZ ; Is it the start code?
GOTO wt_clk_hi ; No, so wait for ^CLK to go high
BSF flag,found_start; Yes, so set a flag
next_char
BCF parityLRC,MSB ; clear the parity flag,
CLRF char_buf ; clear the input buffer,
BSF char_buf,4 ; and set a sentinel bit
wt_clk_hi
IFCLR GPIO,clock ; Check ^CLK line
GOTO wt_clk_hi ; Keep waiting whilst it’s low
GOTO wt_clk_lo ; Then go and wait for it to be
got_char
IFCLR parityLRC,MSB ; If parity bit is ’0’
BSF flag,bad_parity ; set the parity error flag
MOVF char_buf,W ; Copy char_buf to W
XORWF parityLRC ; XOR with the parityLRC register
IFCLR flag,found_end ; yet been seen then this is
GOTO not_LRC ; not the LRC, so store it
MOVF parityLRC,W ; Otherwise it was the LRC, so
ANDLW b’01111000’ ; get the LRC check from the
IFZ ; If it is zero then the LRC was
BCF flag,bad_LRC ; okay so clear the bad_LRC flag
MOVF buf_ptr,W ; Copy the value of buffer pointer
MOVWF num_chr ; to num_chr
GOTO dump_buffer ; and dump it out
not_LRC
MOVLW end_code ; Is this the end sentinel?
XORWF char_buf,W
IFZ ; If so, the next character is
BSF flag,found_end ; the LRC, so set a flag
IFZ
GOTO next_char ; and don’t bother storing it
RLF char_buf ; discard parity by shifting it
MOVLW 0xF0 ; mask off the lower nibble
ANDWF char_buf
CALL get_put_char ; and store the character
IFCLR flag,buf_end ; Is the buffer full?
GOTO next_char ; no, so get the next character
dump_buffer
CLRF buf_ptr ; Load buffer pointer with 0
BSF flag,read_buf ; Set the flag to read mode
BCF flag,buf_end ; Clear the buf_end flag
loop_buffer
CALL get_put_char ; Get character from buffer
MOVLW .48 ; convert to ASCII by adding 48
ADDWF char_buf, W ; and put the result in W
CALL send_char ; and send the character
IFCLR flag,buf_end ; have we emptied the buffer?
GOTO loop_buffer ; No, so loop around
"
MOVLW ’.’ ; Load ASCII "." into W
IFSET flag,bad_parity ; If parity was ever bad
MOVLW ’P’ ; load ASCII "P" into W instead
CALL send_char ; then send the character
MOVLW ’.’ ; Load ASCII "." into W again
IFSET flag,bad_LRC ; If LRC was bad
MOVLW ’L’ ; load ASCII ’L’ into W instead
CALL send_char ; and send the character
MOVLW .13 ; Send CR LF from serial port
CALL send_char
MOVLW .10
CALL send_char
GOTO main_loop ; Back to the beginning and wait
END
LIST C=120, b=4
LIST P=12C509
ERRORLEVEL -305 ; Suppress "Using default
INDF EQU 0x00
TMR0 EQU 0x01
Pc EQU 0x02
STATUS EQU 0x03
FSR EQU 0x04
OSCCAL EQU 0x05
GPIO EQU 0x06 ; lower 5 bits only
GP0 EQU 0x00
GP1 EQU 0x01
GP2 EQU 0x02 ; Shared with T0CKI
GP3 EQU 0x03 ; Always input, shared with MCLR, Vpp
GP4 EQU 0x04 ; Shared with OSC2
GP5 EQU 0x05 ; Shared with OSC1, clkin
C EQU 0x00 ; Carry flag
DC EQU 0x01 ; Digit carry flag
Z EQU 0x02 ; Zero flag
PD EQU 0x03 ; Power down flag
TO EQU 0x04 ; WDT timeout flag
PA0 EQU 0x05 ; Program page select
GPWUF EQU 0x07 ; GPIO reset bit
RP0 EQU 0x05 ; Register page select
LSB EQU 0x00
MSB EQU 0x07
#DEFINE IFSET BTFSC
#DEFINE IFCLR BTFSS
#DEFINE IFZ SKPNZ
#DEFINE IFNZ SKPZ
#DEFINE IFC SKPNC
#DEFINE IFNC SKPC
#DEFINE SKPSET BTFSS
#DEFINE SKPCLR BTFSC
start_code EQU ; Start Sentinel bit pattern,
end_code EQU ; End Sentinel bit pattern,
buf_ptr EQU 0x07 ; card data buffer pointer (nibbles)
num_chr EQU 0x08 ; Number of characters read from card
count EQU 0x09 ; General 8 bit counter
flag EQU 0x0A ; Control flags
char_buf EQU 0x0B ; Character buffer, input and serial output
parityLRC EQU 0x0C ; Parity/LRC workspace
temp EQU 0x0D ; Temporary workspace
lo_mem EQU 0x10 ; Memory buffer start address:
hi_mem EQU 0x33 ; Memory buffer end
if lo_mem > 0x1F
ERROR "Buffer start address (lo_mem) must be in Bank 0"
endif
if hi_mem > 0x1F && hi_mem < 0x30
ERROR "Buffer end address (hi_mem) must be in upper half of Bank 1"
endif
if hi_mem <= 0x1F
buf_sz EQU ((hi_mem - lo_mem) + 1) * 2
else
buf_sz EQU ((hi_mem - lo_mem) - .15) * 2
endif
found_start EQU 0
found_end EQU 1
bad_parity EQU 2
bad_LRC EQU 3
buf_end EQU 4
read_buf EQU 5
ser_out EQU GP0 ; serial TxD pin to host
card EQU GP1 ; ^CLD signal (low when card present)
clock EQU GP2 ; ^RCL signal (low when data valid)
signal EQU GP3 ; ^RDT signal from magstripe
invert_tx EQU 0 ; 0 = Idle (logical ’1’) is 0V
ORG 0x00
MOVWF OSCCAL
GOTO start
send_char
MOVWF char_buf ; Store the character code (in W)
MOVLW .10 ; Set the number of bits (including
MOVWF count ; start and stop bits) in count
CLRC ; Clear carry because the start bit
bit_loop
IFNC ; serial pin logic ’0’
if invert_tx
BCF GPIO,ser_out
else
BSF GPIO,ser_out
endif
IFC ; serial pin logic ’1’
if invert_tx
BSF GPIO,ser_out
else
BCF GPIO,ser_out
endif
CALL bit_delay ; Make up the bit time to 833us
RRF char_buf ; Roll LSB of char_buf into carry,
DECFSZ count ; Loop until all bits have been
GOTO bit_loop ; shifted out.
RETLW 0
bit_delay
MOVLW .52 ; Initialise temp
MOVWF temp
MOVLW .1 ; Put 1 in W for incrementing temp
GOTO $+1 ; Waste 2 cycles
NOP ; Waste 1 cycle
delay_loop
ADDWF temp ; Increment temp 1
IFNC ; Did it overflow? 1
GOTO delay_loop ; No: go round again 2
RETLW 0 ; Yes: return
get_put_char
RRF buf_ptr,W ; load W with buf_ptr/2. Carry
MOVWF FSR ; and use the FSR to point to it
MOVLW lo_mem ; add the buffer start address
ADDWF FSR ; to get the physical address to
IFSET FSR,RP0 ; Check for overflow into the
BSF FSR ,4 ; second register page and set
IFSET flag,read_buf ; check whether this is a read
GOTO get_char ; or write operation
put_char
MOVF char_buf,W ; Move the character (in high
IFCLR buf_ptr,LSB ; except if LSB of buf_ptr is ’0’
SWAPF char_buf,W ; then the destination is an even
IORWF INDF ; since the buffer was cleared
MOVLW buf_sz + 1 ; set limit for ’put’ operation
GOTO get_put_done
get_char
MOVF INDF,W ; Fetch data from buffer to W
IFSET buf_ptr,LSB ; if LSB of buf_ptr is set the
SWAPF INDF,W ; desired character is an odd
ANDLW 0x0F ; mask off upper nibble
MOVWF char_buf ; move it to the character buffer
MOVF num_chr,W ; set limit for ’get’ operation
get_put_done
INCF buf_ptr ; increment memory pointer.
XORWF buf_ptr,W ; check if this was the last
IFZ ; if it was,
BSF flag,buf_end ; then set a flag
RETLW 0
start
CLRF STATUS
MOVLW B’11000000’ ; Disable GPIO pull-ups and wake
OPTION
MOVLW B’00001110’ ; Set GPIO <1:3> as inputs...
TRIS GPIO ; Note: GP3 is always input
CLRF GPIO ; GPIO outputs all 0
if invert_tx
BSF GPIO,ser_out ; except for invert_tx condition
endif
MOVLW 0x07 ; Load start address (0x07) into
MOVWF FSR ; the FSR
clrloop
CLRF INDF ; Clear the RAM location FSR is
INCF FSR ; Increment FSR to next location
MOVF FSR,W ; Check if FSR is pointing past
XORLW 0x10 | 0xC0 ; its end point. Remember MSBs
IFNZ ; If counter was not 0x10
GOTO clrloop ; then loop again
main_loop
MOVLW lo_mem ; Fetch buffer start address
MOVWF FSR
clr_buf _loop
CLRF INDF
INCF FSR
IFSET FSR,RP0 ; If FSR points to register page 1
BSF FSR,4 ; set bit 4 to move into 0x3n
MOVF FSR,W ; Check for buffer end address.
XORLW (hi_mem + 1) | 0xC0
IFNZ ; If not end then loop around
GOTO clr_buf_loop
CLRF buf_ptr ; Initialise buffer pointer to 0
MOVLW buf_sz ; Initialise the number of
MOVWF num_chr ; characters read to the maximum
MOVLW start_code ; Initialise the LRC to the start
MOVWF parityLRC ; sentinel code.
CLRF flag ; Initialise control flags to
BSF flag ,bad_LRC ; zero then set the bad_LRC
MOVLW ’R’ ; Send "Ready" from serial port
CALL send_char
MOVLW ’e’
CALL send_char
MOVLW ’a’
CALL send_char
MOVLW ’d’
CALL send_char
MOVLW ’y’
CALL send_char
MOVLW .13 ; Send CR LF from serial port
CALL send_char
MOVLW .10
CALL send_char
CLRF char_buf ; Clear character input buffer
wait_card
IFSET GPIO,card ; Check ^CARD line
GOTO wait_card ; if it’s high then keep waiting
wt_clk_lo
IFSET GPIO,clock ; Check ^CLK line
GOTO wt_clk_lo ; If it’s high then keep waiting
chk_data
IFSET GPIO,signal ; Check ^DATA
GOTO data_0 ; If it’s high, data bit is ’0’
data_1
BSF STATUS,C ; Otherwise it’s low so data bit
MOVLW 0x80 ; and toggle parity bit in
XORWF parityLRC ; parityLRC register
BTFSS STATUS,C ; Use that fact that carry is
data_0
BCF STATUS,C ; bit is ’0’, so clear carry
store_bit
RRF char_buf ; shift data bit in carry flag
IFC ; So, check the carry flag
GOTO got_char
IFSET flag,found_start; Has the start code been seen?
GOTO wt_clk_hi ; Yes, so wait for ^CLK to go
MOVLW B’11111000’ ; The start code is five bits
ANDWF char_buf ; bits in the buffer (which are
MOVLW start_code ; and compare start_code
XORWF char_buf,W ; to the buffer
IFNZ ; Is it the start code?
GOTO wt_clk_hi ; No, so wait for ^CLK to go high
BSF flag,found_start; Yes, so set a flag
next_char
BCF parityLRC,MSB ; clear the parity flag,
CLRF char_buf ; clear the input buffer,
BSF char_buf,4 ; and set a sentinel bit
wt_clk_hi
IFCLR GPIO,clock ; Check ^CLK line
GOTO wt_clk_hi ; Keep waiting whilst it’s low
GOTO wt_clk_lo ; Then go and wait for it to be
got_char
IFCLR parityLRC,MSB ; If parity bit is ’0’
BSF flag,bad_parity ; set the parity error flag
MOVF char_buf,W ; Copy char_buf to W
XORWF parityLRC ; XOR with the parityLRC register
IFCLR flag,found_end ; yet been seen then this is
GOTO not_LRC ; not the LRC, so store it
MOVF parityLRC,W ; Otherwise it was the LRC, so
ANDLW b’01111000’ ; get the LRC check from the
IFZ ; If it is zero then the LRC was
BCF flag,bad_LRC ; okay so clear the bad_LRC flag
MOVF buf_ptr,W ; Copy the value of buffer pointer
MOVWF num_chr ; to num_chr
GOTO dump_buffer ; and dump it out
not_LRC
MOVLW end_code ; Is this the end sentinel?
XORWF char_buf,W
IFZ ; If so, the next character is
BSF flag,found_end ; the LRC, so set a flag
IFZ
GOTO next_char ; and don’t bother storing it
RLF char_buf ; discard parity by shifting it
MOVLW 0xF0 ; mask off the lower nibble
ANDWF char_buf
CALL get_put_char ; and store the character
IFCLR flag,buf_end ; Is the buffer full?
GOTO next_char ; no, so get the next character
dump_buffer
CLRF buf_ptr ; Load buffer pointer with 0
BSF flag,read_buf ; Set the flag to read mode
BCF flag,buf_end ; Clear the buf_end flag
loop_buffer
CALL get_put_char ; Get character from buffer
MOVLW .48 ; convert to ASCII by adding 48
ADDWF char_buf, W ; and put the result in W
CALL send_char ; and send the character
IFCLR flag,buf_end ; have we emptied the buffer?
GOTO loop_buffer ; No, so loop around
"
MOVLW ’.’ ; Load ASCII "." into W
IFSET flag,bad_parity ; If parity was ever bad
MOVLW ’P’ ; load ASCII "P" into W instead
CALL send_char ; then send the character
MOVLW ’.’ ; Load ASCII "." into W again
IFSET flag,bad_LRC ; If LRC was bad
MOVLW ’L’ ; load ASCII ’L’ into W instead
CALL send_char ; and send the character
MOVLW .13 ; Send CR LF from serial port
CALL send_char
MOVLW .10
CALL send_char
GOTO main_loop ; Back to the beginning and wait
END