?? receiver.asm
字號(hào):
; ================================================================================================
; PROJECT: SnesHack - A wireless/Wii-enabled SNES and NES controller hack.
; FILENAME: Receiver.asm
; DESCRIPTION: Code for the 16F84A receiver firmware.
; COPYRIGHT: Copyright (c) 2007 Mark Feldman. All Rights Reserved.
; ================================================================================================
list p=16F84A
radix hex
#include "C:\Program Files\Microchip\MPASM Suite\p16f84a.inc"
__config _HS_OSC & _PWRTE_OFF & _WDT_OFF & _CP_OFF
; ================================================================================================
; constants
; ================================================================================================
FALSE equ 0
TRUE equ (!FALSE)
; used when we've lost the wireless signal. this is the number of good packets in a row we need
; to receive before assuming that we're picking up a good signal again.
VALID_SIGNAL_COUNT equ 3
; REC_PORT/REC_BIT reads data from the console, it needs to be a pin that can trigger an interrupt.
; SEND_PORT/SEND_BIT sends data to the console on the same line, it needs to be open collector.
; these pins are both connected directly to the console's data line; if this program is ported
; to another type of PIC then there is no reason why they can't be implemented with a single pin,
; provided that pin supports interrupt-on-falling-edge and is open collector output.
REC_PORT equ PORTB
REC_BIT equ 0
SEND_PORT equ PORTA
SEND_BIT equ 4
; this pin reads incoming data packets from the wireless receiver module.
WIRELESS_PORT equ PORTB
WIRELESS_BIT equ 1
; these pins are used to control the bidirectional red/green LED used to indicate whether or
; not we are receiving a valid wireless signal. they have no other function and can be safely
; removed if needed.
RED_LED_PORT equ PORTB
RED_LED_BIT equ 2
GREEN_LED_PORT equ PORTB
GREEN_LED_BIT equ 3
; this pin is used to generate a test signal that is held high while a wireless packet is being read.
; it has no other function, and can be safely removed if needed.
TEST_PORT equ PORTB
TEST_BIT equ 4
; ================================================================================================
; variables
; ================================================================================================
; variables used by the interrupt handler when receiving console packets
W_TEMP equ 0Ch ; saves W
STATUS_TEMP equ 0Dh ; saves STATUS
RECEIVED_PACKET equ 0Eh ; lets main loop know that a packet was just received
BITS_READ equ 0Fh ; total number of bits read so far
BITS_TO_SEND equ 10h ; total number of bits to send to the console
BIT_NUM equ 11h ; total number of bits in the current byte read/sent
CURRENT_BYTE equ 12h ; curent byte being sent (so we don't trash the value in INDF)
; scratch variables used by the wireless timing routines
TIMER1 equ 14h
TIMER2 equ 15h
; used when we've lost the wireless signal, counts the number of good packets
; in a row that we've received
PACKET_COUNTER equ 16h
; counts the number of interrupts we've had since the last valid wireless packet was received.
; when this number exceeds some critical value (hard-coded to 10) then the receiver assumes
; we've lost the wireless signal.
TIMEOUT_COUNTER equ 17h
; temporary 2-byte buffer used to store button data read in from the wireless packets.
; the data is then copied into the WIRELESS_BUTTONS packet for sending to the console.
WIRELESS_BUTTONS equ 18h
; an 11-byte packet sent to the console containing the button press states. the first
; two bytes of this structure are filled with the data from WIRELESS_BUTTONS after a
; complete, uncorrupted packet has been received from the wireless module. this
; double-buffering helps avoid random button messages being sent to the controller
; when the wireless signal is disconnected mid-packet.
CONSOLE_BUTTONS equ 20h
; a general buffer area used to store packet data sent to and received from the console
PACKET_BUFFER equ 30h
; ================================================================================================
; macros
; ================================================================================================
; sets the open collector output data line low
SEND_0 MACRO
bcf SEND_PORT, SEND_BIT
ENDM
; sets the open collector output data line high
SEND_1 MACRO
bsf SEND_PORT, SEND_BIT
ENDM
; initializes FSR to point to a buffer that will be used to store a packet destined for the console
START_PACKET MACRO BUFFER_ADDR
movlw BUFFER_ADDR
movwf FSR
ENDM
; packs a constant value into the buffer pointed to by FSR and increments the buffer pointer
PACK_CONST MACRO CONST
movlw CONST
movwf INDF
incf FSR,F
ENDM
; finishes off a packet by adding a 1 bit to the end of it and gets the buffer ready to
; send by pointing FSR to the start of it
END_PACKET MACRO BUFFER_ADDR, NUM_BYTES
PACK_CONST 08h
movlw BUFFER_ADDR
movwf FSR
movlw NUM_BYTES*8+1
ENDM
; reads a button state from an incoming wireless packet, sets the appropriate bit in the
; buffer, waits for the next bit to arrive and then checks to make sure that an interrupt
; hasn't occurred (interrupts throw off the timing, so the rest of the wireless packet has
; to be ignored; skipping a packet doesn't matter though, as we receive at least two wireless
; packets for every console packet).
READ_WIRELESS_BUTTON MACRO ADDR, BIT, REVERSE_POLARITY
bcf ADDR, BIT ; clear the buffer bit
#if REVERSE_POLARITY
btfss WIRELESS_PORT, WIRELESS_BIT ; read the wireless port, is it 1?
#else
btfsc WIRELESS_PORT, WIRELESS_BIT ; read the wireless port, is it 0?
#endif
bsf ADDR, BIT ; yes, so set the buffer bit
call wireless_pulse_delay ; wait for the next pulse
ENDM
; turns the LED off
LED_OFF MACRO
bcf RED_LED_PORT, RED_LED_BIT
bcf GREEN_LED_PORT, GREEN_LED_BIT
ENDM
; sets the LED to red to indicate we have power but not a valid wireless signal
LED_RED MACRO
bcf GREEN_LED_PORT, GREEN_LED_BIT
bsf RED_LED_PORT, RED_LED_BIT
ENDM
; sets the LED to green to indicate we have power and a valid wireless signal
LED_GREEN MACRO
bcf RED_LED_PORT, RED_LED_BIT
bsf GREEN_LED_PORT, GREEN_LED_BIT
ENDM
; these macros are used to generate a test signal that goes high when we're reading
; a packet from the wireless port. used solely for testing on an oscilloscope.
TEST_SIGNAL_ON MACRO
bsf TEST_PORT, TEST_BIT
ENDM
TEST_SIGNAL_OFF MACRO
bcf TEST_PORT, TEST_BIT
ENDM
; ================================================================================================
; entry point - jumps to the initialization and main loop
; ================================================================================================
org 0000h
goto initialization
; ================================================================================================
; interrupt handler - there's only one type of interrupt used in this program; it gets
; triggered when the console sends a command. this function reads the
; command, parses it, dispatches control to the appropriate handler,
; and re-enables interrupts before returning. timing is critical in this
; function...we don't have time to jump to a handler, so the handler code
; has to appear here.
; ================================================================================================
org 0004h
; get the next packet from the console (cycle #)
movwf W_TEMP ; ( 2/3) save W register
swapf STATUS, W ; ( 3/4) save STATUS register
movwf STATUS_TEMP ; ( 4/5)
movlw PACKET_BUFFER ; ( 5/6) FSR <- buffer address
movwf FSR ; ( 6/7)
clrf BIT_NUM ; ( 7/8)
read_bit
incf BITS_READ, F ; (8) increment bits read
bcf STATUS, C ; (9) clear carry flag
btfsc REC_PORT, REC_BIT ; (10) is this bit a 1?
bsf STATUS, C ; (11) if yes then set carry bit
rlf INDF, F ; (12) rotate carry bit into the current
byte
incf BIT_NUM, F ; (13) increment current bit number
btfsc BIT_NUM, 3 ; (14) have we set 8 bits yet?
incf FSR, F ; (15) if yes then advance the buffer ptr
btfsc BIT_NUM, 3 ; (16) have we set 8 bits yet?
clrf BIT_NUM ; (17) if yes then reset the current bit number to 0
nop ; (18)
nop ; (19)
btfss REC_PORT, REC_BIT ; (20) has the data line returned to 0?
goto start_bit ; (21) if yes then go read another bit
btfss REC_PORT, REC_BIT ; (22) that check is too early, this one is more likely...
goto start_bit ; (23)
btfss REC_PORT, REC_BIT ; (22) and sometimes it can appear here...
goto start_bit ; (23)
btfss REC_PORT, REC_BIT ; (24) last chance...
goto start_bit ; (25)
decf BITS_READ, F ; (34) ok, we've timed out. knock off the last bit
goto finished_packet ; (35) (which should be a 1) and we're done.
start_bit
movfw BITS_READ ; (3) safety check
addlw -22h ; (4) have we read 34 bits?
btfss STATUS, Z ; (5) if yes then don't read any more
goto read_bit ; (6) go read in the next bit
finished_packet
call check_4003XXh ; request button states?
iorlw 0
btfss STATUS, Z
goto end_interrupt
call check_00h ; request id/status?
iorlw 0
btfss STATUS, Z
goto end_interrupt
call check_41h ; request origins?
iorlw 0
btfss STATUS, Z
goto end_interrupt
end_interrupt
bsf RECEIVED_PACKET, 0 ; signal that we've just received a console packet
clrf BITS_READ ; we dont' have time to do this in the interrupt initialization
swapf STATUS_TEMP, W ; restore STATUS
movwf STATUS
swapf W_TEMP, F ; restore W
swapf W_TEMP, W
bcf INTCON, INTF ; clear the pin interrupt flag
retfie ; return from interrupt
; ================================================================================================
; check_4003XXh - checks to see if we've received a "request button states" command,
; if we have then the button buffer is sent to the console.
; ================================================================================================
check_4003XXh
movfw BITS_READ ; must be a 24-bit packet
sublw 18h
btfss STATUS, Z
retlw 0
movfw PACKET_BUFFER
sublw 40h
btfss STATUS, Z
retlw 0
movfw PACKET_BUFFER+1 ; second byte must be 03h
sublw 03h
btfss STATUS, Z
retlw 0
movlw CONSOLE_BUTTONS ; send the button data packet to the console
movwf FSR
movlw 41h ; = 65 bits
call send_packet
incf TIMEOUT_COUNTER ; increment the time-out counter
retlw 1
; ================================================================================================
; check_00h - checks to see if we've received a "request id/status" command,
; if we have then send the standard controller id word and status byte are sent
; to the console
; ================================================================================================
check_00h
movfw BITS_READ ; must be an 8-bit packet
sublw 8h
btfss STATUS, Z
retlw 0
movfw PACKET_BUFFER ; first byte must be 00h
sublw 00h
btfss STATUS, Z
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -