;**************************************************************************** ; ; file: utilities.asm ; Description: This file contains miscellaneous protocol procedures ; process_rx_int ; verify_packet ; transmit_sys ; transmit_app ; set_sys_parity ; set_app_parity ; set_sys_checksum ; set_app_checksum ; clear_rx_packet ; delay200us ; ; ; Target: Cypress CY7C63723 Encore Chip ; $Header: ; Version: 1.3.0000 ; ;**************************************************************************** ; Copyright (2003), Cypress Semiconductor Corporation ; This software is owned by Cypress Semiconductor Corporation (Cypress) and is ; protected by United States copyright laws and international treaty provisions. ; Cypress hereby grants to Licensee a personal, non-exclusive, non-transferable ; license to copy, use, modify, create derivative works of, and compile the ; Cypress Source Code and derivative works for the sole purpose of creating ; custom software in support of Licensee product ("Licensee Product") to be used ; only in conjunction with a Cypress integrated circuit. Any reproduction, ; modification, translation, compilation, or representation of this software ; except as specified above is prohibited without the express written permission ; of Cypress. ; Disclaimer: Cypress makes no warranty of any kind, express or implied, with ; regard to this material, including, but not limited to, the implied warranties ; of merchantability and fitness for a particular purpose. Cypress reserves the ; right to make changes without further notice to the materials described herein. ; Cypress does not assume any liability arising out of the application or use of ; any product or circuit described herein. Cypress’ products described herein are ; not authorized for use as components in life-support devices. ; This software is protected by and subject to worldwide patent coverage, ; including U.S. and foreign patents. Use may be limited by and subject to the ; Cypress Software License Agreement. ; ;**************************************************************************** ;------------------------------------------------------- ; ; process_rx_int ; ; Sets the EOF flags if end of frame interrupt is on ; AND reads data ;------------------------------------------------------- process_rx_int: MOV A, REG_RX_INT_STAT MOV [reg_addr], A CALL SPI_read MOV A, [reg_data] MOV [radio_int], A AND A, bRX_FULL_A ; check for data JZ check_eof CALL data_read check_eof: MOV A, [radio_int] AND A, bRX_EOF_A JZ process_rx_int_complete ; check for EOF MOV A, [rx_counter] AND A, ffh JZ process_rx_int_complete ; don't set EOF flag for 0 byte packets MOV A, bFLAG_EOF MOV [packet_ready], A process_rx_int_complete: RET ;------------------------------------------------------- ; data_read ;------------------------------------------------------- data_read: MOV X, [rx_counter] MOV A, [radio_int] AND A, bRX_VALID_A JZ data_read_invalid MOV A, ffh MOV [X+valid_buffer], A JMP data_read_valid data_read_invalid: MOV A, REG_RX_VALID_A ; read the rx data valid byte MOV [reg_addr], A ; CALL SPI_read ; MOV A, [reg_data] ; IF only the bottom 2-3 bits are CMP A, 08h ; valid, this is probably noise JC reset_byte_counter ; so throw it away MOV [X+valid_buffer], A ; store the valid byte (used in error correction) data_read_valid: MOV A, REG_RX_DATA_A ; read the rx data byte MOV [reg_addr], A ; CALL SPI_read ; MOV A, [reg_data] ; store the data MOV [X+rx_buffer], A ; INC [rx_counter] ; inc the counter for next time MOV A, [rx_counter] ; RWW 2004.9.10 CMP A, RX_BUFFER_LEN+1 JNC reset_byte_counter ; buffer overflow check data_read_complete: MOV A, 00h ; reset the radio timer MOV [timer], A ; to prevent reset in mid-packet from RSSI, etc. RET reset_byte_counter: MOV A, REG_RX_DATA_A ; do a dummy data read to clear the MOV [reg_addr], A ; interrupt flag in the radio. CALL SPI_read ; MOV A, 00h ; reset the rx byte counter MOV [rx_counter], A ; AND return to polling loop RET ;------------------------------------------------------- ; ; verify_packet ; ; parity correction AND verification, ; error correction AND checksum verification, etc. ; ;------------------------------------------------------- verify_packet: MOV A, [rx_counter] CMP A, 1 ; if empty packet just throw it away... it's just noise JC verify_packet_complete verify_packet_header: MOV A, [valid_buffer] CMP A, ffh JNZ verify_packet_header_failed ; throw away packets with invalid packet headers ; check the parity MOV A, 0 MOV [parity], A ; "1" bits counter MOV A, 80h MOV [loop_counter], A ; loop counter verify_parity_loop: MOV A, [rx_buffer] AND A, [loop_counter] JZ verify_parity_low_bit INC [parity] ; keep track of all "1" bits verify_parity_low_bit: MOV A, [loop_counter] ASR AND A, 7fh ; need to clear the top bit, because it doesn't shift in a zero JZ verify_parity_loop_complete MOV [loop_counter], A JMP verify_parity_loop verify_parity_loop_complete: MOV A, [parity] AND A, 01h JZ verify_packet_failed ; if parity is even throw the packet away MOV A, [rx_counter] CMP A, 1 ; If this is a multi-byte packet we need to check the checksum JNZ check_valid_bytes ; Otherwise this is a valid 1-byte packet verify_1_byte_packet_success: MOV A, [packet_ready] ; set the valid packet flag! OR A, bFLAG_VALID MOV [packet_ready], A MOV A, [rx_buffer] ; store the packet type AND A, f0h MOV [packet_type], A RET check_valid_bytes: MOV X, [rx_counter] DEC X MOV A, ffh check_valid_loop: AND A, [X+valid_buffer] DEC X JNC check_valid_loop CMP A, ffh ; if all bits in all bytes are valid blunder check the checksum JZ check_csum MOV [invalid_bit], A ; we have an invalid bit... need to correct the packet MOV A, NUM_BITS_CORRECTABLE MOV [corrected_bits], A ; if the checksum has invalid bits it could be a bit-shift error so toss the packet MOV X, [rx_counter] MOV A, [X + valid_buffer - 1] CMP A, ffh JNZ fix_valid_failed ; invalid bits are not in the checksum so we can try to correct them MOV A, 01h MOV [loop_counter], A ; tracks the bit column we are examining fix_valid_loop: MOV A, [invalid_bit] AND A, [loop_counter] ; check to see if we need to correct this column JNZ fix_valid_next_col DEC [corrected_bits] ; If we have already fixed our maximum number of bits JC fix_valid_failed ; throw the packet away MOV A, [checksum_seed] ; this column needs fixed MOV [parity], A MOV A, ffh; MOV [ls_temp], A ; set to invalid to start with to track if multiple bits are bad MOV X, [rx_counter] DEC X fix_col_loop: MOV A, [X+valid_buffer] AND A, [loop_counter] JZ fix_col_loop_bad_byte MOV A, [X+rx_buffer] ; I only care about one column, but it's faster to XOR the entire byte XOR A, [parity] MOV [parity], A JMP fix_col_loop_next_byte fix_col_loop_bad_byte: MOV A, [ls_temp] CMP A, ffh JNZ fix_valid_failed MOV A, X MOV [ls_temp], A ; track the bad bit fix_col_loop_next_byte: DEC X JNC fix_col_loop MOV A, [parity] ; we finished calculating the AND A, [loop_counter] ; parity for this column.. fix the bad bit JZ fix_col_set_bit_low MOV X, [ls_temp] MOV A, [X+rx_buffer] OR A, [loop_counter] MOV [X+rx_buffer], A JMP fix_valid_next_col fix_col_set_bit_low: MOV X, [ls_temp] MOV A, [loop_counter] CPL AND A, [X+rx_buffer] MOV [X+rx_buffer], A fix_valid_next_col: MOV A, [loop_counter] ASL MOV [loop_counter], A JNZ fix_valid_loop JMP check_csum ; we finished fixing the packet fix_valid_failed: IFDEF BIND_AUTO INC [corrupt_counter] ENDIF RET check_csum: MOV A, [rx_counter] SUB A, 2 ; don't check the checksum, AND it's 0-indexed MOV X, A IFDEF BIND_AUTO MOV A, [rx_buffer] AND A, f0h CMP A, PT_BIND_REQ JNZ seed_checksum MOV A, BIND_CHECKSUM_SEED JMP csum_loop ENDIF ; BIND_AUTO seed_checksum: MOV A, [checksum_seed] csum_loop: XOR A, [X + rx_buffer] DEC X JNC csum_loop SWAP A, X MOV A, [rx_counter] SWAP A, X CMP A, [X + rx_buffer - 1] ; compare with csum byte JNZ verify_packet_failed ; if error discard packet verify_packet_success: MOV A, [packet_ready] ; set the valid packet flag! OR A, bFLAG_VALID MOV [packet_ready], A MOV A, [rx_buffer] ; store the packet type (I'll need this A LOT) AND A, f0h MOV [packet_type], A verify_packet_complete: RET ; returns to process_packet_a verify_packet_failed: IFDEF BIND_AUTO INC [corrupt_counter] ENDIF RET packet_header_failed: MOV A, [rx_counter] CMP A, 1 JNZ verify_packet_failed ; ignore 1-byte noise packets RET ;------------------------------------------------------- ; ; transmit_sys ; ;------------------------------------------------------- transmit_sys: MOV A, 0h MOV [misc_counter1],A MOV X, 00h IFDEF TX_PAUSE bit_shift_loop: IOWR watchdog IORD port0 AND A, IRQ JNZ bit_shift_stall MOV A, REG_TX_INT_STAT MOV [reg_addr], A CALL SPI_read JMP bit_shift_loop bit_shift_stall: CALL delay200us CALL delay200us ENDIF ; TX_PAUSE MOV A, REG_TX_DATA MOV [reg_addr], A tx_sys_stall: IOWR watchdog INC [misc_counter1] ; If we incremented past 255, bail-out JC tx_sys_finished IORD port0 AND A, IRQ JZ tx_sys_stall tx_sys_load: MOV A, [X + tx_sys_buffer] MOV [reg_data], A CALL SPI_write MOV A, 0h MOV [misc_counter1],A INC X MOV A, X SUB A, [tx_sys_counter] JC tx_sys_stall ; wait for a buffer empty interrupt MOV A, REG_TX_INT_EN MOV [reg_addr], A MOV A, bTX_EOF MOV [reg_data], A CALL SPI_write MOV A, 0h MOV [misc_counter1],A tx_sys_wait_finish: IOWR watchdog INC [misc_counter1] ; If we incremented past 255, bail-out JC tx_sys_finished IORD port0 AND A, IRQ JZ tx_sys_wait_finish MOV A, REG_TX_INT_STAT ; If there is an interrupt we need to read MOV [reg_addr], A ; the interrupt status register CALL SPI_read ; in order to clear the interrupt tx_sys_finished: MOV A, REG_TX_INT_EN MOV [reg_addr], A MOV A, bTX_EMPTY MOV [reg_data], A CALL SPI_write CALL radio_idle MOV A, 0 MOV [timer], A ; reset the 1 ms timer RET IFDEF TWO_WAY_DATA ;------------------------------------------------------- ; ; transmit_app ; ;------------------------------------------------------- transmit_app: MOV X, 0h copy_loop: ; for (X=0; X < tx_app_counter; X++) { MOV A, [X + tx_app_header] MOV [X + tx_sys_buffer], A ; tx_sys_buffer[X] = tx_app_header[X]; INC X MOV A, X SUB A, [tx_app_counter] JNZ copy_loop ; } // end for loop MOV A,[tx_app_counter] ; Move tx_app_counter into tx_sys_counter MOV [tx_sys_counter], A CALL transmit_sys ; Use transmit_sys code to do the transfer RET ENDIF ; TWO_WAY_DATA ;------------------------------------------------------- ; ; set_sys_parity ; ;------------------------------------------------------- set_sys_parity: MOV A, 0 MOV [ls_temp], A ; clear the temp register MOV X, [tx_sys_buffer] MOV A, X sys_parity_loop: AND A, 1 JZ sys_parity_end sys_inc_parity: INC [ls_temp] sys_parity_end: MOV A, X ASR AND A, 7Fh ; ASR may not shift in a zero in the top bit MOV X, A AND A, ffh ; once X == 0, either we've shifted the whole byte JNZ sys_parity_loop ; OR the rest is 0's so it doesn't matter MOV A, [ls_temp] AND A, 01h ; IF the lsb is set THEN it's already odd parity, JNZ sys_parity_complete MOV A, [tx_sys_buffer] ; ELSE set the parity bit OR A, bPARITY MOV [tx_sys_buffer], A sys_parity_complete: RET IFDEF TWO_WAY_DATA ;------------------------------------------------------- ; ; set_app_parity ; ;------------------------------------------------------- set_app_parity: MOV A,[tx_app_header] MOV [tx_sys_buffer], A CALL set_sys_parity MOV A,[tx_sys_buffer] MOV [tx_app_header], A RET ENDIF ;------------------------------------------------------- ; ; set_sys_checksum ; ;------------------------------------------------------- set_sys_checksum: IFDEF BIND_AUTO MOV [ls_temp], A ENDIF ; BIND_AUTO sys_init_checksum: MOV A, [tx_sys_counter] SUB A, 2 ; don't check the checksum, 0 indexed MOV X, A IFDEF BIND_AUTO MOV A, [ls_temp] ELSE MOV A, [checksum_seed] ENDIF ; BIND_AUTO sys_checksum_loop: XOR A, [X + tx_sys_buffer] ; XOR each byte AND A, ffh ; clear carry flag DEC X JNC sys_checksum_loop MOV [ls_temp], A MOV X, [tx_sys_counter] MOV A, [ls_temp] MOV [X + tx_sys_buffer - 1], A ; store the checksum RET IFDEF TWO_WAY_DATA ;------------------------------------------------------- ; ; set_app_checksum ; ;------------------------------------------------------- set_app_checksum: MOV A, [tx_app_counter] SUB A, 2 ; don't check the checksum, 0 indexed MOV X, A MOV A, [checksum_seed] app_checksum_loop: XOR A, [X + tx_app_header] ; XOR each byte AND A, ffh ; clear carry flag DEC X JNC app_checksum_loop MOV [ls_temp], A ; csum is subtracted from zero to detect shift errors MOV X, [tx_app_counter] MOV A, [ls_temp] MOV [X + tx_app_header - 1], A ; store the checksum RET ENDIF ;------------------------------------------------------- ; ; clear_rx_packet ; ;------------------------------------------------------- clear_rx_packet: MOV A, 00h MOV [rx_counter], A MOV [packet_ready], A RET ;------------------------------------------------------- ; ; delay10us ; ; A 10 us delay at 12 MHz requires 120 cycles... ; ;------------------------------------------------------- delay10us: MOV A, 8 ; 8 cycles delay10us_loop: ; 9 cycles per loop DEC A ; 4 cycles JNZ delay10us_loop ; 5 cycles (4 if not taken) RET ; 8 cycles delay50us: CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us RET ;------------------------------------------------------- ; ; delay200us ; ;------------------------------------------------------- delay200us: CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us CALL delay10us RET