05 March 2017, 08:16 | #1 |
Registered User
Join Date: Dec 2013
Location: Auckland
Posts: 3,547
|
Detect CD32 pad connected in Blitz?
Is there an easy way to detect whether a CD32 pad is connected? (without using lowlevel.library etc which may not be present)
|
05 March 2017, 11:17 | #2 |
Unregistered User
Join Date: Nov 2005
Location: Tasmania
Age: 42
Posts: 893
|
I can't think of any way to automatically detect one, but you could manually detect one by requesting the user press one of the buttons not present on a standard joystick.
For example to prompt the user to press red or green. If red button is detected then it's a standard controller, if green then it's a cd32 pad. |
05 March 2017, 23:58 | #3 |
Registered User
Join Date: Jun 2009
Location: Dublin, then Glasgow
Posts: 6,379
|
You can do it by peeking and poking the if you're happy to do that? When being read, the CD32 sends a bitstream, with the first 7 bits representing the status of all the buttons other than the D-pad. If you keep reading though, the 8th bit is always 1 and the 9th bit is always 0. If you can detect those bits, you can be sure that it's a CD32 pad connected as no combination of button bashing can change those two bits.
I don't have the code to hand at the moment, but that's how I did the detection in a controller tester I wrote. When I'm at that machine again, I can dig up the code for you if that helps? |
19 March 2017, 03:50 | #4 | |
Registered User
Join Date: Dec 2013
Location: Auckland
Posts: 3,547
|
Quote:
|
|
19 March 2017, 14:14 | #5 | |
Registered User
Join Date: Jun 2009
Location: Dublin, then Glasgow
Posts: 6,379
|
Quote:
The potgo_ functions are from the AmiBlitz3 potgo.include file, but the code in them is pretty simple and is just a wrapper for the OS calls. You can see it in the AmiBlitz3 code repository and download it to use in Blitz 2. It's probably not even strictly necessary if you're shutting down the OS - you could just bang the hardware directly without allocating the resource, but if anything else uses the port you'd get strange things happening. Code:
; Setup code near the start of your program. debug.b=True ; or false... If potgo_Open{}=False Then NPrint "Can't open potgo.resource!":End mask.w = %1111111100000001 allocmask.w = potgo_AllocPotBits{mask} If debug Then NPrint "Allocating...",Right$(Bin$(mask),16) If debug Then NPrint "and got......",Right$(Bin$(allocmask),16) If allocmask & %0000111100000000 If debug Then NPrint "Allocated port 0 bits successfully" Else If debug Then NPrint "Unable to allocate port 0 bits!" End If If allocmask & %1111000000000000 If debug Then NPrint "Allocated port 1 bits successfully" Else If debug Then NPrint "Unable to allocate port 1 bits!" End If VWait 5 ; Let things settle down a little, you might not need this ; ... ; Other initialisation code here ; ... Function.w cd32buttons{port.b} SHARED allocmask, debug result.w=0 ; Define the pins needed for If port=1 potgoon.w =%0010000000000000 potgooff.w=%0011000000000000 firepin.b=%10000000 serbit.w=14 Else potgoon.w =%0000001000000000 potgooff.w=%0000001100000000 firepin.b=%01000000 serbit.w=10 End If Disable_ ; The pot pins get messed with during interrupts, so they need to be disabled Poke.b $BFE201,(Peek.b($BFE201)|firepin) ; Joystick fire to output Poke.b $BFE001,(Peek.b($BFE001) & NOT firepin) ; Output low savepotgo.w=Peek.w($DFF016) ; So we can restore it later Poke.w $DFF034,potgoon ; Set the relevant pin 5 to enable CD32 mode on the controller ; Ugly delay loop to give the pot lines time to stabilise For i.w=1 To 5 mybytes.w=Peek.w($DFF016) Next i If port=1 For i.w=14 To 6 Step -1 Poke.b $BFE001,(Peek.b($BFE001)|firepin) ; Output high bytes.w=Peek.w($DFF016) Poke.b $BFE001,(Peek.b($BFE001) & NOT firepin) ; Output low result=result | ((bytes & (1 LSL 14)) LSR i) ; %0100000000000000 Next i Else ; Port 0 For i.w=10 To 2 Step -1 Poke.b $BFE001,(Peek.b($BFE001)|firepin) ; Output high bytes.w=Peek.w($DFF016) Poke.b $BFE001,(Peek.b($BFE001) & NOT firepin) ; Output low result=result | ((bytes & (1 LSL 10)) LSR i) ; %0000010000000000 Next i End If ; Put things back the way they were so you don't upset other functions Poke.w $DFF034,potgooff Poke.b $BFE001,(Peek.b($BFE001)|firepin) ; Output high Poke.b $BFE201,(Peek.b($BFE201) & NOT firepin) ; Joystick fire to input Poke.w $DFF034,savepotgo ; Another ugly delay loop For i.w=1 To 50 mybytes.w=Peek.w($DFF016) Next i Enable_ ; Turn interrupts back on Function Return result End Function ; ... ; More code here ; ... ; Detect controller on port 1 game.w=cd32buttons{1} If (game & %10000000) AND (game & %100000000)=False NPrint "CD32 Controller Found on Port 1! " Else NPrint "Standard Controller on Port 1!" End If ; ... ; And more code... ; ... ; Free the potgo resource when you're finished potgo_FreePotBits{allocmask} I hope it makes sense, but let me know if you need a hand with it. Edit: Added extra code at the end to demonstrate the actual detection. Last edited by Daedalus; 19 March 2017 at 14:23. |
|
19 March 2017, 19:50 | #6 |
Registered User
Join Date: Oct 2008
Location: Finland
Posts: 643
|
I started experimenting with inline assembly in Blitz Basic 2. Here is an alternative joystick / CD32 gamepad routine written in assembly. You can use it like a normal function, usage example included in code. This function will also read the joystick directions so it can replace all joyx joyy joyb calls, I have no idea if this is any faster though, I haven't tested.
EDIT1: There is a bug somewhere in this routine that causes problems on hardware, port 1 is working fine but not port 2. So I advice you not to use this until I find the bug... Can anybody see the problem? Probably a wrong address or something. EDIT2: Ok, I found the bug. I had a MOVEQ instead of a MOVE.w instruction and another interesting problem was that when reading both ports, the second port would always return a pressed blue button status. This is because the capacitors used for pins on the joystick ports are so big so it takes up to 300µs for the pin mode change to take effect. Instead of resetting the pins after each port read, I created a macro that resets both ports after reading them, so this macro needs to be called once after reading one or both joystick ports. The code is now updated, I have tested it on my stock A500 and A1200 with cd32 pad + mouse, joystick + mouse, cd32 pad + joystick and cd32 pad + cd32 pad. EDIT3: Edited the code one more time, POTGO value is now restored to it's previous state after reading joystick port(s). I made a JoyTester program, you can download it below if interested (bootable adf image, tested on A500 and A1200, source included): http://www.gamephase.net/files/JoyTesterv10.zip EDIT4: Did some adjustments to the code. I removed the ReadPotgo and RestorePotgo macros (POTGO is "restored" with Poke at end of routine). Commented UNLK a4 at the start of the routine and replaced RTS at end of routine with AsmExit (talked about below). Code:
; CD32 GAMEPAD ROUTINE FOR BLITZ BASIC 2 #JOY_UP = 8 #JOY_DOWN = 4 #JOY_LEFT = 2 #JOY_RIGHT = 1 #JOY_BUTTON1 = 2048 #JOY_BUTTON2 = 4096 #CD32_RED = 2048 #CD32_BLUE = 4096 #CD32_GREEN = 512 #CD32_YELLOW = 1024 #CD32_LTRIGGER = 128 #CD32_RTRIGGER = 256 #CD32_PLAY = 64 #CD32_GAMEPAD = 16 DEFTYPE .w Function.w ReadJoy{n} ; UNLK a4 ; Must be at the top of an assembly procedure (a4 is used as local variable base). EDIT: Seems that this is not necessary after all. BTST #0,d0 ; Test if d0=1 by testing bit 0 (Z=0 if bit 0 is 1) BNE.b joy1 ; Branch to joy1 if Z=0 ; --------------------------------------------------- ; Joy0 MOVEQ #6,d3 ; Button 1 bit (bit 6 (/FIR0) at address $BFE001 which is CIAA PRA) ; also bit 6 of $BFE201 which is CIAA DDRA (data direction of joy0 pin 6) MOVE.w #10,d4 ; Button 2 bit (joy0 pin 9, POTGOR) MOVE.w #$f600,d5 ; Used to set POTGO (joy0 pin 5 output low) was f600 MOVEA.l #$dff00a,a0 ; Joystick 0 data address (joy0dat) BRA directions ; --------------------------------------------------- joy1: MOVEQ #7,d3 ; Button 1 bit (bit 7 (/FIR1) at address $BFE001 which is CIAA PRA) ; also bit 7 of $BFE201 which is CIAA DDRA (data direction of joy1 pin 6) MOVE.w #14,d4 ; Button 2 bit for Joy1 (joy1 pin 9, POTGOR) MOVE.w #$6f00,d5 ; Used to set POTGO (joy1 pin 5 output low) was 6f00 MOVEA.l #$dff00c,a0 ; Joystick 1 data address (joy1dat) MOVEQ #0,d0 ; Set d0 to 0 MOVE.w #0,d6 ; Set d6 to 0 ; --------------------------------------------------- directions: MOVE.w (a0),d0 ; Read joy0dat or joy1dat to d0 MOVE.w d0,d1 ; Copy d0 to d1 LSR.w #1,d1 ; Shift d1 one bit to the right EOR.w d0,d1 ; Exclusive OR d0 and d1 and store in d1 BTST #8,d1 ; Check joystick up (test bit 8 and set Z to 1 if bit is 0) SNE d6 ; Set first byte of d7 to %11111111 if Z bit is set ADD.w d6,d6 ; Add d7 to itself BTST #0,d1 ; Check joystick down (test bit 0... read above) SNE d6 ADD.w d6,d6 BTST #9,d0 ; Check joystick left (test bit 9... read above) SNE d6 ADD.w d6,d6 BTST #1,d0 ; Check joystick right (test bit 1... read above) SNE d6 ADD.w d6,d6 LSR.w #8,d6 ; Shift d6 8 steps to the right (logical) ANDI.b #%1111,d6 ; Save only bits 0-3 of d6 ; --------------------------------------------------- ; Normal buttons BTST d3,$bfe001 ; Check button 1 bit at CIAA PRA BNE.b button2 ; Branch to button2 if button1 is not pressed BSET #11,d6 ; If button1 is pressed, set bit 13 of d6 button2: BTST d4,$dff016 ; Check button 2 bit at POTGOR (aka. POTINP) BNE.b cd32 ; Branch to cd32 if button2 is not pressed BSET #12,d6 ; If button2 is pressed, set bit 13 of d6 ; --------------------------------------------------- ; CD32 buttons cd32: BSET d3,$bfe201 ; Set ciaa ddr port a high (configure /fire0 as output) 6=joyport0, 7=joyport1 BCLR d3,$bfe001 ; Set /fire0 low MOVE.w d5,$dff034 ; Set pin 5 as output low (write to potgo) MOVEQ #0,d0 ; Set d0 to 0 MOVEQ #8,d1 ; Set d1 to 9, this will be used for the button read loop BRA in ; jump to in loop: TST.b $bfe001 ; Read CIAA PRA multiple times to create a delay so a reliable button status TST.b $bfe001 ; can be read. in: TST.b $bfe001 TST.b $bfe001 TST.b $bfe001 TST.b $bfe001 TST.b $bfe001 TST.b $bfe001 MOVE.w $dff016,d2 ; Read POTGOR to d2 BSET d3,$bfe001 ; Set /fire0 high (clock pulse for shift register) BCLR d3,$bfe001 ; Set /fire0 low BTST d4,d2 ; Test bit 10 or 14 of POTGOR (pin 9, CD32 gamepad button data) BNE.b readnext ; Branch to readnext if pin 9 is 1 (0 means button is pressed) BSET d1,d0 ; Set bit d1 of d0 if button is pressed readnext: DBF d1,loop ; Decrement d1 and jump to loop if d1 > 0 BSET d3,$bfe001 ; Set button1 high BCLR d3,$bfe201 ; Set ciaa ddr port as input MOVE.b d0,d1 ; Copy first byte of d0 to d1 ANDI.b #%11,d1 ; Save the lowest two bits of d1 CMPI.b #%01,d1 ; Check if lowest bits equal %01 (cd32 gamepad signature) BEQ.b cd32ok ; If cd32 signature is ok, branch to cd32ok MOVE.b #0,d0 ; Clear low byte of d0 since cd32 button readings are wrong cd32ok: LSL.w #4,d0 ; Shift d0 four steps to the left OR.l d6,d0 ; Combine d0 with d6 by using bitwise OR AsmExit End Function BLITZ ; Go into blitz mode BitMap 0, 320, DispHeight, 5 ; Create a bitmap PalRGB 0,1,15,15,15 BitMapOutput 0 Slice 0,42,5 Use Palette 0 Show 0, 0, 0 joystick = 0 Repeat VWait ; Read joy1 (0 for joy0) joystick = ReadJoy{1} ; Reset POTGO register, call this after reading ports 0 and 1 ; So if reading both ports, do that above and then call this once Poke.w $dff034,$ff00 ; Print joystick variable Locate 0,0 : Print Bin$(joystick) ; CD32 gamepad check Locate 0,1 If joystick & #CD32_GAMEPAD Print "CD32 Gamepad Connected! " Else Print "Normal joystick connected!" EndIf ; Direction check Locate 0,2 If joystick & #JOY_UP Print "Going up!" Else Print " " EndIf ; Button check Locate 0,3 If joystick & #CD32_PLAY Print "Play is pressed!" Else Print " " EndIf Until Joyb(0)>0 Last edited by MickGyver; 09 June 2018 at 09:10. Reason: Bug fixes and changes to the code, read post |
06 June 2018, 06:48 | #7 |
Registered User
Join Date: Dec 2013
Location: Auckland
Posts: 3,547
|
Damn, very nice. I missed your message @MickGyver and ended up adapting the code by JOTD, Wepl, Girv and ASM that's in the Ruff N Tumble CD32 slave.
This -seems- to work though it's not extensively tested, and it JUST does a CD32 pad detection rather than a full read. Edit: Whoops.. I can see at least a couple of potential issues here, ignore the code below until it's fixed. Edit2: Ok! Code should be more solid now. IsCD32Pad returns > 0 if it is, and 0 if it isn't. Code:
;Constants #IsCD32Pad_ciapra=$BFE001-$BFE001 #IsCD32Pad_ciaddra=$BFE201-$BFE001 #IsCD32Pad_potgo=$DFF034-$DFF000 #IsCD32Pad_potinp=$DFF016-$DFF000 #IsCD32Pad_CIAB_GAMEPORT0=$6 #IsCD32Pad_CIAB_GAMEPORT1=$7 #IsCD32Pad_intreq=$DFF09C-$DFF000 #IsCD32Pad_intreqr=$DFF01E-$DFF000 Function.b IsCD32Pad{port.b} move.b D0,D1 bsr detect ; ignore first read bsr wvbl move.b D1,D0 bsr detect AsmExit ; wait for VBL .wvbl lea $DFF000,a0 move.w #$7FFF,IsCD32Pad_intreq(a0) .waitvbl move.w IsCD32Pad_intreqr(a0),d0 btst #5,d0 beq waitvbl rts ; detection routine .detect movem.l d1-d6/a0-a6,-(a7) tst.l d0 bne.b port1 moveq #IsCD32Pad_CIAB_GAMEPORT0,d3 ; red button ( port 0 ) moveq #10,d4 ; blue button ( port 0 ) move.w #$f600,d5 ; for IsCD32Pad_potgo port 0 bra buttons .port1 moveq #IsCD32Pad_CIAB_GAMEPORT1,d3 ; red button ( port 1 ) moveq #14,d4 ; blue button ( port 1 ) move.w #$6f00,d5 ; for IsCD32Pad_potgo port 1 .buttons lea $DFF000,a0 lea $BFE001,a1 bset d3,IsCD32Pad_ciaddra(a1) ;set bit to out at IsCD32Pad_ciapra bclr d3,IsCD32Pad_ciapra(a1) ;clr bit to in at IsCD32Pad_ciapra move.w d5,IsCD32Pad_potgo(a0) moveq #0,d0 moveq #10-1,d1 ; read 9 times instead of 7. Only 2 last reads interest us bra gamecont4 .gamecont3 tst.b IsCD32Pad_ciapra(a1) tst.b IsCD32Pad_ciapra(a1) .gamecont4 tst.b IsCD32Pad_ciapra(a1) ; wepl timing fix tst.b IsCD32Pad_ciapra(a1) tst.b IsCD32Pad_ciapra(a1) tst.b IsCD32Pad_ciapra(a1) tst.b IsCD32Pad_ciapra(a1) tst.b IsCD32Pad_ciapra(a1) move.w IsCD32Pad_potinp(a0),d2 bset d3,IsCD32Pad_ciapra(a1) bclr d3,IsCD32Pad_ciapra(a1) btst d4,d2 bne.b gamecont5 bset d1,d0 .gamecont5 dbf d1,gamecont3 bclr d3,IsCD32Pad_ciaddra(a1) ;set bit to in at IsCD32Pad_ciapra move.w #$ff00,IsCD32Pad_potgo(a0) ;changed from ffff, according to robinsonb5@eab or.b #$C0,IsCD32Pad_ciapra(a1) ;reset port direction ; test only last bits and.w #03,D0 movem.l (a7)+,d1-d6/a0-a6 rts End Function NPrint IsCD32Pad{0} NPrint IsCD32Pad{1} End Last edited by earok; 06 June 2018 at 11:40. |
06 June 2018, 08:20 | #8 | |
Registered User
Join Date: Oct 2008
Location: Finland
Posts: 643
|
Quote:
|
|
06 June 2018, 11:41 | #9 | |
Registered User
Join Date: Dec 2013
Location: Auckland
Posts: 3,547
|
Quote:
|
|
08 June 2018, 13:37 | #10 |
Registered User
Join Date: Sep 2007
Location: Stockholm
Posts: 4,356
|
|
08 June 2018, 14:06 | #11 |
Registered User
Join Date: Oct 2008
Location: Finland
Posts: 643
|
From page 63 in the BB2.1 user guide. Looking at the example on that page now, that command is not there, so maybe it's not needed at all? There are all kinds of errors in the BB documentation so...
|
08 June 2018, 16:45 | #12 |
Registered User
Join Date: Sep 2007
Location: Stockholm
Posts: 4,356
|
That's very odd, it's not in the Amigaguide version of the 2.1 manual, nor is it part of the other PDF version of the Blitz manual.
|
08 June 2018, 17:26 | #13 |
Registered User
Join Date: Oct 2008
Location: Finland
Posts: 643
|
|
08 June 2018, 17:58 | #14 |
Registered User
Join Date: Oct 2008
Location: Finland
Posts: 643
|
I just did a quick test of removing the UNLK a4 command. The program froze on WinUAE, same on my A1200, so I guess it is required for asm procedures, at least to be safe.
|
08 June 2018, 19:55 | #15 |
Registered User
Join Date: Sep 2007
Location: Stockholm
Posts: 4,356
|
That's also very odd, I never use it in my asm procedures and they tend to be quite stable. Of course, I never touch the reserved registers.
|
09 June 2018, 01:37 | #16 |
Registered User
Join Date: Jun 2009
Location: Dublin, then Glasgow
Posts: 6,379
|
My version of the manual (blue ring-bound manual, came with Blitz 2.1 floppy edition) has that exact code extract (page 63), but also has a section earlier on (page 34) saying that A4-A6 must be preserved, and restored before returning from the procedure if they were modified. This doesn't mention the UNLK line, and the code segment mentioned is missing. The addendum points to the code on page 63 for omission.
Last edited by Daedalus; 09 June 2018 at 12:43. Reason: Ring-bound manual, not spiral-bound. |
09 June 2018, 02:24 | #17 |
Registered User
Join Date: Sep 2007
Location: Stockholm
Posts: 4,356
|
I wonder if the difference between mine and MickGyver's asm-only functions is that mine always end with AsmExit.
I also wonder if it's a good idea to end a function with RTS. |
09 June 2018, 07:41 | #18 | |
Registered User
Join Date: Oct 2008
Location: Finland
Posts: 643
|
Quote:
EDIT: Removing UNLK a4 in the beginning of the routine and replacing RTS with AsmExit is working, at least in WinUAE (don't have access to my A1200 now). I applied the changes to the code in my post above. Last edited by MickGyver; 09 June 2018 at 09:12. Reason: Tested the code change |
|
05 April 2022, 00:42 | #19 |
Registered User
Join Date: Sep 2019
Location: Sydney
Posts: 357
|
Resurrecting an old thread here, but is anyone aware of any problems with auto-detected CD32 pads?
I implemented the code from post 6 by MickGyver in my Turrican port, and it worked great for me using both WinUAE and a Competition Pro pad on a real A1200, but I've had reports from another user that the CD32 pad from AmigaKit does not seem to be detected, so it runs like a normal joystick instead of using CD32 specific controls. I'm wonder if either the pad does not fully implement the CD32 standard, or the code has a problem, or something else. Anyone experienced this? Last edited by Muzza; 05 April 2022 at 00:47. |
05 April 2022, 01:01 | #20 |
Registered User
Join Date: Jun 2009
Location: Dublin, then Glasgow
Posts: 6,379
|
Can you do an output of the full binary stream of the read? Maybe as a small stand-alone executable that includes MickGyver's test code too? The key points are bits 7 and 8, which must be 1 and 0 regardless of what the rest of the pad is doing.
From a quick look at pictures someone posted of the board inside the AmigaKit controller, it looks like it probably does implement the full protocol, but I don't have one myself to verify. |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Using CD32 pad on A1200 running CD32 games issue | RetroPaul | support.Games | 23 | 14 October 2013 23:51 |
Using a six-button Megadrive pad as a CD32 pad | StarEye | support.Hardware | 22 | 09 September 2013 03:51 |
jit or 2x1200 speed break cd32 detect cd | turrican3 | support.WinUAE | 4 | 20 April 2013 17:51 |
PSX pad for CD32 | cd32.co.uk | MarketPlace | 27 | 30 September 2008 17:31 |
The Quest To Make The Comp Pro CD32 Pad My Favourite Pad | StarEye | support.Hardware | 0 | 02 December 2007 22:21 |
|
|