Difference Analysis Generated by HtmlDiff on 10/26/2004 1:34 PM  

Base file: C:\CY4632_RDK_1_21\Firmware\Source Code\RDK Bridge\wusb-ls-main.asm

Modified file: C:\CY4632_RDK_1_3\Firmware\Source Code\RDK Bridge\wusb-ls-main.asm

;****************************************************************************
;
;   file: wusb-ls-main.asm 
;   Description: This code acts as a bridge for a WirelessUSB mouse and keyboard
;   Target: Cypress CY7C63743
;   Version:        1.3.0000
;
;   This code is based on the logo.asm fw 
;
;   Overview:  
;       This firmware executes A single simple program loop.
;       On reset, the firmware initializes the radio and then
;       waits until enumerated by the USB host.
;       It then continuously polls the radio "data ready" 
;       input, and when active it reads and processes
;       radio received data. If valid, the received data
;       is loaded into the EP1 FIFO, and EP1 is armed
;       for transmission.
;                  
;   USB:
;       At bus reset the USB interface is re-initialized,
;       AND  the firmware soft reboots.  We are then able to
;       handle the standard chapter nine requests on 
;       endpoint zero (the control endpoint).  After this
;       device enumerates as A HID mouse on the USB, the
;       requests come to endpoint one (the data endpoint).
;       Endpoint one is used to send mouse displacement AND 
;       button status information.  
;
;   Pin Connections:
;
;                -------------------
;               | P0[0]     P0[4]   |
; RX Data Rdy   | P0[1]     P0[5]   |
;               | P0[2]     P0[6]   |
;               | P0[3]     P0[7]   |
;               | P1[0]     P1[1]   |   
;               | P1[2]     P1[3]   |
;               | P1[4]     P1[5]   |
;               | P1[6]     P1[7]   |
;       GND     | VSS       D+/SCLK |   USB D+ / PS2 SCLK
;       GND     | VPP       D-/SDATA|   USB D- / PS2 SDATA
;   PULLUP      | VREG      VCC     |   +5V
;               | XTALIN    XTALOUT |
;                -------------------
;
; Revisions:
;
;****************************************************************************
; 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.
;
;****************************************************************************

;---------------- assembler directives -------------------- 

INCLUDE "config.inc"            ; includes protocol configuration

IFDEF PDC_9075
    CPU 63743
ENDIF

IFDEF PDC_9168
    CPU 63723
ENDIF

XPAGEON

INCLUDE "637xx.inc"
INCLUDE "wusb-ls-headers.inc"


;--------------- interrupt vector table -------------------

ORG 00h         

JMP  reset               ; reset vector      
JMP  bus_reset           ; bus reset interrupt
JMP  error               ; 128us interrupt
JMP  ms_timer            ; 1.024ms interrupt
JMP  endpoint0_stub      ; endpoint 0 interrupt
JMP  error               ; endpoint 1 interrupt
JMP  error               ; endpoint 2 interrupt
JMP  error               ; reserved
JMP  error               ; Capture timer A interrupt Vector
JMP  error               ; Capture timer B interrupt Vector
JMP  error               ; GPIO interrupt
JMP  wakeup_isr          ; Wake-up interrupt vector 


;-------------- program listing ---------------------------

ORG  1Ah
error: JMP reset

;-------------------------------------------------------
;   MACROS
;-------------------------------------------------------
MACRO set_port_0 mask
    MOV  A, mask
    OR   [port0Shadow], A
    MOV  A, [port0Shadow]
    IOWR port0
ENDM

MACRO clr_port_0 mask
    MOV  A, ~mask
    AND  [port0Shadow], A
    MOV  A, [port0Shadow]
    IOWR port0
ENDM

MACRO set_port_1 mask
    MOV  A, mask
    OR   [port1Shadow], A
    MOV  A, [port1Shadow]
    IOWR port1
ENDM

MACRO clr_port_1 mask
    MOV  A, ~mask
    AND  [port1Shadow], A
    MOV  A, [port1Shadow]
    IOWR port1
ENDM


endpoint0_stub:                     ; cannot CALL directly from the interrupt table
    CALL endpoint0                  ; into the upper 4K block
    RETI
    
;----------------------------------------------------------
;
;   Interrupt handler: wakeup_isr
;
;----------------------------------------------------------
wakeup_isr:
RETI

;----------------------------------------------------------
;
;   Interrupt handler: bus_reset
;   Purpose: The program jumps to this routine when
;        the microcontroller has A bus reset.
;
;----------------------------------------------------------

bus_reset:
    MOV  A, STALL_IN_OUT             ; set to STALL INs&OUTs
    IOWR ep0_mode

    MOV  A, ADDRESS_ENABLE           ; enable USB address 0
    IOWR usb_address
    MOV  A, DISABLE                  ; disable endpoint1
    IOWR ep1_mode
    IOWR ep2_mode

    MOV  A, 00h                      ; reset program stack pointer
    MOV  psp,A   

    JMP  reset


;----------------------------------------------------------
;
;   Interrupt: ms_timer
;   Purpose: Every 1ms this interrupt handler clears
;       the watchdog timer.
;
;----------------------------------------------------------

ms_timer:
    PUSH A
    PUSH X

    IOWR watchdog
    
    INC  [app_timer]
    INC  [timer]                ; INC  1ms counter

IFDEF MFG_TEST
    MOV  A, [in_mfg_test]
    CMP  A, 00h
    JNZ  ms_timer_done
ENDIF

    INC  [led_timer]
    JNC  ms_suspend_timer
    MOV  A, f0hF0h                  ; prevent led_timer from overflowing
    MOV  [led_timer], A

ms_suspend_timer:                  
    IORD usb_status              ; read bus activity bit
    AND  A, BUS_ACTIVITY         ; mask off activity bit
    JNZ  bus_activity
        
    INC  [suspend_count]         ; increment suspend counter
    MOV  A, [suspend_count]
    CMP  A, 04h                  ; no bus activity for 4ms, suspend
    JNC  prepare_suspend
    JMP  ms_timer_done

prepare_suspend:
    ; We get here if we need to go into suspend mode
    CALL radio_suspend
    CALL encore_suspend

    ; Put the enCoRe into suspend    
usb_suspend:                        ; Put the enCoRe into suspend    
    MOV  A, [remote_wakeup]         ; if remote_wakeup enabled
    CMP  A, 01h
    JNZ  no_wake_up_int

    MOV  A, (USB_RESET_INT | WAKEUP_INT)      ; wake on USB_RESET_INT
    JMP  global_i
    
no_wake_up_int:
    MOV  A, (USB_RESET_INT)      ; wake on USB_RESET_INT

    global_i:
    IOWR global_int    

    IORD control
    OR   A, (SUSPEND|RUN)        ; set suspend bit
    AND  A, 11001111b            ; clear the RESET bits
    EI
    IOWR control

    ;;; IN SUSPEND STATE HERE ;;;

    NOP      ; This is first instruction executed after woken up

    ; Stay here if waking up while RESET
    IORD    control
    AND     A, 00110000b          ; check for reset and brownout reset (just in case)
    JZ      check_bus_activity

    MOV  A, 00h
    MOV  [remote_wakeup], A       ; disable remote wakeup

wait_reset:
    IOWR    watchdog
    JMP     wait_reset



;**************************************************************
; This section gets called during suspend due to the wake up
; timer. The bridge initiates a resume under the following
; conditions:
; 1. resume from system (bus activity)
; 2. resume from the bind button (force resume functionality)
; 3. resume from wireless device
;**************************************************************

check_bus_activity:                 ; if bus activity, exit suspend
    IORD usb_status
    AND  A, BUS_ACTIVITY
    JNZ  prepare_resume
        
while_host_is_suspended:
;DEFINE RESUME_FROM_BIND_BUTTON
IFDEF RESUME_FROM_BIND_BUTTON        
    CALL check_for_bind
    AND  A, ffh
    JNZ  prepare_resume
ENDIF

    CALL rwu_poll_radio
    CMP  A, 01h
    JNZ  do_rwu_resume                 
    JMP  usb_suspend

prepare_resume:
    CALL encore_resume
    CALL radio_resume
    JMP  do_rwu_resume                  ; saw wake up event

do_rwu_resume:
    MOV  A, [remote_wakeup]             ; if remote_wakeup enabled
    CMP  A, 01h
    JNZ  back_in_business
    CALL signal_usb_resume

    MOV   A,NAK_IN                  
    IOWR  ep1_mode


back_in_business:        
    MOV  A, (1MS_INT|USB_RESET_INT)
    IOWR global_int    

bus_activity:
    MOV  A, 00h                         ; reset suspend counter
    MOV  [suspend_count], A

    IORD usb_status                 
    AND  A, ~BUS_ACTIVITY               ; clear bus activity bit
    IOWR usb_status                 

ms_timer_done:
    POP  X
    POP  A
    RETI

;----------------------------------------------------------
;
;   Interrupt handler: reset
;   Purpose: The program jumps to this routine when
;        the microcontroller has A power on reset.
;
;----------------------------------------------------------

reset:
    MOV  A, (LVR_ENABLE | INTERNAL_CLK)  ; set for use with internal oscillator  
    IOWR clock_config
    
    MOV  A, DSP_TOP                  ; set data stack pointer
    swap A, dsp                  
    MOV  A, PSP_BASE                 ; set PC stack pointer
    MOV  psp,A   
    
    IOWR watchdog
        
    CALL radio_interface_init       ; configure the GPIOs

    ; clear variables
    MOV  A, 00h                      

    MOV  [ep0_in_machine], A     
    MOV  [configuration], A              
    MOV  [ep1_stall], A                  
    MOV  [idle], A
    MOV  [suspend_count], A
    MOV  [ep1_dmabuff0], A
    MOV  [ep1_dmabuff1], A
    MOV  [ep1_dmabuff2], A
    MOV  [int_temp], A
    MOV  [idle_timer], A
    MOV  [idle_prescaler], A
    MOV  [event_machine], A
    MOV  [ep0_transtype], A

    MOV  [pc_has_desc], A
    MOV  [remote_wakeup], A          ; remote wake up is disabled by default
IFDEF MFG_TEST
    MOV  [in_mfg_test], A
ENDIF ; MFG_TEST

    MOV  [c0h], A
    MOV  [c1h], A
    MOV  [c2h], A
    MOV  [c3h], A
    MOV  [c4h], A
    MOV  [c5h], A
    MOV  [c6h], A
    MOV  [c7h], A
    MOV  [c8h], A
    MOV  [c9h], A
    MOV  [cah], A
    MOV  [cbh], A
    MOV  [cch], A
    MOV  [cdh], A
    MOV  [ceh], A
    MOV  [cfh], A

    MOV  [button_pushed], A                
    MOV  [rssi_a], A                   
    MOV  [rssi_b], A   
IFDEF AGC_SUPPORT
    MOV  [corrupt_rssi], A                
    MOV  [agc_control], A
ENDIF ; AGC_SUPPORT
                   
    ;initialize application variables
    MOV  [rx_counter], A
    MOV  [packet_ready], A
    MOV  [sequence_id_a], A
    MOV  [app_timer], A
IFDEF USE_DEVICE_ID_BIT
    MOV  [sequence_id_b], A
ENDIF ; USE_DEVICE_ID_BIT
    MOV  [timer], A

    MOV  [checksum_a], A
    MOV  [checksum_b], A
    
IFDEF BIND_AUTO
    MOV  [corrupt_counter], A
    MOV  [tx_ack_pending], A
ENDIF

IFDEF TWO_WAY_DATA
    MOV  [tx_app_counter], A
ENDIF

IFDEF ENCRYPT_DATA_A
    MOV  [encrypt_signature], A
ENDIF

    MOV  [bad_packets_a_low], A  
    MOV  [bad_packets_a_high], A 
    MOV  [good_packets_a_low], A    
    MOV  [good_packets_a_high], A
    MOV  [bad_packets_b_low], A  
    MOV  [bad_packets_b_high], A 
    MOV  [good_packets_b_low], A    
    MOV  [good_packets_b_high], A

    MOV  [led_state], A
    MOV  [ep1_dmabuff + 0], A
    MOV  [ep1_dmabuff + 1], A
    MOV  [ep1_dmabuff + 2], A
    MOV  [ep1_dmabuff + 3], A
    MOV  [ep1_dmabuff + 4], A
    MOV  [ep1_dmabuff + 5], A
    MOV  [ep1_dmabuff + 6], A
    MOV  [ep1_dmabuff + 7], A
    MOV  [ep2_dmabuff + 0], A
    MOV  [ep2_dmabuff + 1], A
    MOV  [ep2_dmabuff + 2], A
    MOV  [ep2_dmabuff + 3], A
    MOV  [ep2_dmabuff + 4], A
    MOV  [ep2_dmabuff + 5], A
    MOV  [ep2_dmabuff + 6], A
    MOV  [ep2_dmabuff + 7], A
    
IFDEF DYNAMIC_PA_SUPPORT
    MOV  A, PA_BIAS
    MOV  [pa_bias_a], A
    MOV  [pa_bias_b], A
ENDIF ; DYNAMIC_PA_SUPPORT
    
    MOV  A, 01h
    MOV  [protocol], A

    MOV  A, WAKEUP_ADJUST2|WAKEUP_ADJUST1|WAKEUP_ADJUST0|PRECISION_CLK_ENABLE|INTERNAL_CLK ;128*tWAKE
    IOWR clock_config                 ; set wakeup timer interval AND  disable XTALOUT

    ; enable global interrupts
    MOV  A, (1MS_INT | USB_RESET_INT)
    IOWR global_int

    ; enable endpoint  0 interrupt
    MOV  A, EP0_INT          
    IOWR endpoint_int

    ; enable USB address for endpoint 0
    MOV  A, ADDRESS_ENABLE
    IOWR usb_address

    MOV A,ffh
    MOV  [led_timer], A
    
IFDEF TWO_WAY_DATA
    MOV  A, 50h                     ; THIS IS DEBUG CODE FOR TWO_WAY_DATA
    MOV  [tx_app_buffer], A
ENDIF   ; TWO_WAY_DATA

    EI                              ; enable all interrupts

    MOV  A, VREG_ENABLE             ; enable USB pullup resistor
    IOWR    usb_status              ; to signal connection to host

IFDEF MFG_TEST
    IORD port2
    AND  A, 30h
    CMP  A, 30h
    JNZ  not_se1_state

    CALL delay200us
    CALL delay200us

    IORD port2
    AND  A, 30h
    CMP  A, 30h
    JNZ  not_se1_state
    
    MOV  A, FFh
    MOV  [in_mfg_test], A
    JMP  mfg_test_mode              ; SE1 state signals mfg test mode
    
not_se1_state:
ENDIF ; MFG_TEST

enum_wait:        
    IOWR watchdog
    MOV  A, [configuration]          ; wait until configured
    CMP  A, 01h                      
    JNZ  enum_wait

IFDEF ENDPOINT_1                      
    ;send A null USB report on EP1
    MOV  A, NUM_EP1_BYTES            ; set endpoint 1 to send defined number of bytes
    OR   A, [ep1_data_toggle]         
    IOWR ep1_count                  
    MOV  A, ACK_IN                   ; set to ack on endpoint 1
    IOWR ep1_mode                    ; AND  flag that data is waiting

IFDEF STARTUP_WAIT_ON_EP                      
.desc_wait1:        
    IOWR watchdog                   ; wait until PC takes that first null report
    IORD ep1_mode                   ; which indicates that PCHasDesc
    AND  A, 0Fh
    CMP  A, ACK_IN
    JZ   .desc_wait1
    CMP  A, NAK_IN
    JZ   .desc_wait_end1
    MOV  A, ACK_IN
    IOWR ep1_mode
    JMP  .desc_wait1
.desc_wait_end1:
    MOV  A, 01h
    MOV  [pc_has_desc], A
ENDIF ; STARTUP_WAIT_ON_EP                     
ENDIF ; ENDPOINT_1
        
    CALL app_init_a
    CALL app_init_b

IFDEF BIND_AUTO
    JMP  power_on_mode
ENDIF ; BIND_AUTO

;**********************************************************
;
;       connected_mode:
;
;**********************************************************
connected_mode_init:
IFNDEF BIND_AUTO
    CALL radio_init             ; set up the radio
    CALL bind_init              ; set up the PN_CODE AND  channel                      
    CALL setup_rx               ; set the radio into RX mode...
ENDIF ; BIND_AUTO

connected_mode:
IFDEF BIND_AUTO
    CALL switch_rx
ENDIF ; BIND_AUTO

    MOV  A, 00h
    MOV  [packet_type], A
    MOV  [rx_counter], A
IFDEF BIND_AUTO
    MOV  [corrupt_counter], A
    MOV  [rssi_counter], A
ENDIF

connected_loop:
    IOWR watchdog

    MOV  A, 0
    MOV  [packet_ready], A

    IORD port0
    AND  A, IRQ
    JZ   connected_bind_check
    CALL process_rx_int                  

check_packet:
    MOV  A, [rx_counter]             ; sometimes process_rx_int triggers null length packets
    AND  A, ffh                      ; at 32 AND  64 kbps
    JZ   connected_loop

    MOV  A, [packet_ready]
    AND  A, bFLAG_EOF
    JZ   connected_loop
    
    CALL verify_packet              ; process packet on channel A
    MOV  A, [packet_ready]          ; check if the packet is valid
    AND  A, bFLAG_VALID
    JZ   process_corrupt_packet

    CALL switch_tx

    IFDEF BIND_AUTO    
        CALL dec_corrupt_counter    ; decrement the corrupt counter for each valid packet received
    ENDIF  ; BIND_AUTO

    MOV  A, [packet_type]           ; Check for DATA packet
    CMP  A, PT_DATA
    JZ   process_data

IFDEF BIND_AUTO
    MOV  A, [packet_type]
    CMP  A, PT_CONN_REQ
    JNZ  conn_check_ping
    CALL process_conn_req
    CMP  A, ffh                     ; A == ffh if A good conn req
    JNZ  process_packet_complete

    MOV  A, bWAIT_FOR_ACK_A
    MOV  [tx_ack_pending], A        ; wait for an ACK for this conn req
    MOV  A, 0
    MOV  [timer], A                 ; reset the timer so that the ACK doesn't time out
    JMP  process_packet_complete

conn_check_ping:                    ; Check for PING packet
    MOV  A, [packet_type]
    CMP  A, PT_PING
    JNZ  conn_check_null
    CALL send_ping_rsp
    JMP  process_packet_complete
ENDIF   ; BIND_AUTO

conn_check_null:    
    MOV  A, [packet_type]
    CMP  A, PT_NULL
    JNZ  conn_check_ack

    MOV  A, [rx_counter]       
    CMP  A, LEN_NULL                ; either 1 or 2 bytes long
    JNZ  process_packet_complete

IFDEF USE_DEVICE_ID_BIT    
    MOV  A, [rx_buffer]
    AND  A, bDEVICE_ID_NULL
    JNZ  conn_null_b
ENDIF ; USE_DEVICE_ID_BIT

conn_null_a:
IFDEF USE_NULL_PKTS   
    MOV  A, [rx_buffer]              ; store the received sequence_id
    MOV  [sequence_id_a], A

    CALL send_ack_a
    MOV  A, [rx_buffer]
    ASR 
    ASR 
    AND  A, 03h                      ; A = two data bits from NULL header
    MOV  X, 0
    CALL app_data_received_a
ENDIF ; USE_NULL_PKTS    
    JMP  process_packet_complete


IFDEF USE_DEVICE_ID_BIT    
conn_null_b: 
IFDEF USE_NULL_PKTS   
    MOV  A, [rx_buffer]              ; store the received sequence_id
    MOV  [sequence_id_b], A

    CALL send_ack_b
    MOV  A, [rx_buffer]
    ASR 
    ASR 
    AND  A, 03h                  ; A = two data bits from NULL header
    MOV  X, 0
    CALL app_data_received_b
ENDIF ; USE_NULL_PKTS  
    JMP  process_packet_complete
ENDIF ; USE_DEVICE_ID_BIT    


conn_check_ack:
    MOV  A, [packet_type]
    CMP  A, PT_ACK
    JZ   conn_process_ack

IFDEF ENCRYPT_DATA_A
    MOV  A, [packet_type]
    CMP  A, PT_KEY_REQUEST
    JNZ  process_packet_complete
    MOV  A, [rx_counter]       
    CMP  A, 1                       ; KEY_REQUEST packets must be 1 byte long
    JNZ  process_packet_complete
    CALL process_key_req
ENDIF    

process_packet_complete:            ; process_data_a jumps to here when finished
    CALL switch_rx
    MOV  A, 00h
    MOV  [packet_ready], A
    MOV  [packet_type], A
    MOV  [rx_counter], A
    JMP  connected_loop_complete
  
connected_bind_check:                
    MOV  A, [timer]                   
    SUB  A, BIND_POLL_TIMEOUT        
    JC   connected_loop               

    MOV  A, [rx_counter]
    CMP  A, 0
    JNZ  connected_loop         ; do not check RSSI or bind if we are in the middle of receiving a packet
    
IFDEF BIND_BASIC    
    CALL bind_process           ; this should CALL bind_process every 48ms except when there is data...    
ENDIF
IFDEF BIND_SEMI
    CALL check_for_bind         ; if bind button is pushed, check_for_bind returns A non-zero A
    AND  A, ffh
    JZ   connected_check_rssi
    ; clear any pressed buttons
    CALL app_disconnect_a
    JMP  bind_mode
ENDIF   ; BIND_SEMI
IFDEF BIND_AUTO
    CALL check_for_bind             ; if bind button is pushed, check_for_bind returns A non-zero A
    AND  A, ffh
    JZ   connected_check_rssi
    ; clear any pressed buttons
    CALL app_disconnect_a
    JMP  bind_mode
ENDIF   ; BIND_AUTO
       
connected_check_rssi: 
IFDEF USE_RSSI
    MOV  A, [rssi_counter]          ; multiply rssi_counter by 3
    ASL  A
    ADD  A, [rssi_counter]
;                                   ;7.14 TRY    
    MOV  [rssi_counter], AA, CONNECTED_MODE_RSSI
    CALL check_rssi
    ADD  A, [rssi_counter]          ; add current rssi reading to rssi_counter
    ASR  A
    ASR  A
    AND  A, 03Fh                    ; ASR may not shift a 0 into top bit
    MOV  [rssi_counter], A
    CMP  A, [rssi_adjust]NUM_HIGH_RSSI_READINGS

    JC   connected_rssi_reset
    CALL app_disconnect_a
    MOV  A, PING_REASON_RSSI        ; jumping to ping due to RSSI
    JMP  ping_mode                  ; Change channels if this channel is too noisy

connected_rssi_reset:
    CALL setup_rx    
ENDIF   ; USE_RSSI
    
IFDEF BIND_AUTO    
    MOV  A, 00h
    MOV  [tx_ack_pending], A
ENDIF ; BIND_AUTO

connected_loop_complete:   
    MOV  A, 00h
    MOV  [timer], A
    CALL clear_rx_packet
    CALL connected_leds

    MOV  A, [app_timer]
    CMP  A, APP_IDLE_TIMEOUT
    JC   connected_loop
    
    CALL app_idle_a
    MOV  A, 0
    MOV  [app_timer], A
    JMP  connected_loop
       

;-------------------------------------------------------
;   process_corrupt_packet_a
;-------------------------------------------------------
process_corrupt_packet:
IFDEF AGC_SUPPORT
    MOV  A, [corrupt_rssi]          ; multiply corrupt_rssi by 3
    ASL  A
    ADD  A, [corrupt_rssi]
    MOV  [corrupt_rssi], A
    CALL get_rssi
    ADD  A, [corrupt_rssi]          ; add current rssi reading to corrupt_rssi
    ASR  A
    ASR  A
    AND  A, 03Fh                    ; ASR may not shift a 0 into top bit
    MOV  [corrupt_rssi], A
    ; the corrupt packets could be caused by a device in close proximity
    CMP  A, CORRUPT_RSSI_MAX_THRESHOLD
    JC   process_corrupt_check_threshold
    MOV  A, [corrupt_counter]
    CMP  A, AGC_CORRUPT_THRESHOLD
    JC   process_corrupt_check_threshold
    CALL radio_agc_on
    JMP  process_packet_complete
ENDIF ; AGC_SUPPORT

process_corrupt_check_threshold:
IFDEF BIND_AUTO
    MOV  A, [corrupt_counter]
    CMP  A, CORRUPT_THRESHOLD
    JC   process_packet_complete
    
process_corrupt_disconnect:
    CALL app_disconnect_a
    MOV  A, PING_REASON_CORRUPT
    JMP  ping_mode  
ENDIF   ; BIND_AUTO
    
process_corrupt_okay:    
    INC  [bad_packets_a_low]
    JNC  corrupt_link_qual_b
    INC  [bad_packets_b_high]

corrupt_link_qual_b:
    INC  [bad_packets_a_low]
    JNC  process_packet_complete
    INC  [bad_packets_b_high]

    JMP  process_packet_complete


;-------------------------------------------------------
;   process_data
;
;   Checks for retransmitted packet AND  unchanged data
;
;   NOTE: process_data falls through to send_ack
;-------------------------------------------------------
process_data:
    MOV  A, [rx_counter]
    CMP  A, 2
    JC   process_packet_complete

IFDEF USE_DEVICE_ID_BIT
    MOV  A, [rx_buffer]
    AND  A, bDEVICE_ID_DATA
    JNZ  process_data_b
ENDIF ; USE_DEVICE_ID_BIT    

process_data_a:
    MOV  A, CONNECTED_MODE_RSSI
    CALL getcheck_rssi
    ADD  A, [rssi_a]
    ASR  A
    AND  A, 7Fh
    MOV  [rssi_a], A
IFDEF AGC_SUPPORT
    CMP  A, RSSI_MIN_AGC_THRESHOLD
    JNC  check_seq_a
    ; Is the low signal RSSI caused by AGC being on?
    CALL radio_agc_off
ENDIF

check_seq_a:
    MOV  A, [sequence_id_a]
    AND  A, FFh
    JZ   store_seq_a                  

    CMP  A, [rx_buffer]              ; compare last received sequence_id with sequence_id byte
    JNZ  store_seq_a
    MOV  X, [rx_counter]
    MOV  A, [X+rx_buffer-1]
    CMP  A, [checksum_a]
    JNZ  store_seq_a

    CALL send_ack_a

    INC  [bad_packets_a_low]
    JNC  check_seq_a_link_qual_b
    INC  [bad_packets_a_high]
check_seq_a_link_qual_b:
    INC  [bad_packets_b_low]
    JNC  process_packet_complete
    INC  [bad_packets_b_high]

    JMP  process_packet_complete

store_seq_a:
    MOV  X, [rx_counter]
    DEC  X                           ; substract header and checksum
    DEC  X
    MOV  A, 00h                      ; to be sent.
    CALL app_verify_packet_a        ; IF A == 0 then packet is bad, else packet is good
    AND  A, ffh
    JZ   process_packet_complete

    MOV  A, [rx_buffer]              ; store the received sequence_id
    MOV  [sequence_id_a], A

    MOV  X, [rx_counter]
    MOV  A, [X+rx_buffer-1]
    MOV  [checksum_a], A            ; store the checksum

    CALL send_ack_a
    MOV  X, [rx_counter]
    DEC  X                           ; substract header and checksum
    DEC  X
    MOV  A, 00h                      
IFDEF ENCRYPT_DATA_A
    MOV  [encrypt_signature], A
ENDIF
    CALL app_data_received_a         ; app-specific routine to format the data and hand it off to app

good_link_qual_a:
    INC  [good_packets_a_low]
    JNC  good_link_qual_a_b
    INC  [good_packets_a_high]
    JNC  good_link_qual_a_b    ; reset corrupt packet count if total packet count rolled over
    MOV  A, 0
    MOV  [bad_packets_a_low], A
    MOV  [bad_packets_a_high], A

good_link_qual_a_b:
    INC  [good_packets_b_low]
    JNC  process_packet_complete
    INC  [good_packets_b_high]
    JNC  process_packet_complete    ; reset corrupt packet count if total packet count rolled over
    MOV  A, 0
    MOV  [bad_packets_b_low], A
    MOV  [bad_packets_b_high], A
    JMP  process_packet_complete

IFDEF USE_DEVICE_ID_BIT    
process_data_b:
    MOV  A, CONNECTED_MODE_RSSI         ; check the RSSI of the channel
    CALL getcheck_rssi
    ADD  A, [rssi_b]
    ASR  A
    AND  A, 7Fh
    MOV  [rssi_b], A
IFDEF AGC_SUPPORT
    CMP  A, RSSI_MIN_AGC_THRESHOLD
    JNC  check_seq_b
    ; Is the low signal RSSI caused by AGC being on?
    CALL radio_agc_off
ENDIF ; AGC_SUPPORT

check_seq_b:
    MOV  A, [sequence_id_b]
    AND  A, FFh
    JZ   store_seq_b                  

    MOV  A, [sequence_id_b]         ; Check for retransmitted packet
    CMP  A, [rx_buffer]             ; compare last received sequence_id with sequence_id byte
    JNZ  store_seq_b
    MOV  X, [rx_counter]
    MOV  A, [X+rx_buffer-1]
    CMP  A, [checksum_b]
    JNZ  store_seq_b

    CALL send_ack_b                 ; IF same THEN discard packet, but send an ACK
    INC  [bad_packets_a_low]
    JNC  check_seq_b_link_qual_b
    INC  [bad_packets_a_high]
check_seq_b_link_qual_b:
    INC  [bad_packets_b_low]
    JNC  process_packet_complete
    INC  [bad_packets_b_high]

    JMP  process_packet_complete

store_seq_b:
    MOV  X, [rx_counter]
    DEC  X                          ; substract header AND  checksum
    DEC  X
    MOV  A, 0
    CALL app_verify_packet_b        ; IF A == 0 then packet is bad, else packet is good
    AND  A, ffh
    JZ   process_packet_complete    

    MOV  A, [rx_buffer]            ; store the received sequence_id
    MOV  [sequence_id_b], A

    MOV  X, [rx_counter]
    MOV  A, [X+rx_buffer-1]
    MOV  [checksum_b], A            ; store the checksum

    CALL send_ack_b
    MOV  X, [rx_counter]
    DEC  X                          ; substract header AND  checksum
    DEC  X
    MOV  A, 0
    CALL app_data_received_b        ; app-specific routine to format the data AND  hand it off to USB

good_link_qual_b:
    INC  [good_packets_b_low]
    JNC  good_link_qual_b_a
    INC  [good_packets_b_high]
    JNC  good_link_qual_b_a         ; reset corrupt packet count if total packet count rolled over
    MOV  A, 0
    MOV  [bad_packets_b_low], A
    MOV  [bad_packets_b_high], A

good_link_qual_b_a:
    INC  [good_packets_a_low]
    JNC  process_packet_complete
    INC  [good_packets_a_high]
    JNC  process_packet_complete    ; reset corrupt packet count if total packet count rolled over
    MOV  A, 0
    MOV  [bad_packets_a_low], A
    MOV  [bad_packets_a_high], A
    JMP  process_packet_complete

    JMP  process_packet_complete
ENDIF ; USE_DEVICE_ID_BIT    

;-------------------------------------------------------
;       get_rssi
;-------------------------------------------------------
get_rssi:
    MOV  A, REG_RSSI
    MOV  [reg_addr], A
    CALL SPI_read
    CALL SPI_read                      ; RWW we may not need this SPI_read
    MOV  A, [reg_data]
    AND  A, mRSSI                   ; mask-off high-order 3 bits
    RET
    

;-------------------------------------------------------
;       send_ack
;-------------------------------------------------------
send_ack_a:
IFDEF DYNAMIC_PA_SUPPORT
    CALL set_pa_a
ENDIF ; DYNAMIC_PA_SUPPORT

    MOV  A, [batt_report_req_a]     ; batt_report_req_a can be 0 or 1.   
    MOV  [tx_app_counter], A        ; When tx_app_counter = 1 we send ACK_DATA instead of ACK

    ; Put the KBD signature in the data byte of ACK_DATA
    ; If batt_report_req_a == 0, signature will be overwritten by ACK
    SWAP A,X
    MOV  A, 74h                     
    MOV  [X + tx_app_header], A                                     
    
    MOV  A, 0h                      ; Reset batt_report_req_a to 0 
    MOV  [batt_report_req_a], A      

    MOV  A, [sequence_id_a]
    ASR 
    AND  A, 02h                      ; clear everything but the data toggle bit
IFDEF USE_DEVICE_ID_BIT
    JMP  send_ack

send_ack_b:
IFDEF DYNAMIC_PA_SUPPORT
    CALL set_pa_b
ENDIF ; DYNAMIC_PA_SUPPORT

    MOV  A, [batt_report_req_b]     ; batt_report_req_b can be 0 or 1. 
    MOV  [tx_app_counter], A        ; When tx_app_counter = 1 we send ACK_DATA instead of ACK

    ; Put the Mouse signature in the data byte of ACK_DATA
    ; If batt_report_req_b == 0, signature will be overwritten by ACK
    SWAP A,X
    MOV  A, 1Eh                     
    MOV  [X + tx_app_header], A                                     

    MOV  A, 0h                      ; Reset batt_report_req_b to 0 
    MOV  [batt_report_req_b], A
             
    MOV  A, [sequence_id_b]
    ASR 
    AND  A, 02h                      ; clear everything but the data toggle bit
    OR   A, bDEVICE_ID_ACK
ENDIF ; USE_DEVICE_ID_BIT

send_ack:
IFDEF TWO_WAY_DATA              
    MOV  [ls_temp], A
    
    MOV  A, [tx_app_counter]         ; if tx_app_counter > 0, send_ack_data_a
    AND  A, ffh                      ; MOV  doesn't set zero flag
    JNZ  send_ack_data
    
    MOV  A, [ls_temp]
ENDIF ; TWO_WAY_DATA
    
    OR   A, PT_ACK                   ; set header nibble as ACK 
    OR   A, bHEADER_FLAG
    MOV  [tx_sys_buffer], A
    CALL set_sys_parity              ; set the parity bit
    
    MOV  A, LEN_ACK                  ; ACK Packet length
    MOV  [tx_sys_counter], A    

IFDEF CHECKSUM_ALL_PACKETS
    MOV  A, [checksum_seed]         ; A = checksum seed
    CALL set_sys_checksum           ; calculate the checksum
ENDIF ; CHECKSUM_ALL_PACKETS

    CALL delay50us                  ; the HID isn't turning around as fast as the bridge...
    CALL delay50us                  
    CALL delay50us                  
    CALL delay50us                  
    CALL delay50us                  
    CALL delay50us                  

    CALL transmit_sys

IFDEF TWO_WAY_DATA    
    MOV  A, 00h
    MOV  [tx_ack_pending], A        ; clear tx_ack_pending flag
ENDIF ; TWO_WAY_DATA
    
    RET         

IFDEF TWO_WAY_DATA              
;-------------------------------------------------------
;   send_ack_data
;-------------------------------------------------------
send_ack_data:
    MOV  A, [rx_buffer]               ; extract the data toggle bit from the recvd packet
    ASR  A
    AND  A, 02h                       ; 
    OR   A, PT_ACKDATA                ; set packet type
    OR   A, bHEADER_FLAG              ; set flag for positive ACK    
    MOV  [tx_app_header], A  

    MOV  A, [tx_ack_pending]        ; IF the ACK/Data was previously sent, but
    AND  A, bWAIT_FOR_ACK_A         ; an ACK was not received, do not toggle the
    JNZ  send_ack_data_parity       ; the data toggle

    MOV  A, bWAIT_FOR_ACK_A
    MOV  [tx_ack_pending], A        ; set tx_ack_pending to a non-zero value

    MOV  A, [tx_data_toggle]
    AND  A, ffh
    JNZ  send_ack_data_toggle_off
    MOV  A, [tx_app_header]          ; set the TX data toggle bit
    OR   A, bTX_DATA_TOGGLE
    MOV  [tx_app_header], A
    MOV  [tx_data_toggle], A         ; set the tx_data_toggle
    JMP  send_ack_data_parity
    
send_ack_data_toggle_off:    
    MOV  A, 0
    MOV  [tx_data_toggle], A         ; clear the tx_data_toggle

send_ack_data_parity:
    CALL set_app_parity
    INC  [tx_app_counter]            ; increment the counter to include the data byte
    INC  [tx_app_counter]            ; increment the counter to include the checksum
    CALL set_app_checksum
    
    CALL transmit_app
    
    MOV  A, 00h
    MOV  [tx_app_counter], A         ; clear so that ACK/DATA won't be sent again
    RET 


;-------------------------------------------------------
;   transmit_app_packet
;
;-------------------------------------------------------
transmit_app_packet:
    MOV  A, PT_DATA                  ; set packet type
    OR   A, bHEADER_FLAG              ; set flag for positive ACK
    MOV  [tx_app_header], A  

    MOV  A, [tx_data_toggle]
    AND  A, ffh
    JNZ  transmit_app_toggle_off
    MOV  A, [tx_app_header]          ; set the TX data toggle bit
    OR   A, bTX_DATA_TOGGLE
    MOV  [tx_app_header], A
    MOV  [tx_data_toggle], A         ; set the tx_data_toggle
    JMP  transmit_app_parity
    
transmit_app_toggle_off:    
    MOV  A, 0
    MOV  [tx_data_toggle], A         ; clear the tx_data_toggle

transmit_app_parity:
    CALL set_app_parity
    INC  [tx_app_counter]            ; increment the counter to include the header byte
    INC  [tx_app_counter]            ; increment the counter to include the checksum
    CALL set_app_checksum
    
    CALL transmit_app
    
    RET 

ENDIF ; TWO_WAY_DATA


;-------------------------------------------------------
;   conn_process_ack
;-------------------------------------------------------
conn_process_ack:
IFNDEF TWO_WAY_DATA
IFDEF BIND_AUTO
    MOV  A, [rx_counter]
    CMP  A, LEN_ACK
    JNZ  process_packet_complete
    MOV  A, [tx_ack_pending]
    AND  A, bWAIT_FOR_ACK_A
    JNZ  wait_for_ack_received

    INC  [corrupt_counter]                ; if we receive an unexpected valid ACK someone else is on our channel/PN code
    MOV  A, [corrupt_counter]
    CMP  A, CORRUPT_THRESHOLD
    JC   wait_for_ack_received      ; check the corrupt threshold
    CALL app_disconnect_a
    MOV  A, PING_REASON_CORRUPT
    JMP  ping_mode  
    
wait_for_ack_received:
    MOV  A, 0
    MOV  [tx_ack_pending], A
    JMP  process_packet_complete
ENDIF ; BIND_AUTO
ELSE ; TWO_WAY_DATA              
    MOV  A, [tx_ack_pending]         ; are we waiting for an ACK?
    AND  A, bWAIT_FOR_ACK_A
    JNZ  conn_process_ack_expected   ; We're not waiting for an ACK, it's probably unsolicited
IFDEF BIND_AUTO
    INC  [corrupt_counter]       
    MOV  A, [corrupt_counter]
    CMP  A, CORRUPT_THRESHOLD
    JC   conn_process_ack_complete
    CALL app_disconnect_a
    MOV  A, PING_REASON_CORRUPT
    JMP  ping_mode  
ELSE    ; BIND_AUTO
    JMP conn_process_ack_complete
ENDIF    ; BIND_AUTO
    
conn_process_ack_expected:    
    MOV  A, [rx_buffer]
    AND  A, bHEADER_FLAG
    JZ   conn_process_ack_complete    ; Bad ACK... do not clear flags
    
    MOV  A, 00h                       ; good ACK, clear tx_app_counter
    MOV  [tx_app_counter], A
    MOV  [tx_ack_pending], A

    JMP  conn_process_ack_complete
        
ENDIF   ; TWO_WAY_DATA

conn_process_ack_complete:
    JMP  process_packet_complete




;****************************************************************************
; encore_suspend
;
; Processing:
; The radio is put into Suspend state
;
;****************************************************************************
encore_suspend :

; Set all pins to resistive mode if possible to prevent current flow during suspend. 

; Set Port 1.0 to Hiz, others to resistive (data=1!) for low power
    MOV  A, P1_MODE_1_SUSPEND
    IOWR port1_mode1
    MOV  A, P1_MODE_0_SUSPEND
    IOWR port1_mode0
    MOV  A, P1_DATA_SUSPEND
    IOWR port1

; Set Port 0 to resistive mode
    MOV  A, P0_MODE_1_SUSPEND 
    IOWR port0_mode1
    MOV  A, P0_MODE_0_SUSPEND 
    IOWR port0_mode0
    MOV  A, P0_DATA_SUSPEND 
    IOWR port0
  
    RET 

;****************************************************************************
; encore_resume
;
; Processing:
; The radio is put into Suspend state
;
;****************************************************************************
encore_resume :

    ;Put the GPIOs back to their normal state 
    MOV  A, [port0Shadow]
    IOWR port0
    MOV  A, P0_MODE_0_DEFAULT
    IOWR port0_mode0
    MOV  A, P0_MODE_1_DEFAULT
    IOWR port0_mode1
        
    MOV  A, [port1Shadow]
    IOWR port1
    MOV  A, P1_MODE_0_DEFAULT
    IOWR port1_mode0
    MOV  A, P1_MODE_1_DEFAULT
    IOWR port1_mode1

    RET 
    
;****************************************************************************
; signal_usb_resume
;
; Processing:
; The USB bus is forced into resume state
;
;****************************************************************************
signal_usb_resume:

    MOV  A, VREG_ENABLE | CONTROL1   ; force J   (D+ Low, D- High)
    IOWR usb_status
    MOV  A, VREG_ENABLE | CONTROL0   ; force K   (D+ High, D- Low)
    IOWR usb_status
            
    MOV  A, 10h                      ; wait (USB Spec is 1ms - 15ms)
    MOV  X, A

usb_res_timer_1:
    IOWR watchdog
    MOV  A, FFh                     
usb_res_timer_0:                       
    DEC  A                            
    JNZ  usb_res_timer_0             
    DEC  X                            
    JNZ  usb_res_timer_1             

    MOV  A, VREG_ENABLE | CONTROL1  ; force J - to prevent SE1 on the bus
    IOWR usb_status

    MOV  A, VREG_ENABLE             ; disable forcing 
    IOWR usb_status       

    MOV  A, 0h                      ; Flag that we have signalled resume on USB
    MOV  [remote_wakeup], A         ; Keeps us from re-signalling resume (for ill-behaved USB boxes)

    MOV  [sequence_id_a], A         ; Ensures that the wakeup packet actually wakes-up the host
    MOV  [sequence_id_b], A
                                    
    RET 

;****************************************************************************
; rwu_poll_radio
;
; Processing:
; The radio is polled during suspend to allow remote wakeup from HID device
;
; Output:
; A == 1 ==> radio was resuspended (no remote wakeup)
; A == 0 ==> radio was not resuspended (remote wakeup activated)
;
;****************************************************************************
rwu_timer_0:          equ C8h
rwu_timer_1:          equ C9h
rwu_resuspend:        equ CAh
            
rwu_poll_radio:
    CALL encore_resume
    CALL radio_resume

    MOV  A,00h
    MOV  [packet_ready],A          ; packet_ready = 0;
    MOV  [rx_counter],A            ; rx_counter = 0;
         
    MOV  A,01h
    MOV  [rwu_resuspend],A         ; rwu_resuspend = 1;
                  
    MOV  A,06h                     ; ~ ms ON time of radio
    MOV  [rwu_timer_1],A           ; Period is ~ 270 ms
                                   ; 0A = 10 ms ON, 260 ms OFF
                                   
.rwu_timer_1_loop:
    IOWR watchdog                  ; WATCHDOG = AC;
    MOV  A,ffh
    MOV  [rwu_timer_0],A           ; rwu_timer_0 = 0xFF;
                                   ; do
.rwu_timer_0_loop:
    IORD port0                     ; AC = PORT0;
    AND  A,IRQ                     ; if(!(AC & IRQ)) 
    JZ   .dec_rwu_timer_0 
    
.rwu_poll_radio:
    CALL process_rx_int
    MOV  A,[rx_counter]            ; if(rx_counter) 
    CMP  A,00h       
    JZ   .dec_rwu_timer_0                              
    MOV  A,00h
    MOV  [rwu_resuspend],A         ; rwu_resuspend = 0;

.dec_rwu_timer_0:
    DEC  [rwu_timer_0]             ; rwu_timer_0--;
    MOV  A,[rwu_timer_0]           ; while(rwu_timer_0 && rwu_resuspend);
    CMP  A,00h       
    JZ   .dec_rwu_timer_1       
    MOV  A,[rwu_resuspend]     
    CMP  A,00h       
    JNZ  .rwu_timer_0_loop       
    
.dec_rwu_timer_1:
    DEC  [rwu_timer_1]             ; rwu_timer_1--;
    MOV  A,[rwu_timer_1]           ; while(rwu_timer_1 && rwu_resuspend);
    CMP  A,00h       
    JZ   .if_rwe_resuspend       
    MOV  A,[rwu_resuspend]     
    CMP  A,00h       
    JNZ  .rwu_timer_1_loop       
                  
.if_rwe_resuspend:
    MOV  A,[rwu_resuspend]         ; if(rwu_resuspend) 
    CMP  A,00h       
    JZ   .radio_poll_return_val                            

.radio_poll_resuspend:
    CALL radio_suspend
    CALL encore_suspend

.radio_poll_return_val:
    MOV  A,[rwu_resuspend]         ; AC = rwu_resuspend;

    RET
    
;-------------- end program listing -----------------------------------------

    INCLUDE "utilities.asm"
    INCLUDE "radio.asm"    
    INCLUDE "bind-auto.asm"
IFDEF MFG_TEST
    INCLUDE "mfgtest.asm"
ENDIF ; MFG_TEST
IFDEF ENCRYPT_DATA_A
    INCLUDE "encrypt_support.asm"
ENDIF

 ; Place USB code in upper 4K block
ORG 1000h                          
    INCLUDE "usbcode.asm"       

ORG 1800h
IFDEF ENCRYPT_DATA_A
    INCLUDE "encrypt.asm"
ENDIF
    INCLUDE "dvk_hardware.asm"
    INCLUDE "rdk_keyboard.asm"
    INCLUDE "rdk_mouse.asm"
IFNDEF PROTOCOL_1_1
    INCLUDE "E2.asm"        
ELSE ; PROTOCOL_1_1
IFDEF ENCRYPT_DATA_A
    INCLUDE "E2.asm"        
ENDIF ; ENCRYPT_DATA_A
ENDIF ; PROTOCOL_1_1