Jump to content



0

keypads and batari basic


46 replies to this topic

#1 toiletunes OFFLINE  

toiletunes

    Stargunner

  • 1,153 posts
  • Custom Status
  • Location:Salem, Mo 65560 USA

Posted Sun Apr 22, 2007 7:51 PM

Does Batari Basic currently support keypad functions?
I'd love to learn how to use them.

While I'm asking stuff, does Batari Basic work with the driving controllers?

That's all- thank you

#2 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Sun Apr 22, 2007 9:24 PM

View Posttoiletunes, on Sun Apr 22, 2007 9:51 PM, said:

Does Batari Basic currently support keypad functions?
I'd love to learn how to use them.
At present there are no builtin functions or statements to support the keypad controllers, the way there are for the joysticks and paddles. However, you can read the keypad on your own in batari Basic, and it's probably just a matter of time before commands for the keypad get added. I've been interested in the keypad controllers, too, so I'll see if I can write a routine or some example code.

View Posttoiletunes, on Sun Apr 22, 2007 9:51 PM, said:

While I'm asking stuff, does Batari Basic work with the driving controllers?
I've never had any driving controllers, and to be honest, I don't understand the difference between the driving controllers and the paddles. Can somebody explain how they're different?

Michael

#3 supercat OFFLINE  

supercat

    Quadrunner

  • 6,367 posts

Posted Sun Apr 22, 2007 10:12 PM

View PostSeaGtGruff, on Sun Apr 22, 2007 10:24 PM, said:

I've never had any driving controllers, and to be honest, I don't understand the difference between the driving controllers and the paddles. Can somebody explain how they're different?

Aside from the fact that they're both "round", there is no similarity between the driving controllers and the paddles.

The driving controllers operate by using two on-off contacts to indicate rotation. If the contacts are called A and B (they correspond to the "left" and "right" inputs on the joystick, but I'm not sure which is which) rotating the knob one click clockwise will cause contact A to get the value of B while B gets the opposite of value A (thus going through the sequence "off off / off on / on on / on off". Rotating the knob one clock counter-clockwise will cause contact B to get the value of A, while A gets the opposite of value B. Software can watch the sequence of transitions and count how many clicks the knob is turned in either direction.

The driving controller does not have to be read as often as the paddles, nor does it have to be read with any particularly accurate or consistent timing, provided that the maximum time between readings never exceeds the time between adjacent clicks in the same direction. If a game only reads the controller once per frame, a user who turns the knob very quickly will exceed the software's ability to accurately count it. If the screen is divided into zones that are at most 30 or so scan lines high, however, checking the controller once per zone may suffice. If RAM is available, each check need only take 7-8 cycles in the kernel (LDA SWCHA / STA temp [or temp,x]); you can check the fetched data later. If RAM is more precious than that, I'm not sure the best approach.

#4 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Sun Apr 22, 2007 10:29 PM

View Postsupercat, on Mon Apr 23, 2007 12:12 AM, said:

Aside from the fact that they're both "round", there is no similarity between the driving controllers and the paddles.
Thank you for the explanation. I'm sure coding examples must be out there in the Stella archives, but since I've never had any driving controllers, I've never studied how to read them. :)

Michael

#5 Gorf OFFLINE  

Gorf

    River Patroller

  • 4,633 posts

Posted Mon Apr 23, 2007 4:53 AM

Yes quite different. A paddle is giving you a analog voltage level in
digital form. The paddle is a potentiometer. 0- MAX resistance, that
the VCS circuitry converts to digital data. The driving controller
uses switches and either grey or quadrature encoding to determine
which direction the knob is being turned and even how fast.

The other MAJOR difference is a paddle is finite....it has an upper
and lower limit. With quadrature encoding its an eternal loop(if
you so desire it to be)and makes for a much nicer and smoother
analog stick....I hope to prove that with one of my Jaguar releases.

Also the other advantage of quadrature and encoders is you do not
need an A to D converter but only two input bits. All game systems
have at least two input bits on their controller ports and all can use
an encoder to simulate a paddle or analog device. The newer xgen
consoles are using USB like controller ports but no problem. Mice
and USB work great together. Oh a mouse is two encoders, one for
x axis and one for y axis. It's like two high rez driving controllers.

Here...some extra tidbits.

http://en.wikipedia..../Rotary_encoder


:D

Edited by Gorf, Mon Apr 23, 2007 4:54 AM.


#6 CurtisP OFFLINE  

CurtisP

    Chopper Commander

  • 211 posts

Posted Mon Apr 23, 2007 8:50 PM

View PostSeaGtGruff, on Sun Apr 22, 2007 11:24 PM, said:

I've been interested in the keypad controllers, too, so I'll see if I can write a routine or some example code.

I've considered writing a Keypad routine as well. My thought was to stick the reading code in the VBLANK routine, and store the results in the variables used by the paddle routine to be read by the program. Don't know when I'll get to it though.

Or we could collaborate...

#7 Gorf OFFLINE  

Gorf

    River Patroller

  • 4,633 posts

Posted Mon Apr 23, 2007 9:41 PM

I remember using those keyboards to input the one and only
MagiCard program i ever used that thing for. I think those could
have served a game like 'Adventure' pretty well.

#8 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Mon Apr 23, 2007 10:17 PM

View PostCurtisP, on Mon Apr 23, 2007 10:50 PM, said:

View PostSeaGtGruff, on Sun Apr 22, 2007 11:24 PM, said:

I've been interested in the keypad controllers, too, so I'll see if I can write a routine or some example code.

I've considered writing a Keypad routine as well. My thought was to stick the reading code in the VBLANK routine, and store the results in the variables used by the paddle routine to be read by the program. Don't know when I'll get to it though.

Or we could collaborate...
The "Stella Programmer's Guide" says that a delay of 400 microseconds is needed between sending a signal to SWCHA and reading INPT0, INPT1, and INPT4 to see which key is being pressed. If I did my math correctly, I think that translates into a delay of about 6.28 scan lines, or setting TIM8T to 60 intervals. Since there are 4 rows that need to be checked, that means it would take slightly more than 25 scan lines to check all 4 rows-- let's say about 26 or 27 scan lines, since it takes time to set the timer, check the timer, read the INPT0/1/4 registers, and store the results. So it will take most of the "VBLANK" time to read one keypad controller. And since there are 12 buttons, it will take at least 2 bytes to store the results. Thus, only one keypad controller per frame could be checked this way, which should be okay-- so that sounds like a plan!

Michael

#9 supercat OFFLINE  

supercat

    Quadrunner

  • 6,367 posts

Posted Mon Apr 23, 2007 11:35 PM

View PostSeaGtGruff, on Mon Apr 23, 2007 11:17 PM, said:

And since there are 12 buttons, it will take at least 2 bytes to store the results. Thus, only one keypad controller per frame could be checked this way, which should be okay-- so that sounds like a plan!

Why check only one at a time? Start out by setting all rows low on both controllers and leave them "idle" in that configuration. Then you should be able to do something like:
  lda INPT0
  and INPT1
  and INPT4
  bpl got_left_key
  lda INPT2
  and INPT3
  and INPT5
  bpl got_right_key


#10 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Tue Apr 24, 2007 1:13 AM

View Postsupercat, on Tue Apr 24, 2007 1:35 AM, said:

Why check only one at a time? Start out by setting all rows low on both controllers and leave them "idle" in that configuration. Then you should be able to do something like:
  lda INPT0
  and INPT1
  and INPT4
  bpl got_left_key
  lda INPT2
  and INPT3
  and INPT5
  bpl got_right_key
I didn't realize you could do that. The "Stella Programmer's Guide" seems to say that you write to SWCHA to set the row you want to read, and then check INPT0, INPT1, and INPT4 to see which key was pressed in that row. It doesn't say anything about reading INPT2, INPT3, and INPT5. :ponder:

The SPG is short on examples, so I guess the thing to do is disassemble a program that uses the keypad controllers, and see how it reads them.

Michael

#11 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,236 posts
  • begin 644 contest

Posted Tue Apr 24, 2007 3:31 AM

Regarding driving controllers, I think I posted some bB code examples about a year ago. There are asm examples on the Stella list of course, but I've never gotten them to work and I never figured out why.

#12 Gorf OFFLINE  

Gorf

    River Patroller

  • 4,633 posts

Posted Tue Apr 24, 2007 6:15 AM

I'd like to see the rotary code.

#13 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,236 posts
  • begin 644 contest

Posted Tue Apr 24, 2007 1:54 PM

View PostGorf, on Tue Apr 24, 2007 7:15 AM, said:

I'd like to see the rotary code.
I posted it here:
http://www.atariage....showtopic=87310

It's not terribly efficient but it works very well.

#14 Gorf OFFLINE  

Gorf

    River Patroller

  • 4,633 posts

Posted Thu Apr 26, 2007 3:10 AM

Cool! In 2600 terms, this may indeed be inefficient but it still a far cry simpler than a Jaguar DSP version I wrote which was kind of a PITA.
However it works quite well. Reading the Jaguar Ports is an operating system in itself. You have to read one row of inputs at a time. So that is 6 reads, then you have to rotate the read and on and on. I miss the old days when one read was usually enough to get the info you needed.

#15 SpiceWare ONLINE  

SpiceWare

    Quadrunner

  • 5,981 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Thu Apr 26, 2007 11:35 AM

View PostSeaGtGruff, on Tue Apr 24, 2007 2:13 AM, said:

The SPG is short on examples, so I guess the thing to do is disassemble a program that uses the keypad controllers, and see how it reads them.

Michael
Here's a project I didn't get very far on in 2004 - Dragon Defense Squad - I did get the keyboard to work.

#16 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Thu Apr 26, 2007 7:04 PM

View PostSpiceWare, on Thu Apr 26, 2007 1:35 PM, said:

Here's a project I didn't get very far on in 2004 - Dragon Defense Squad - I did get the keyboard to work.
Thank you, thank you, thank you! I already see something I was doing wrong. When you write to SWCHA for the row you want to read, I was writing a value of 1 to the bit, but apparently you're supposed to write 0 to that bit and 1s to the other bits? (As I said, the SPG is short on examples-- as in, zip, zilch, nada, nosirree-- and in some cases the explanations are so vague that they don't actually "explain" anything! :ponder:)

I think I can get my bB keypad controller routine working now. :)

Michael

#17 atari2600land OFFLINE  

atari2600land

    Quadrunner

  • 6,489 posts
  • All hail the zyzzyva!
  • Location:Salem, Oregon

Posted Thu Apr 26, 2007 7:43 PM

Is the keypad the same as the children's controller in terms of programming?

#18 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,236 posts
  • begin 644 contest

Posted Thu Apr 26, 2007 8:21 PM

View PostSeaGtGruff, on Thu Apr 26, 2007 8:04 PM, said:

View PostSpiceWare, on Thu Apr 26, 2007 1:35 PM, said:

Here's a project I didn't get very far on in 2004 - Dragon Defense Squad - I did get the keyboard to work.
Thank you, thank you, thank you! I already see something I was doing wrong. When you write to SWCHA for the row you want to read, I was writing a value of 1 to the bit, but apparently you're supposed to write 0 to that bit and 1s to the other bits? (As I said, the SPG is short on examples-- as in, zip, zilch, nada, nosirree-- and in some cases the explanations are so vague that they don't actually "explain" anything! :ponder:)

I think I can get my bB keypad controller routine working now. :)

Michael
Cool :cool:

In order to maximize the utility of such a routine in the bB environment, I think it would be wise to write the routine as a bB function, taking the controller number as an argument (0 or 1 for L/R) and have it return the number pressed (0-9 for their respective numbers, 10 for *, 11 for #, and 12 for nothing pressed.)

This would make it ideal to use a data table or "on ... goto" for the value returned, and/or allow the number to be used for a calculation of some kind.

#19 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Fri Apr 27, 2007 12:02 AM

Okay, I finally got my keypad controller routine to work. I'm sure it could be done a lot better, and I intend to optimize it before putting it into a routine that could be included in a batari Basic program-- e.g., by adding "include keypads.asm" and "dim keypads = a" (or some other user variable) to the program. One way it can be optimized is by replacing the "sleep" statements with less ROM-hungry methods of wasting 476 cycles.

Right now, the routine reads both keypad controllers during the vblank period-- so that rules out any possibility of using the vblank period for other things. And even if someone wanted to customize the routine so they can squeeze other tasks into the four lengthy "sleep" periods, the routine uses the accumulator and the Y register for storing the left and right key presses, so any other tasks that are squeezed into the "sleep" periods would be able to use only the X register-- unless the routine were rewritten to use X and Y, such that only the accumulator could be used for other tasks. Anyway, the key presses that are stored in A and Y get combined at the end of the routine, and are stored in the variable "keypads" (which must be set to one of the user variables using a "dim" statement). When the routine ends, the low nybble of "keypads" will contain the key pressed on the left keypad, and the high nybble will contain the key pressed on the right keypad, as follows:

$00 = nothing pressed

$01_$02_$03__________$10_$20_$30
$04_$05_$06__________$40_$50_$60
$07_$08_$09__________$70_$80_$90
$0A_$0B_$0C__________$A0_$B0_$C0
If two keys are pressed on the same controller, the higher-valued key will take priority-- e.g., if 1 and 7 are pressed at the same time, then 7 will override 1. However, a key pressed on one keypad will *not* override a key pressed on the other keypad-- e.g., if 1 is pressed on the left keypad, and 7 is pressed on the right keypad, then both key presses will be returned.

When I optimize the routine and put it into an includes file, I'll also add a function that can be called to more easily identify the key that was pressed on a given keypad, so the includes file will contain both the vblank routine and the function.

The "keypad_test.bas" program displays two 3-by-4 grids of squares that represent the keys on the left and right keypads. As you press a key on either keypad controller, the appropriate square will light up to show which key you're pressing.

Don't forget that when you run the program in an emulator, you need to tell the emulator that the program uses the keypad controllers in the left and right ports. In the Stella emulator, the keys on the left and right keypads are controlled (or emulated) by the following keys on the keyboard:

1_2_3__________8_9_0
Q_W_E__________I_O_P
A_S_D__________K_L_;
Z_X_C__________,_._/
I want to extend sincere gratitude to the following people:

-- tolietunes, for asking the question that prompted me to finally try this;
-- CurtisP, for suggesting that the keypads be read during vblank;
-- supercat, for pointing out that both keypads can be read at the same time;
-- SpiceWare, for providing a working example of actual code; and
-- batari, for suggesting the idea of a function (which I haven't done yet).

And to answer atari2600land's question-- yes, I think the kids' controllers are identical to the keypad controllers as far as functionality and programming are concerned.

If anyone can see ways of improving the vblank routine, *please* post them, so I can modify the routine before posting it as a "keypads.asm" includes file.

Michael

keypad_test_1.png

keypad_test_2.PNG

Attached Files



#20 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,236 posts
  • begin 644 contest

Posted Fri Apr 27, 2007 12:23 AM

View PostSeaGtGruff, on Fri Apr 27, 2007 1:02 AM, said:

$00 = nothing pressed

$01_$02_$03__________$10_$20_$30
$04_$05_$06__________$40_$50_$60
$07_$08_$09__________$70_$80_$90
$0A_$0B_$0C__________$A0_$B0_$C0
Combining both keyboards into a single byte is a clever idea as it requires just one pass of the function to get two reads. For that matter, it kind of obviates the need for a function altogether, as you don't need to pass any arguments. It might not be obvious to beginners how to separate the nybbles, so that would be covered in the documentation.

Though I'm not sure about the way the keys are encoded. 1-9 map to their respective keys but $0B maps to the 0 key here. While it does make sense to map $00 to nothing pressed, it also makes sense to map $00 to key 0. So what do others think is better?

#21 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Fri Apr 27, 2007 12:26 AM

View PostGorf, on Mon Apr 23, 2007 11:41 PM, said:

I remember using those keyboards to input the one and only
MagiCard program i ever used that thing for. I think those could
have served a game like 'Adventure' pretty well.
For many years, I've been planning an adventure game (or trilogy) called "Quest for the Lost Pyramids of Atlantis," and I think the ideal situation would be to use a joystick in the left port for controlling the player's movement, and a keypad in the right port (or vice versa) for selecting items in the inventory strip, or selecting actions (e.g., pick up, drop, buy, sell, talk, etc.) in the action strip.

However, I'd also like to use the AtariVox or MemCard/SaveKey for saving games, so I'm not sure how that could be worked out, since there's no way to have a keypad and the SaveKey plugged into a port at the same time. :( I guess one solution would be to switch to a "save game" or "load game" menu screen using the keypad controller (or perhaps using the "select" console switch), and then letting the player unplug the keypad, plug in the SaveKey, save or load the game, and then plug in the keypad controller again before switching back to the game screen. :ponder:

Michael

#22 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Fri Apr 27, 2007 12:33 AM

View Postbatari, on Fri Apr 27, 2007 2:23 AM, said:

Combining both keyboards into a single byte is a clever idea as it requires just one pass of the function to get two reads. For that matter, it kind of obviates the need for a function altogether, as you don't need to pass any arguments. It might not be obvious to beginners how to separate the nybbles, so that would be covered in the documentation.

Though I'm not sure about the way the keys are encoded. 1-9 map to their respective keys but $0B maps to the 0 key here. While it does make sense to map $00 to nothing pressed, it also makes sense to map $00 to key 0. So what do others think is better?
I was thinking that a function is still a good idea, because it makes it easier for beginners to use the keypads without having to worry about bit operations. And the function could return different values than the ones that the vblank routine uses, such as changing $0B to a returned value of 0. I'd even like to make the return values "programmable," probably using some sort of user-defined lookup tables that convert the "internal" values into "returned" values. For example, having keys 1, 2, and 3 on the top row may make sense for a program that uses a "telephone buttons" type of arrangement, but it does *not* make sense for a calculator type of program. :)

Michael

#23 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Fri Apr 27, 2007 1:24 AM

View PostSeaGtGruff, on Fri Apr 27, 2007 2:02 AM, said:

Right now, the routine reads both keypad controllers during the vblank period-- so that rules out any possibility of using the vblank period for other things. And even if someone wanted to customize the routine so they can squeeze other tasks into the four lengthy "sleep" periods, the routine uses the accumulator and the Y register for storing the left and right key presses, so any other tasks that are squeezed into the "sleep" periods would be able to use only the X register-- unless the routine were rewritten to use X and Y, such that only the accumulator could be used for other tasks.
I was just thinking that I could code this in such as way that four "mini-vblank" routines could be performed (if defined in the program) while the keypad-reading routine is waiting during the four lengthy "sleep" periods. And I could store A, X, and Y in temp variables before JSR-ing to the four mini-vblank routines, and restore them upon returning to the keypad routine, so that all three could be used by the mini-vblank routines. This is going to be fun to do! :)

Michael

#24 CurtisP OFFLINE  

CurtisP

    Chopper Commander

  • 211 posts

Posted Fri Apr 27, 2007 9:55 AM

View PostSeaGtGruff, on Fri Apr 27, 2007 2:02 AM, said:

Okay, I finally got my keypad controller routine to work. I'm sure it could be done a lot better, and I intend to optimize it before putting it into a routine that could be included in a batari Basic program-- e.g., by adding "include keypads.asm" and "dim keypads = a" (or some other user variable) to the program. One way it can be optimized is by replacing the "sleep" statements with less ROM-hungry methods of wasting 476 cycles.

One of my ideas was to use the paddle variables for the keyboard. However, since they are shared with missile0, this would require the kernel_option no_blank_lines to be set. I think I like the idea of dimming the variable better.

The way I would have used vblank was to spread the reading of the controller out over multiple vblanks. Set the output register in one and read it in the next. The drawscreen in between would give you plenty of microseconds. This would require two variables, one for a counter and one for the results. The results variable would just stay 0 until the keypad read was done.

Another possible issue is that this code forces both controllers to be a keypad, whereas some people would like to use a keypad plus a joystick.

All that said, it's fantastic that you got the reading code to work!

#25 toiletunes OFFLINE  

toiletunes

    Stargunner

  • 1,153 posts
  • Custom Status
  • Location:Salem, Mo 65560 USA

Posted Fri Apr 27, 2007 10:15 AM

Thanks again to everyone for their hard work and interest- You're the best!




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users