PDA

View Full Version : PS2 Mouse Interpreter



Art
- 3rd December 2015, 11:51
Hi Guys :)
I’ve been playing with this PS2 Mouse to Amiga mouse port translator,
so I thought I might as well wrap it in BASIC to compile it, and it can be used if needed.

It’s essentially still assembler in the manner DT’s Elapsed Timer code is.
You can still access variables from PBP code.
It receives packets from the mouse, converts to pulses for vintage Commodore Amiga computers.
The PS2 (3 byte packets) are easy enough to interpret, but I have left the Amiga output code as well.
The Amiga expects mouse buttons to be individual pins, so it physically converts back to individual button signals.

http://img.photobucket.com/albums/v186/ArtArt/Mouse_Mod.bmp_zpsduc318ut.png

There are some important notes to go with this:
1. The schematic is correct other than portB.2 is used for hardware serial out.
2. The Amiga mouse port connector need not be connected for use with PBP, other than the circuit needs power of course.
3. The PS2 main routine should become a subroutine which will only be practical in a real time cyclic program.
You can’t neglect to repeditively call the code, or the mouse will not be responsive.
4. Timing is important for the PS2 reading routine. I have not even tried a 4MHz crystal.
5. Configuration for the demo I will show later are: WDT OFF, BOD OFF, XT Clock, Powerup delay ENABLE.
6. Decoded PS2 serial packets are re-encoded to 2400 8N1 and passed out the hardware serial port.
7. The middle button is disabled if present. Instead, while the middle button is held, the left & right
buttons provide two additional outputs.
8. Blocking HPWM (multiple bytes send in one command) loses mouse responsiveness.
It’s just a cool way to demonstrate, and is easy to set up and look at with a serial terminal program
and real mouse port for viewing both outputs on one screen at the same time!

Enjoy :D

Cheers, Art.

Art
- 3rd December 2015, 12:03
Code...

YouTube video demo to follow shortly, where the code was compiled with PBP.



'
'************************************************* **********************************
'* *
'* PS2 Mouse Interpreter *
'* *
'* Microchip Pic 16F628 @ 3.57MHz *
'* *
'************************************************* **********************************
'
'
DEFINE OSC 3 '
DEFINE NO_CLRWDT ' watchdog is cleared manually
'
DEFINE HSER_RCSTA 90h ' enable hardware serial receiver
DEFINE HSER_TXSTA 20h ' enable hardware serial transmitter (24h)
DEFINE HSER_BAUD 2400 '

'
' -------------------------------------
' PS/2 Mouse to Amiga Mouse Converter
' v1.0 (30-Jun-2001)
‘ ported to 16F628A Brek Martin 2015.
' -------------------------------------

' Copyright 2001 Nevenko Baricevic


' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.

' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.

' You should have received a copy of the GNU General Public License
' along with this program. If not, see <http://www.gnu.org/licenses/>.


‘ *** Pic Basic / Pro users don’t declare any variables before these
‘ *** to ensure the assembler variables are all placed in Bank 0.

' ---------- registers definition -----------

bytebuf var byte' ; byte to receive or send
parity var byte' ; parity bit is held here
parcnt var byte' ; counter for calculating parity
roller var byte' ; help for 8 data bits to byte conversion
pack1 var byte' ; 1st byte of mouse data packet
pack2 var byte' ; 2nd byte of mouse data packet
pack3 var byte' ; 3rd byte of mouse data packet
xrot var byte' ; rotation byte for H and HQ
yrot var byte' ; rotation byte for V and VQ
delcnt var byte' ; delay counter
serbufa var byte' ; serial output buffer
serbufb var byte
serbufc var byte

‘ --------- main routine -----------

main:
@ movlw 0x07
@ movwf CMCON
@ bsf STATUS,RP0 ; page 1
@ bcf TRISA,3 ; new mouse output
@ bsf TRISA,2 ; port A, bit 2 is input
@ bsf TRISA,1 ; port A, bit 1 is input
@ bcf TRISA,0 ; port A, bit 0 is output to LED
@ clrf TRISB ; port B is all outputs
@ bcf STATUS,RP0 ; page 0
@ bsf PORTA,0
@ movlw 0xff ; was ff
@ movwf PORTB ; port B all pins to 1
@ movlw 0x2d ; put b'00101101' to xrot and yrot
@ movwf _xrot
@ movwf _yrot
@ call _REC ; receive byte from mouse
@ call _INHIB ; pull CLK low to inhibit furhter sending
@ movf _bytebuf,W
@ xorlw 0xaa ; if it's $AA mouse self test passed
@ btfss STATUS,Z
@ goto _IERROR
@ call _REL ; release CLK (allow mouse to send)
@ call _REC ; receive byte from mouse
@ call _INHIB
@ movf _bytebuf,W
@ xorlw 0x00 ; mouse ID code should be $00
@ btfss STATUS,Z
@ goto _IERROR
@ movlw 0xf4 ; "Enable Data Reporting" command to mouse
@ movwf _bytebuf
@ call _NEWPAR ; get parity for $F4
@ call _REL
@ call _DEL200
@ call _SEND ; send command to mouse
@ call _REC ; receive acknowledge ($FA) from mouse)
@ call _INHIB
@ movf _bytebuf,W
@ xorlw 0xfa
@ btfss STATUS,Z
@ goto _IERROR
@ call _REL
CHK:
@ call _REC ; receive byte1 from mouse packet
@ call _INHIB
@ movf _bytebuf,W
@ movwf _pack1
@ call _REL
@ call _REC ; receive byte2 from mouse packet
@ call _INHIB
@ movf _bytebuf,W
@ movwf _pack2
@ call _REL
@ call _REC ; receive byte3 from mouse packet
@ call _INHIB
@ movf _bytebuf,W
@ movwf _pack3
@ call _CONV
@ call _REL
@ goto _CHK ; receive another packet

' --------------------------------------------------------

PERROR:
@ nop
RERROR:
@ nop
IERROR:
@ nop
E_LOOP:
@ goto _E_LOOP

' --------------------------------------------------------

DEL10:
@ nop ; delay 10us
@ return
DEL200:
@ movlw 0x32 ; delay 200us
@ movwf _delcnt
DEL2:
@ decfsz _delcnt
@ goto _DEL2
@ return

' --------- byte receiving subroutine -------------

REC:
@ btfsc PORTA,2 ; wait clock (start bit)
@ goto _REC
RL1:
@ btfss PORTA,2
@ goto _RL1
@ call _RECBIT ; receive 8 data bits
@ call _RECBIT
@ call _RECBIT
@ call _RECBIT
@ call _RECBIT
@ call _RECBIT
@ call _RECBIT
@ call _RECBIT
RL2:
@ btfsc PORTA,2 ; receive parity bit
@ goto _RL2
@ btfsc PORTA,1
@ goto _RL3
@ bcf _parity,0
RL4:
@ btfss PORTA,2 ; receive stop bit
@ goto _RL4
STP:
@ btfsc PORTA,2
@ goto _STP
@ btfss PORTA,1
@ goto _RERROR
RL8:
@ btfss PORTA,2
@ goto _RL8
@ return
RL3:
@ bsf _parity,0
@ goto _RL4

' ---------- bit receiving subroutine ------------

RECBIT:
@ btfsc PORTA,2
@ goto _RECBIT
@ movf PORTA,W
@ movwf _roller
@ rrf _roller
@ rrf _roller
@ rrf _bytebuf
RL5:
@ btfss PORTA,2
@ goto _RL5
@ return

' ---------- subroutines -----------------

INHIB:
@ call _CLKLO ; inhibit mouse sending (CLK low)
@ call _DEL200
@ return
REL:
@ call _CLKHI ; allow mouse to send data
@ return
CLKLO:
@ bsf STATUS,RP0 ; CLK low
@ bcf TRISA,2
@ bcf STATUS,RP0
@ bcf PORTA,2
@ return
CLKHI:
@ bsf STATUS,RP0 ; CLK high
@ bsf TRISA,2
@ bcf STATUS,RP0
@ return
DATLO:
@ bsf STATUS,RP0 ; DATA low
@ bcf TRISA,1
@ bcf STATUS,RP0
@ bcf PORTA,1
@ return
DATHI:
@ bsf STATUS,RP0 ; DATA high
@ bsf TRISA,1
@ bcf STATUS,RP0
@ return

' ------------- send to mouse --------------

SEND:
@ call _INHIB ; CLK low
@ call _DEL10
@ call _DATLO ; DATA low
@ call _DEL10
@ call _REL ; CLK high
SL1:
@ btfsc PORTA,2 ; wait for CLK
@ goto _SL1
@ call _SNDBIT ; send 8 data bits
SS1:
@ btfss PORTA,2
@ goto _SS1
SS2:
@ btfsc PORTA,2
@ goto _SS2
@ call _SNDBIT
SS3:
@ btfss PORTA,2
@ goto _SS3
SS4:
@ btfsc PORTA,2
@ goto _SS4
@ call _SNDBIT
SS5:
@ btfss PORTA,2
@ goto _SS5
SS6:
@ btfsc PORTA,2
@ goto _SS6
@ call _SNDBIT
SS7:
@ btfss PORTA,2
@ goto _SS7
SS8:
@ btfsc PORTA,2
@ goto _SS8
@ call _SNDBIT
SS9:
@ btfss PORTA,2
@ goto _SS9
SS10:
@ btfsc PORTA,2
@ goto _SS10
@ call _SNDBIT
SS11:
@ btfss PORTA,2
@ goto _SS11
SS12:
@ btfsc PORTA,2
@ goto _SS12
@ call _SNDBIT
SS13:
@ btfss PORTA,2
@ goto _SS13
SS14:
@ btfsc PORTA,2
@ goto _SS14
@ call _SNDBIT
SS15:
@ btfss PORTA,2
@ goto _SS15
SS16:
@ btfsc PORTA,2
@ goto _SS16
@ call _SNDPAR ; send parity bit
SS17:
@ btfss PORTA,2
@ goto _SS17
SS18:
@ btfsc PORTA,2
@ goto _SS18
@ call _DATHI ; release bus
SL4:
@ btfss PORTA,2
@ goto _SL4
SL5:
@ btfsc PORTA,2
@ goto _SL5
@ btfsc PORTA,1
@ goto _RERROR
SL7:
@ btfss PORTA,2
@ goto _SL7
SL8:
@ btfss PORTA,1
@ goto _SL8
@ return

' -------------- subroutines --------------

SNDBIT:
@ rrf _bytebuf ; send data bit
@ btfsc STATUS,C
@ goto _DHIGH
@ call _DATLO
SL2:
@ return
DHIGH:
@ call _DATHI
@ goto _SL2
SNDPAR:
@ btfsc _parity,0 ; send parity bit
@ goto _PHIGH
@ call _DATLO
SP1:
@ return
PHIGH:
@ call _DATHI
@ goto _SP1
CLCPAR:
@ movlw 0 ; calculate parity bit
@ movwf _parcnt
@ btfsc _bytebuf,0
@ incf _parcnt
@ btfsc _bytebuf,1
@ incf _parcnt
@ btfsc _bytebuf,2
@ incf _parcnt
@ btfsc _bytebuf,3
@ incf _parcnt
@ btfsc _bytebuf,4
@ incf _parcnt
@ btfsc _bytebuf,5
@ incf _parcnt
@ btfsc _bytebuf,6
@ incf _parcnt
@ btfsc _bytebuf,7
@ incf _parcnt
@ return
NEWPAR:
@ call _CLCPAR
@ btfss _parcnt,0
@ goto _PARONE
@ bcf _parity,0
@ return
PARONE:
@ bsf _parity,0
@ return
CHKPAR:
@ call _CLCPAR ; check parity
@ movf _parcnt,W
@ andlw 0x01
@ movwf _parcnt
@ movf _parity,W
@ xorwf _parcnt
@ btfss STATUS,Z
@ return
@ call _PERROR
@ return

' --------------- conversion to Amiga format --------------

CONV:
@ btfsc _pack1,0 ; left button
@ goto _LPRESS
@ bsf PORTB,6
@ bsf PORTB,7
CON1:
@ btfsc _pack1,1 ; right button
@ goto _RPRESS
@ bsf PORTB,0
@ bsf PORTA,0
CON2:
@ btfsc _pack1,2 ; middle button
@ goto _MPRESS
@ bsf PORTB,1

MOVE:
‘ Pic BASIC / Pro code to send serial here
serbufa = pack1'
serbufb = pack2'
serbufc = pack3'
HSEROUT [" : ",BIN8 serbufa," ",BIN8 serbufb," ",BIN8 serbufc,13,10]


@ movf _pack2,W ; movement conversion
@ andlw 0xff
@ btfss STATUS,Z
@ call _MOVEX
@ movf _pack3,W
@ andlw 0xff
@ btfss STATUS,Z
@ call _MOVEY
@ return


LPRESS:
@ bcf PORTB,6
@ btfsc _pack1,2
@ bcf PORTB,7
@ goto _CON1

RPRESS:
@ bcf PORTB,0
@ btfsc _pack1,2
@ bcf PORTA,0
@ goto _CON2


MPRESS:
@ bcf PORTB,1
@ goto _MOVE
MOVEX:
@ btfss _pack1,4
@ goto _LEFT
@ goto _RIGHT
MOVEY:
@ btfss _pack1,5
@ goto _DOWN
@ goto _UP
LEFT:
@ call _DEL200 ; send H and HQ for left movement
@ rlf _xrot
@ btfss STATUS,C
@ goto _LH0
@ goto _LH1
LH0:
@ bcf _xrot,0
@ bcf PORTB,4
@ goto _LHQ
LH1:
@ bsf _xrot,0
@ bsf PORTB,4
LHQ:
@ rlf _xrot
@ btfss STATUS,C
@ goto _LHQ0
@ goto _LHQ1
LHQ0:
@ bcf _xrot,0
@ bcf PORTA,3
@ goto _LONE
LHQ1:
@ bsf _xrot,0
@ bsf PORTA,3
LONE:
@ decfsz _pack2
@ goto _LEFT
@ return
RIGHT:
@ call _DEL200 ; send H and HQ for right movement
@ rrf _xrot
@ btfss STATUS,C
@ goto _RHQ0
@ goto _RHQ1
RHQ0:
@ bcf _xrot,7
@ bcf PORTA,3
@ goto _RH
RHQ1:
@ bsf _xrot,7
@ bsf PORTA,3
RH:
@ rrf _xrot
@ btfss STATUS,C
@ goto _RH0
@ goto _RH1
RH0:
@ bcf _xrot,7
@ bcf PORTB,4
@ goto _RONE
RH1:
@ bsf _xrot,7
@ bsf PORTB,4
RONE:
@ incfsz _pack2
@ goto _RIGHT
@ return
UP:
@ call _DEL200 ; send V and VQ for up movement
@ rlf _yrot
@ btfss STATUS,C
@ goto _UV0
@ goto _UV1
UV0:
@ bcf _yrot,0
@ bcf PORTB,5
@ goto _UVQ
UV1:
@ bsf _yrot,0
@ bsf PORTB,5
UVQ:
@ rlf _yrot
@ btfss STATUS,C
@ goto _UVQ0
@ goto _UVQ1
UVQ0:
@ bcf _yrot,0
@ bcf PORTB,3
@ goto _UONE
UVQ1:
@ bsf _yrot,0
@ bsf PORTB,3
UONE:
@ incfsz _pack3
@ goto _UP
@ return
DOWN:
@ call _DEL200 ; send V and VQ for down movement
@ rrf _yrot
@ btfss STATUS,C
@ goto _DVQ0
@ goto _DVQ1
DVQ0:
@ bcf _yrot,7
@ bcf PORTB,3
@ goto _DV
DVQ1:
@ bsf _yrot,7
@ bsf PORTB,3
DV:
@ rrf _yrot
@ btfss STATUS,C
@ goto _DV0
@ goto _DV1
DV0:
@ bcf _yrot,7
@ bcf PORTB,5
@ goto _DONE
DV1:
@ bsf _yrot,7
@ bsf PORTB,5
DONE:
@ decfsz _pack3
@ goto _DOWN
@ return
@ end
' --------------------------------------------------------


Cheers, Art.

Art
- 3rd December 2015, 16:28
Here is the YouTube example of it running (this was compiled within PBP).
It’s slow to respond because the pic program isn’t looking at the mouse while sending
31 or so serial bytes in a row at 2400 baud for every mouse movement.
Without this it’s very responsive, which can be seen in previous videos.

https://www.youtube.com/watch?v=EfCIKz3B0lk