djhackersdev / bemanitools

Runs recent Konami arcade games and emulates various arcade hardware.
The Unlicense
84 stars 16 forks source link

Add Nostalgia support #69

Open icex2 opened 3 years ago

icex2 commented 3 years ago

In GitLab by @shtokopep on Dec 7, 2020, 22:30

Summary

Add support for Nostalgia games

Detailed description

Self explanatory

Benefits

Good game

Drawbacks

?

Current blockers

?

icex2 commented 3 years ago

In GitLab by @shtokopep on Dec 7, 2020, 23:18

I opened this as a pretext to share the bits of reversing I did when I wrote my nostalgia arduino firmware, as I think some of that info should be useful for future support (even though it's far from enough as this only covers the acio part of it). At first I wanted to try to implement the acio bit but I'm not sure how to proceed given some aspects of it (which i'll recapitulate in Blockers)

I/O

I/O is comprised of two ACIO devices :

Only COM1 needs additional code, then, since PANB emu is not there yet :

ACIO commands to PANB are always sent to node number 1, the dispatch is done by the keyboard itself

Sending commands

Should be the same as other acio devices but i'm including it in case it is not, as I have little experience with other acio stuff :

size (in bytes) : 1           1            2      1         1    NBBYTE    1 
contents        : AA [00 || node number] [CMD] [SEQNUM] [NBBYTE] [DATA] [CHKSUM]

CMD   : 2-byte command identifier (0001 for assign addrs (enum), 0002 pour get version, etc..)
SEQNUM: sequence number, starts at 1 and is incremented every time a command is sent wrapping the range [0x01;0xFE] (*note*: AA is escaped (0xAA -> 0xFF 0x55)) 
NBBYTE: number of subsequent DATA bytes (not including escape bytes)
CHKSUM: usual acio checksum (lower byte of sum of all received (non-escaped when applicable) packets)

setting lamps

acio command is SET_LAMP (01 11) followed by 84 bytes of data (28 keys from left to right : red[0-255] then green[0-255] then blue[0-255] ).

Note: this command doesn't seem to trigger any reply from the keyboard, just a seqnum that will be incremented in the next polling data messages (more on that later).

polling button state

this is where it gets a bit different from what I've seen so far :

acio command AUTO_INPUT (01 15) is sent only once, with a parameter, which triggers some kind of "auto poll" where the keyboard will then keep sending us 01 10 commands followed by a certain number of bytes depending on the parameter passed with the 01 15

The game sends 01 15 xx xx 04 (to poll the 4 nodes), then the keyboard starts spamming 01 10 followed by 16 bytes of data :

size (in bytes) :     1           1         14
content         : [S_SEQNUM1] [S_SEQNUM2] [BUTDATA]

So, with the rest of acio protocol overhead, that gives us packets formatted like this :

AA [81] [01 10] [SEQNUM] [10] [ [S_SEQNUM1] [S_SEQNUM2] [BUTDATA] ] [CHKSUM]

SEQNUM   : always equal to the received SEQNUM **at the time of the AUTO_INPUT (CMD 01 15)**
S_SEQNUM1: equal to last received SEQNUM (for example, via a SET_LAMP (CMD 01 11) )
S_SEQNUM2: this is the actual auto increment sequence number (one that starts at 00 and keeps growing with each packet)
BUTDATA  : each byte encodes a pair of keys, high nibble for the first key velocity, low nibble for the second key velocity (**note**: high nibble only goes from 0x0 to 0xE whereas low nibble goes from 0x0 to 0xF)
CHKSUM : usual acio checksum (lower byte of number of received packets (not including escape bytes))

Current blockers

Current acio emulation code has a "one request directly expects one reply" structure. We should split these and be able to handle incoming unsollicited packets.

Current acio emulation code doesn't read the packet size from the incoming datagram, but uses prior knowledge to pass it as parameter during the "send_and_receive" call (can be easily fixed by reading the 5th byte during reception, but I'm not sure if that'd break other acio devices which might use a different format?).

Current acio emulation code expects the reply to use the same command number as the request, which isn't the case here (send 01 15 once, receive 01 10 multiple times).

There are 4 nodes but the game code really only communicates with the first one, seems like the keyboard does the dispatch internally so I'm not sure how it is supposed to work on btools, haven't seen internal node communication before.

icex2 commented 3 years ago

I am really glad that you reached out to us here, opened an issue and shared all the information. That is definitely appreciated by whoever is going to pick this up.

We will follow up regarding your blockers with more information.

icex2 commented 3 years ago

In GitLab by @xyen on Dec 7, 2020, 23:41

The primary issue with Nostalgia (and Museca) support isn't REing the protocol (although this is very helpful) but the lack of better analog support in geninput, and MIDI.

For the blockers themselves, the acio packet size thing is a known issue, and I have a fix WIP to fix it for aciodrv (I can probably also fix acioemu, but your noted fix is more or less correct).

As for the multiple receives, this would require a re-architecture of how packets are handled in acioemu (ie. instead of expecting a request-response pair, you register handlers for packet type / device pairs instead). This is something I'm in the process of doing for aciodrv, but it won't be directly applicable to acioemu, due to the intricacy of how the IO emulation layer is designed. That being said, I have some ideas for how to design such a system, without needing to re-write the rest of the existing emulation code.

If possible, could you join the DJH Dev discord? (we'll need your discord username)

icex2 commented 3 years ago

In GitLab by @shtokopep on Dec 8, 2020, 10:28

I see about geninput.. and this is cool to hear the multiple packet receive was already under the radar :) Oh sure, didn't know there was a discord, my username is CrazyRedMachine#1421