Shop OBEX P1 Docs P2 Docs Learn Events
PSTWO controller emulation - Page 2 — Parallax Forums

PSTWO controller emulation

2»

Comments

  • scanlimescanlime Posts: 106
    edited 2008-07-08 17:18
    computer guy said...

    Also do you have a copy of the schematic for connecting the prop to the PS2?

    It's simple enough that I haven't made an actual schematic. You can connect the PS2 controller data pins directly to the prop, they're both 3.3v logic. There are five data pins, which my emulator expects to be connected sequentially to Prop pins:

    PIN_DAT = 0
    PIN_CMD = 1
    PIN_SEL = 2
    PIN_CLK = 3
    PIN_ACK = 4

    There are plenty of places on the internet where you can find pinouts for the PS2 controller socket. Connect all of these pins to the prop, (every one of them is necessary) hook up ground, and ignore power (unless you want to power the prop off of the PS2 supply- if you do this, be very careful, as it's easy to blow a hard-to-replace fuse in the PS2).
    computer guy said...

    I have had a look at your emulator and am not sure how to use it.
    Could you please write some short code to configure it to emulate an Analog Controller and then send out that the "Square" button has been pushed.
    This should be enough to give me a general idea of how to use it.

    I haven't tested this code, so please excuse any bugs, but it'd be something like this... All of the magic numbers for bytes and bits within the controller packet format are defined in my other "psx_remote_port" object, or most of them are available on the internet.

    CON
      _CLKMODE = XTAL1 + PLL16X
      _XINFREQ = 5_000_000
    
      CONTROLLER_PIN = 4
    
    OBJ
      emulator : "psx_controller_emulator"
    
    VAR
      ' 18-byte buffer for controller state
      word c_buttons
      byte c_axes[noparse][[/noparse] 4]
      byte c_pressure[noparse][[/noparse]12]
    
    PUB main
    
      ' Initialize default controller state.
      ' Buttons are released (1), axes are centered ($80).
    
      c_buttons := $FFFF
      bytefill(@c_axes, $80, 4)
      bytefill(@c_pressure, 0, 12)
                                          
      emulator.start(CONTROLLER_PIN, -1, emulator#CONTROLLER_ANALOG)
      emulator.add_state_buffer(@c_buttons)
    
      ' Press the left D-pad button.
      ' Next time the Playstation polls the controller emulator, it will see this change.
      c_buttons &= ~$0080
    
      etc..
    
    



    Good luck!

    Post Edited (Micah Dowty) : 7/8/2008 5:25:03 PM GMT
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-09 04:28
    Micah,

    Sorry just one more thing to release the left D-pad button what would I do?

    My guess would be
    c_buttons &= $0080
    
    



    but I am probably wrong.


    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip
  • scanlimescanlime Posts: 106
    edited 2008-07-09 07:20
    computer guy said...
    Micah,

    Sorry just one more thing to release the left D-pad button what would I do?

    My guess would be
    c_buttons &= $0080
    
    



    but I am probably wrong.


    Thank you smile.gif

    c_buttons is a bitfield- "1" is not-pressed, "0" is pressed. To release the button, you'd bitwise OR it with $0080:

    c_buttons |= $0080
    
    



    --Micah
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-09 09:51
    So press Left and Right

    c_buttons &= $0080 & $0020 
    
    



    release left

    c_buttons |= $0080 
    
    



    release right

    c_buttons |= $0020 
    
    




    Also to set the position of the left analog stick? and how many bits is it so that I can get the value from an ADC and go direct to output without any maths in between.

    I will leave you alone so that you can get on with your own projects now. smile.gif

    Thank you so much smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip

    Post Edited (computer guy) : 7/9/2008 11:06:26 AM GMT
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-09 12:48
    Is there anything wrong with putting 100ohm resistors on all of the i/o pins of the prop. (for protection against wrong wiring)

    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip
  • scanlimescanlime Posts: 106
    edited 2008-07-09 18:04
    computer guy said...
    So press Left and Right

    c_buttons &= $0080 & $0020 
    
    



    Almost... One way to do it is "c_buttons &= ~($0080 | $0020)". If you're still confused, re-read over the Propeller manual's section on operators, and perhaps check out a tutorial on boolean logic.

    Also, be warned, I might have misspoke when I said that "1" is released and "0" is pressed. Some of my own notes were inconsistent, and I think it actually might be the other way around- "1" is pressed.
    computer guy said...

    Also to set the position of the left analog stick? and how many bits is it so that I can get the value from an ADC and go direct to output without any maths in between.

    An 8-bit A/D should do exactly what you want. $00 and $FF are the extremes of motion (I forget the polarity- which one is left/top/right/bottom) and $80 is the center. If you're hooking this up to a pot, connect one leg of the pot to ground, one leg to your analog supply, and the wiper to your A/D.

    On a serendipitous note... I also recently got asked about my PSX controller emulator by Julian Bleecker, who wanted to use it for his own project which interposes between a PS2 controller and the console in order to modify the analog joystick values. He was successful at using the emulator, and he even wrote a blog post which includes some sample code:

    www.nearfuturelaboratory.com/2008/07/09/psx-with-propeller/

    --Micah
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-09 23:51
    So this should work?

      'main loop
      repeat
        GREEN_PIN   := INA[noparse][[/noparse]12]
        RED_PIN     := INA[noparse][[/noparse]13]
        YELLOW_PIN  := INA[noparse][[/noparse]14]
        BLUE_PIN    := INA[noparse][[/noparse]15]
        ORANGE_PIN  := INA[noparse][[/noparse]16]
    
        IF GREEN_PIN == 1
          IF GREEN_FLAG == 0
            c_buttons &= BTN_L2
            GREEN_FLAG := 1
        ELSE
            c_buttons |= BTN_L2
            GREEN_FLAG := 0      
          
        IF RED_PIN == 1
          IF RED_FLAG == 0
            c_buttons &= BTN_L1
            RED_FLAG := 1
        ELSE
            c_buttons |= BTN_L1
            GREEN_FLAG := 0
          
        IF YELLOW_PIN == 1
          IF YELLOW_FLAG == 0
            c_buttons &= BTN_R1
            YELLOW_FLAG := 1
        ELSE
            c_buttons |= BTN_R1
            YELLOW_FLAG := 0
          
        IF BLUE_PIN == 1
          IF BLUE_FLAG == 0
            c_buttons &= BTN_R2
            BLUE_FLAG := 1
        ELSE
            c_buttons |= BTN_R2
            BLUE_FLAG := 0
          
        IF ORANGE_PIN == 1
          IF ORANGE_FLAG == 0
            c_buttons &= BTN_X
            ORANGE_FLAG := 1
        ELSE
            c_buttons |= BTN_X
            ORANGE_FLAG := 0
    
    




    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip
  • scanlimescanlime Posts: 106
    edited 2008-07-10 01:08
    You're forgetting to invert ("~") the bit masks when you turn off a button. Except for that bug (and possibly inverting the one bits and zero bits) this looks like it would work, but it's much more complicated than it needs to be.

    The most straightforward way to do this would be to build a bitfield using a local variable, then assign c_buttons once at the end of your main loop. Something like:

       repeat
         new_buttons := BTN_LEFT
    
         if ina[noparse][[/noparse]GREEN_PIN]
           new_buttons |= BTN_L2
         if ina[noparse][[/noparse]RED_PIN]
           new_buttons |= BTN_L1
         ...
    
         c_buttons := new_buttons
    
    



    It doesn't matter what values new_buttons takes on intermediately, as long as you assign to c_buttons only once.
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-10 01:57
    So new_buttons would be a long.

    I noticed that in Julian Bleecker's code he is setting the axis values using the same variable as the buttons (in my case "c_buttons").
    Is this how it is done?

    The whammy bar of a guitar her controller uses the "Left Analog stick's" Y value as the position of the whammy bar.
    So this will also need to be set in the repeat loop.

    Thank you, your code and assistance is appreciated. smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip
  • scanlimescanlime Posts: 106
    edited 2008-07-10 03:05
    computer guy said...
    So new_buttons would be a long.
    new_buttons can be a long on the stack, a word in the VAR section, etc. As long as it's at least 16 bits.
    computer guy said...
    I noticed that in Julian Bleecker's code he is setting the axis values using the same variable as the buttons (in my case "c_buttons").
    Is this how it is done?
    The emulator object just needs any arbitrary 18 bytes of memory. This can be a byte array of size 18, but it can also be a consecutive sequence of separate values: a word for the buttons, a 4-byte array for the axes, etc. It can be in the var section or the dat section. In my example, I used separate consecutively-allocated variables. In my example, the axes would be a different variable in the VAR section, immediately after c_buttons. That's one way of doing the job, but it isn't the only way.
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-10 03:10
    but how does the emulator know weather the data stored in the variable is for the buttons or the axes?

    Would this code work?
    emulator.add_state_buffer(@c_axes)
    
    c_axes[noparse][[/noparse]0] = $80
    
    



    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip

    Post Edited (computer guy) : 7/10/2008 3:17:05 AM GMT
  • scanlimescanlime Posts: 106
    edited 2008-07-10 03:14
    computer guy said...
    emulator.add_state_buffer(@c_axes)
    
    c_axes[noparse][[/noparse]0] = $80
    
    



    Thank you smile.gif

    Er.. not quite. Call add_state_buffer() only once, with @c_buttons. Then modify the values in c_axes. This works because c_axes comes immediately after c_buttons in memory. The emulator object actually treats the address you pass it as a pointer to an 18-byte buffer with the whole controller state.
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-10 03:16
    Ok so all I have to do is set.

    c_axes[noparse][[/noparse]0 to 3] to the value I want and it will do the rest?

    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip
  • scanlimescanlime Posts: 106
    edited 2008-07-10 03:19
    computer guy said...
    Ok so all I have to do is set.

    c_axes[noparse][[/noparse]0 to 3] to the value I want and it will do the rest?

    Thank you smile.gif

    Yup. Every time the Playstation polls your device, the emulator will read the necessary parts of your state buffer from hub memory- without any direct interaction from your Spin code. Go Propeller [noparse];)[/noparse]

    --Micah
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-10 04:31
    This has nothing to do with the emulator but is there an easy way to set a pin high for 10 seconds and then set it back to low inside of the repeat without it delaying the next repeat for 10 seconds?


    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip
  • scanlimescanlime Posts: 106
    edited 2008-07-10 06:43
    computer guy said...
    This has nothing to do with the emulator but is there an easy way to set a pin high for 10 seconds and then set it back to low inside of the repeat without it delaying the next repeat for 10 seconds?


    Thank you smile.gif

    If you have cogs to burn, you could start a separate Spin cog which sets the pin high, sleeps for 10 seconds, then sets it low. [noparse];)[/noparse]

    Otherwise, you'll need to know what this cog is doing 10 seconds into the future. It's impossible to always set the pin low *exactly* 10 seconds into the future if the cog will be doing other things, but if you can periodically poll ("Is it time to set the pin low yet?") while the cog is doing other things, you can approximate this kind of multi-tasking.

    In your simple button-polling loop, you could implement this by:

    1. When you want to set the pin high...
    - Set it high
    - Set a flag, to remind yourself that you need to set it low at some point
    - Save the current CNT value

    2. Then, periodically poll:
    - Is the flag set?
    - If so, subtract the current CNT value from the one you saved. Has it been 10 seconds yet?
    - If so, set the pin low and clear the flag.

    --Micah
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-10 07:12
    So would this do the trick?

        IF INA[noparse][[/noparse]STAR_PIN]
          new_buttons |= BTN_L2
          IF !star_act
            OUTA[noparse][[/noparse]STAR_LED]~~
            star_act := 1
            count := cnt
          Else
            IF cnt => (((clkfreq / 1_000 * 10_000 - 3932)) + count)
              star_act := 0
              OUTA[noparse][[/noparse]STAR_LED]~
    
    




    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip

    Post Edited (computer guy) : 7/10/2008 7:31:59 AM GMT
  • scanlimescanlime Posts: 106
    edited 2008-07-10 07:30
    computer guy said...
    So would this do the trick?

        IF INA[noparse][[/noparse]STAR_PIN]
          new_buttons |= BTN_L2
          IF !star_act
            OUTA[noparse][[/noparse]STAR_LED]~~
            star_act := 1
            count := cnt
          Else
            IF cnt => (((clkfreq / 1_000 * 10_000 - 3932)) + count)
              star_act := 0
              OUTA[noparse][[/noparse]STAR_LED]~
    
    




    Thank you smile.gif

    Looks basically fine, though that method of comparing 'cnt' won't do what you expect. You can't rely on the CNT register to monotonically increase- it will wrap every minute or so. It's better to do something like this:

       ten_seconds := clkfreq * 10
    
       repeat
          ...
          if (cnt - count) => ten_seconds
              ...
    
    
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-10 07:53
    Will try this and see how it goes.

    IF cnt - count => (clkfreq / 1_000 * 10_000 - 3932)
    
    



    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-07-10 08:07
    hello,

    Yes there is.

    You can do this with a variable that is used as a boolean flag

    VAR
      byte First_Loop
    
    
    PUB Main
    
      First_Loop := true 'initially it is true
    
      repeat
        if First_Loop
          First_Loop := false 'first thing to do is to set the flag to false so beginning with second loop the condition is false 
          outa[noparse][[/noparse]16] := 1  
    
    
    



    best regards

    Stefan

    Post Edited (StefanL38) : 7/10/2008 8:28:10 AM GMT
  • computer guycomputer guy Posts: 1,113
    edited 2008-07-11 07:06
    StefanL38,


    That would only work if I was repeating every 10 seconds.
    Check the previous page of this thread for code that I think might work.

    I don't need the delay to be exact, I just want an LED to light when a button is pushed and stay lit for aprox 10 seconds after the button is released.
    Without the delay having to temporarily stop the repeat.


    Thank you anyway. smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Check out my robot using the propeller RECONAUTOR
    If you like my avatar then check this out Propeller Domed Stickers for sale

    Building Blocks To The Propeller Chip

    Post Edited (computer guy) : 7/11/2008 7:11:18 AM GMT
  • StefanL38StefanL38 Posts: 2,292
    edited 2008-07-11 07:38
    hello cg,

    first of all i want to make a suggestion
    this question has moved far away from the PS2-issue
    how about starting a new thread ?
    timer-programming-techniques are of common interest
    but would never be expected in the middle of a thread about PS2-emulation

    back to the question

    aha i understand,

    now this could be done by comparing the actual value of the systemvariable cnt with
    a calculated value

     'pseudecode
      TimeSnapShot := cnt
      repeat
      ...
      if cnt >  TimeSnapShot + 10 Sec
        turn off LED
    
    



    There has do be done a little bit more because the cnt-variable wraps around from $FFFFFFFF to $0

    @the forum: what is the result of +-calculations that exceed the 32-bit limit f.e. $FFFFFFFF + 100 ?


    or second possability:

    if your speed-requirements allow this
    make a short waitcnt (maybe every millisecond) inside your loop and after every ms a variable is incremented.
    If it reaches 3600000 = 1h it will be reset to zero

    here is still a wrap around to zero but it could be calculated in 32bit

    if TimeSnapShot + 10 sec > TimeMax handle wrap around


    another concept could be to put the details of the timecomparing in a method ElapsedTime with a parameter TimeSnapShot
    here the value of TimeSnapShot is the "relative-zero"-point

    the method calculates the elapsed time in Milliseconds

     'pseudecode
      TimeSnapShot := cnt
      repeat
      ...
      if ElapsedTime(TimeSnapShot) > 10 milliseconds
        turn off LED
    
    
    



    these timerfunctions could be dedicated to its own cog
    then your mainloop stays faster

    and last but not least there is a timerobject in the obex

    obex.parallax.com/objects/45/

    it provides a clock with Milliseconds

    pseudo-code
    repeat
      if Button is pressed
        StartTime := rdReg(TMR_SECS) 'make snapshot if the seconds if button is pressed
      
      ActualTime := rdReg(TMR_SECS)
    
      if ActualTime - StartTime > 0
        if ActualTime - StartTime > WaitTime
          turn LED off
      else     
        if 60 + ActualTime - StartTime > WaitTime
          turn LED off
    
    
    
    




    best regards

    Stefan

    Post Edited (StefanL38) : 7/11/2008 8:00:30 AM GMT
  • computer guycomputer guy Posts: 1,113
    edited 2008-08-17 09:00
    With the PS2 would it be best to power the controller from the normal power out or the power for the vibration (feedback) motors.
    Which provides more current and what one will be able to power the prop, sd, i/o expander, 20 leds, and perhaps an xbee unit?


    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Building Blocks To The Propeller Chip A web site designed to help people who are new to the propeller chip.

    Guitar Hero controller using the prop (WIP) --> HERE
  • scanlimescanlime Posts: 106
    edited 2008-08-17 23:05
    computer guy said...
    With the PS2 would it be best to power the controller from the normal power out or the power for the vibration (feedback) motors.
    Which provides more current and what one will be able to power the prop, sd, i/o expander, 20 leds, and perhaps an xbee unit?


    Thank you smile.gif

    I'd recommend using the motor power supply, and regulating it yourself. The 3.3v power rail actually isn't quite 3.3v: it's more like 3.6v if I remember right. I also don't know how much power it's rated for. Normal controllers only draw maybe 10mA at most from the 3.3v rail, and the Prop could need a good bit more than that.

    The motor power supply is basically connected directly to the PS2's power brick, which is at about 7v. It can source plenty of current, but do be careful- i managed to blow the fuses on my PS2 multiple times while developing my Unicone2 device [noparse]:)[/noparse]

    If you do blow the fuse, it's not that hard to replace- it's a 0-ohm SMT resistor. You can follow the traces from the controller ports on the PS2 circuit board to find it.

    Good luck,
    --Micah
  • computer guycomputer guy Posts: 1,113
    edited 2009-01-18 05:28
    @Micah Dowty,

    Hi again.
    I have connected a ps2 cable up to my prop and loaded a test file.

    
    c_buttons := $FFFF
    bytefill(@c_axes, $80, 4)
    bytefill(@c_pressure, 0, 12)
    
    emulator.start(CONTROLLER_PIN, -1, emulator#CONTROLLER_DUAL_SHOCK)
    emulator.add_state_buffer(@c_buttons)
    
     c_buttons &= BTN_X
     c_axes := $80
    
    
    



    When I turn it on whilst in the ps2 menu it does nothing. The second controller I have plugged in will only let me press "X".
    If I change
    
    c_buttons &= BTN_X
    
    



    to

    c_buttons &= BTN_TRIANGLE
    
    



    than I can only press triangle.

    I have tried
    c_buttons |= BTN_X
    
    


    but it does nothing.

    If I use
    c_buttons &= ~BTN_X
    
    or
    
    c_buttons |= ~BTN_X
    
    



    the propeller tool says "expected a variable".


    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Building Blocks To The Propeller Chip A web site designed to help people who are new to the propeller chip.

    Guitar Hero controller using the prop (WIP) --> HERE
  • scanlimescanlime Posts: 106
    edited 2009-01-18 22:18
    Hi Computer Guy,

    I'm assuming your value of BTN_X is $4000, right?

    In that case, the code you posted will actually press every button except X!

    The 'buttons' word is a bit field, each button is assigned one bit. A '1' means the button is not pressed, a '0' means it's pressed. So the default value of $FFFF means all buttons are up.

    The BTN_X constant is a mask, which tells you which bit corresponds with the X button. $4000 has one bit set, and that bit is in the position corresponding with the X button in 'buttons'.

    So, to press the 'X' button, you need to set its bit to zero, and to release it you need to set it to one. To set the bit you can bitwise 'or' it with the mask. To clear the bit, you can 'and' it with a mask in which every *other* bit is one, but the bit you want to clear is zero.

    So to press the X button, you should be able to do:

    c_buttons &= !BTN_X

    and to release it:

    c_buttons |= BTN_X

    Sorry about the "~" syntax earlier- that's how you do a bitwise 'not' operation in C. In spin, it's just '!'.

    --Micah
  • computer guycomputer guy Posts: 1,113
    edited 2009-01-18 22:52
    Thank you Micah. smile.gif

    Works great.
    I think I tried every bitwise operation except that.

    I even tried
    c_buttons &= NOT BTN_X
    
    


    out of frustration.

    Thank you smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Building Blocks To The Propeller Chip A web site designed to help people who are new to the propeller chip.

    Guitar Hero controller using the prop (WIP) --> HERE
Sign In or Register to comment.