DC Controller Code

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
Post Reply
404NotFound
DCEmu Ex-Mod
DCEmu Ex-Mod
Posts: 4970
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Thu Nov 29, 2001 3:40 pm
Location: The Canadian-Mexican border.
Has thanked: 0
Been thanked: 0

DC Controller Code

Post by 404NotFound »

Ok, I understand the type of code used in examples, where it's as such:

Code: Select all

MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st)
            if (st->buttons & CONT_DPAD_RIGHT)
but, what i'm wondering is how do i get a more powerful control scheme? As in I want to be able to register if two buttons are pressed simultaneously, and how to get multiple controllers working (up to 4)

I've read through all the old posts, even toastman's lengthy explanations, but I'm still not fully getting it here... ideally i'd write a class to do it for me (as that seems the easiest after a little initial work), but I still haven't learned classes yet.

I've also looked through siggler's SmashDC code, which I understand. It is as follows:

Code: Select all

void UpdateControls()
{
	UpdateControlSet( 0 );
	UpdateControlSet( 1 );
	UpdateControlSet( 2 );
	UpdateControlSet( 3 );
}

uint8 GetPortAddr( int port )
{
	uint8 addr;

	addr=maple_addr( port, 0 );

	return addr;
}

int PadInPort( int port )
{
	int retval=FALSE;

	if ( maple_device_func( port, 0 ) == MAPLE_FUNC_CONTROLLER )
		retval=TRUE;

	return retval;
}

void UpdateControlSet( uint8 index )
{
	uint8 mcont = 0;
	cont_cond_t cond;

	mcont = GetPortAddr( index );

	if (cont_get_cond(mcont, &cond))
	{
		//printf("Error getting controller status\n");
	}
	else
	{
		if (!(cond.buttons & CONT_DPAD_UP))
			ControlSets[index].Up=TRUE;
		else ControlSets[index].Up=FALSE;

		if (!(cond.buttons & CONT_DPAD_DOWN))
			ControlSets[index].Down=TRUE;
		else ControlSets[index].Down=FALSE;

		if (!(cond.buttons & CONT_DPAD_LEFT))
			ControlSets[index].Left=TRUE;
		else ControlSets[index].Left=FALSE;

		if (!(cond.buttons & CONT_DPAD_RIGHT))
			ControlSets[index].Right=TRUE;
		else ControlSets[index].Right=FALSE;

		if (!(cond.buttons & CONT_Y))
			ControlSets[index].ShootUp=TRUE;
		else ControlSets[index].ShootUp=FALSE;

		if (!(cond.buttons & CONT_A))
			ControlSets[index].ShootDown=TRUE;
		else ControlSets[index].ShootDown=FALSE;

		if (!(cond.buttons & CONT_X))
			ControlSets[index].ShootLeft=TRUE;
		else ControlSets[index].ShootLeft=FALSE;

		if (!(cond.buttons & CONT_B))
			ControlSets[index].ShootRight=TRUE;
		else ControlSets[index].ShootRight=FALSE;

		if (!(cond.buttons & CONT_START))
		{
			ControlSets[index].Exit=TRUE;
		}
		else
			ControlSets[index].Exit=FALSE;
	}
}
BUT Toastman said that 1.1.8 introduced a new controller API, so the above is probably not working code in 1.1.9. Can someone point out the differeneces?
Viktor
DC Developer
DC Developer
Posts: 30
Joined: Sun Nov 04, 2001 4:47 am
Location: Stockholm, Sweden
Has thanked: 0
Been thanked: 1 time
Contact:

Post by Viktor »

You can try to look at my wrapper class for controll input, you can find it on my page, http://www.vgsoftware.com/, there is also a example program with the class. But its all in C++ and uses classes so it helps if you know how to use classes.

/Viktor
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Post by BlackAura »

Code: Select all

if (!(cond.buttons & CONT_A)) 
becomes

Code: Select all

if (st->buttons & CONT_A)
and the ports thingy is different now.

Just using C, you can get the status of whichever controller you like by using the following function. 0 is the first controller, 1 is the second, 2 is the third, and 3 is the fourth. It returns a pointer to the controller status, or NULL if there aren't that many controllers.

Code: Select all

cont_state_t padGetState(int padnum)
{
	maple_device_t	*dev;
	cont_state_t	*state;

	// Find a controller 
	dev = maple_enum_type(padnum, MAPLE_FUNC_CONTROLLER);
	if(!dev)
		return NULL;

	// Get controller state
	state = (cont_state_t *)maple_dev_status(dev);
	if(!state)
		return NULL;

	// Return the state structure
	return state;
}
Now, once we have that status structure, we need to know how to use it. You can get the status of the first controller like this

Code: Select all

cont_state_t *state;
state = padGetState(0);
Next, you need to know how to read a button. The variable buttons[/b] contains the status of all the buttons, stored as bits. Each bit represents one button, and if the bit is turned on (1) then the button is pressed. You can detect if the A button is pressed like this

Code: Select all

if(state-> buttons & CONT_A)
	....
It doesn't matter if multiple buttons are pressed, because that code will only check for one button. If you want to do something when, say, A and B are pressed, you simply combine the test for A and B, like this:

Code: Select all

if( (state->buttons & CONT_A) && (state->buttons & CONT_B) )
	....
You can check the status of all the digital buttons on the controller in this way, you simply replace CONT_A with the name of whichever button you want. Here's the ones that are valid for a standard Dreamcast controller
  • A = CONT_A
    B = CONT_B
    X = CONT_X
    Y = CONT_Y
    Start = CONT_START
    D-Pad Up = CONT_DPAD_UP
    D-Pad Down = CONT_DPAD_DOWN
    D-Pad Left = CONT_DPAD_LEFT
    D-Pad Right = CONT_DPAD_RIGHT
EverStoned
Psychotic DCEmu
Psychotic DCEmu
Posts: 602
Joined: Sat Nov 30, 2002 8:34 am
Has thanked: 0
Been thanked: 0
Contact:

Post by EverStoned »

I was gonna say that.

Or at least the bit about the &&.
User avatar
toastman
Iron Fist of Justice
Iron Fist of Justice
Posts: 4933
Joined: Sat Nov 10, 2001 3:08 am
Location: New Orleans
Has thanked: 0
Been thanked: 0
Contact:

Post by toastman »

Or better yet,

Code: Select all

if( (state->buttons & (CONT_A | CONT_B)) ) 
 //Do stuff here
That will also test the buttons together.
No signature.
404NotFound
DCEmu Ex-Mod
DCEmu Ex-Mod
Posts: 4970
Joined: Thu Nov 29, 2001 3:40 pm
Location: The Canadian-Mexican border.
Has thanked: 0
Been thanked: 0

Post by 404NotFound »

K thx guys. I understand it all now.
EvilSporkMan
God Of All Things Sporkish
God Of All Things Sporkish
Posts: 755
Joined: Sat Feb 16, 2002 1:04 pm
Location: Somewhere over the cuckoo's nest
Has thanked: 0
Been thanked: 0

Post by EvilSporkMan »

Or better yet,
Code:

if( (state->buttons & (CONT_A | CONT_B)) )
//Do stuff here


That will also test the buttons together.
Maybe you should explain how that's a "binary" OR and what exactly it does, so poor 404 doesn't have to use code he doesn't understand. :P
You can go anywhere you want if you look serious and carry a clipboard.
404NotFound
DCEmu Ex-Mod
DCEmu Ex-Mod
Posts: 4970
Joined: Thu Nov 29, 2001 3:40 pm
Location: The Canadian-Mexican border.
Has thanked: 0
Been thanked: 0

Post by 404NotFound »

EvilSporkMan wrote:
Or better yet,
Code:

if( (state->buttons & (CONT_A | CONT_B)) )
//Do stuff here


That will also test the buttons together.
Maybe you should explain how that's a "binary" OR and what exactly it does, so poor 404 doesn't have to use code he doesn't understand. :P
WTF... how did you know...

Yeah, i'm guessing there is a difference between && and &, || and |...

DOH, slipped my mind, & is a pointer.... scratch that.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Post by BlueCrab »

&& = Logical AND
|| = Logical OR
& = Bitwise AND
| = Bitwise OR

& can also be used to pass some variable by reference. (i.e. pointer)

Here's a page that explains Bitwise operators:
http://www.cs.cf.ac.uk/Dave/C/node13.ht ... 0000000000
Which is a part of this page (that contains a lot of information on C):
http://www.cs.cf.ac.uk/Dave/C/CE.html
Last edited by BlueCrab on Mon Mar 03, 2003 2:55 pm, edited 2 times in total.
EvilSporkMan
God Of All Things Sporkish
God Of All Things Sporkish
Posts: 755
Joined: Sat Feb 16, 2002 1:04 pm
Location: Somewhere over the cuckoo's nest
Has thanked: 0
Been thanked: 0

Post by EvilSporkMan »

& isn't a pointer, it's "address of" when used before a variable.

int foo;
int *ptr = &foo;

And thank you, bitwise was the word I wanted :)
You can go anywhere you want if you look serious and carry a clipboard.
EverStoned
Psychotic DCEmu
Psychotic DCEmu
Posts: 602
Joined: Sat Nov 30, 2002 8:34 am
Has thanked: 0
Been thanked: 0
Contact:

Post by EverStoned »

reference and constant reference are two different things...that should be noted.
User avatar
toastman
Iron Fist of Justice
Iron Fist of Justice
Posts: 4933
Joined: Sat Nov 10, 2001 3:08 am
Location: New Orleans
Has thanked: 0
Been thanked: 0
Contact:

Post by toastman »

& - a case study

There are many uses for &:

& - Bitwise AND
Using bitwise AND, you will compare the EACH AND EVERY BIT of both the left and right operand. The result will be any and all bits that the two sides have in common.
Example:
110011 & 100001 would return 100001 as those are the common bits.

&& - Logical AND
Logical AND will take two values and see if they are both TRUE, where TRUE is any non-zero number.
Example:
127 && 4 would return non-zero, 0 && 4 would return zero, 0 && 0 would return 0

&<variable>
This unfortunately is dependant on context
When used in a function header like so:

Code: Select all

int My_Function(int &watch_me);
It means to pass the variable "by reference". This means that watch_me is actually a pointer to the original variable. This means that anything you do to this variable in that function will remain after you exit the function.

When used anywhere else, it means to reference a variable, or get the address in memory. There's no good way I can explain it, I hope a short example helps:

Code: Select all

int *pointer;
int variable = 42;

/*To make pointer point to variable, you need to somehow get variable's address to pointer. This is one thing that referencing is good for.*/
pointer = &variable //Now pointer points to variable
There also some functions you'll see in KOS that have definitions like this
int KOS_function(int *wtf);
If you have a normal variable you wish to pass into there, you can also reference it, when you call the function.
KOS_function(&my_variable);
No signature.
404NotFound
DCEmu Ex-Mod
DCEmu Ex-Mod
Posts: 4970
Joined: Thu Nov 29, 2001 3:40 pm
Location: The Canadian-Mexican border.
Has thanked: 0
Been thanked: 0

Post by 404NotFound »

Ah i'm crystal now!

As in each controller alias has a different bit definition.. say CONT_A has 001000 and CONT_B has 100000, and you say this:

Code: Select all

if( (state->buttons & (CONT_A | CONT_B)) ) 
It means it does a bitwise OR, and produces 101000, and stores that code as the state of the controller, and since the bitwise state has the combination of both buttons, it then says "hey look, they are both pressed."

K, sweetness.
ragnarok2040
DC Developer
DC Developer
Posts: 462
Joined: Wed Oct 17, 2001 7:44 pm
Has thanked: 0
Been thanked: 0

Post by ragnarok2040 »

Glad that I read this thread as I just made a function with (outa, outb) where those two variables plug into some equations and then spits out values into them, *_*.

/me corrects code
User avatar
toastman
Iron Fist of Justice
Iron Fist of Justice
Posts: 4933
Joined: Sat Nov 10, 2001 3:08 am
Location: New Orleans
Has thanked: 0
Been thanked: 0
Contact:

Post by toastman »

404NotFound wrote:Ah i'm crystal now!

As in each controller alias has a different bit definition.. say CONT_A has 001000 and CONT_B has 100000, and you say this:

Code: Select all

if( (state->buttons & (CONT_A | CONT_B)) ) 
It means it does a bitwise OR, and produces 101000, and stores that code as the state of the controller, and since the bitwise state has the combination of both buttons, it then says "hey look, they are both pressed."

K, sweetness.
Yeah, something like that.
No signature.
nymus
DC Developer
DC Developer
Posts: 968
Joined: Tue Feb 11, 2003 4:12 pm
Location: In a Dream
Has thanked: 5 times
Been thanked: 6 times

Post by nymus »

404, I like the way you figured it out, especially since you haven't had prior exposure to binary logic. Good for you man!

Anyways, here's a class i wrote for the contrtoller (KOS-1.1.9)

Code: Select all

#ifndef CONTROLLER_H
#define CONTROLLER_H


#include <kos.h>
/**
 * controller class for handling controllers
 */
 
class Controller {
	private:
	static int IN_USE[4]; //indices in use;//initalize to -1
	
	int mapleIndex; //location on Maple bus for KOS
	uint32 pushedLast; //millisecond
	
	uint32 delay; //millisecond
	
	public:
	Controller() {
		delay = 0;
		pushedLast = 0;
		mapleIndex = -1;//set false first
		
		int i=0;
		while(i < 4) { //four controller ports
			maple_device_t* dev = maple_enum_type(i, MAPLE_FUNC_CONTROLLER);
		
			if(dev) 
				if(IN_USE[i] == -1) {
					mapleIndex = i; //free slot
					IN_USE[i] = 1;
					break;
				}
		
			i++;
		}				
	}
	
	virtual ~Controller() { }
	
	uint32 getDelay() { return delay; }
	uint32 lastPush() { return pushedLast; }
	int getMapleIndex() { return mapleIndex; }
	
	Controller& setDelay(uint32 d) { delay = d; return *this;}
	
	uint32 checkController() {
		uint32 curTime;
		timer_ms_gettime(NULL, &curTime);
		
		if((curTime-pushedLast) > delay) {
			maple_device_t* dev = maple_enum_type(mapleIndex, MAPLE_FUNC_CONTROLLER);
			pushedLast = curTime;
			return ((cont_state_t*)maple_dev_status(dev))->buttons;
		}
		
		return 0;
	}
};
#endif
save it as "Controller.h" and use it as follows:

Code: Select all


int Controller::IN_USE = {-1, -1, -1, -1};

int main() {
	Controller c;

	/**
	 * Check if the contrtoller was found
	 */
	if(c.getMapleIndex() == -1) {
		printf("Error initialising controller!\n");
		return 0;
	}

	/* The DC Controller is very FAST so you can use this
	 * to slow down the button refresh
	 */
	
	c.setDelay(200);

	while(true) {
		uint32 result = c.checkController();
		
		if(result & (CONT_A | CONT_X)) printf("A and X pushed.\n");
				
		else if((result & CONT_DPAD_UP)) printf("UP pushed.\n");
			
		else if((result & CONT_DPAD_DOWN)) printf("DOWN pushed.\n");
				
		else if((result & CONT_DPAD_RIGHT)) printf("RIGHT pushed.\n");
			
		else if((result & CONT_START)) {
			printf("Bored already?\n");
			 return 0;						
		}
	}
}
behold the mind
inspired by Dreamcast
Phantom
DC Developer
DC Developer
Posts: 1753
Joined: Thu Jan 16, 2003 4:01 am
Location: The Netherlands
Has thanked: 0
Been thanked: 0
Contact:

Post by Phantom »

404NotFound wrote:Ah i'm crystal now!

As in each controller alias has a different bit definition.. say CONT_A has 001000 and CONT_B has 100000, and you say this:

Code: Select all

if( (state->buttons & (CONT_A | CONT_B)) ) 
It means it does a bitwise OR, and produces 101000, and stores that code as the state of the controller, and since the bitwise state has the combination of both buttons, it then says "hey look, they are both pressed."
That code checks if CONT_A or CONT_B is pressed (or both). If one or both of those buttons is pressed, the result of the bitwise AND will be unequal to zero, i.e. 'true'.

EDIT: See BlackAura's post earlier in this thread for an example of how to check for two buttons being pressed at the same time.

EDIT 2: I just noticed that this thread is over a week old, so this reply is probably useless by now.. bleh. :)
Post Reply