What's new
I will test that out and let you know - hopefully this weekend.
I was able to run a quick test today on WMMT with a physical reader.

The behavior isn't quite what I remembered. The game simply asks you to insert a card if you have it. The alternative is to move the cursor over to the Purchase New Card option and hit the gas pedal to activate it.

It will time out and select purchase card if you don't insert anything. So the script simply needs to not insert a card when the card file is blank.

As a test, I did try to insert a blank card. The game didn't like it and ejected the card with a read error, indicating I should check to make sure it was inserted properly. Anyway, the script doesn't need to handle that scenario. It just needs to not allow for it.
 
What occurs at my work here is that someone will hit the accelerator (because it defaults to "yes, I have a card)... and the way it's setup up right now - you select a card to enter - and until you do that, the process isn't running... so - with no process running, it times out with an error and stays on that screen until I get in a few days later (burn in!!! no!)

Either a process that just simulates responding to "status" commands can be run when an actual card isn't selected (maybe the easier way) or logic in the main program that has a concept of 'no card is loaded' - but I think the first idea would be easier - and just control it from a process perspective.

Matt
 
What occurs at my work here is that someone will hit the accelerator (because it defaults to "yes, I have a card)
I was thinking I was observing that hitting the accelerator on "yes, I have a card" isn't actually doing anything. I'll have to double-check. I don't think it would make sense to have the accelerator activating anything because inserting a card is the answer to the question of whether or not you have one. I would imagine the script is either not sending a reply as if there's no card, or it's trying to insert a blank card.

It's been so long since I've had this stuff actually hooked up, I'm having to relearn some things.

At the moment, I've got a script intended for continuous running, so it's always sending replies, and card files are simply managed by updating a text file with the card name. Once the script sees that a card is in use, it no longer polls for changes in card file name. Once it ejects, it polls for card file name until it is in use.

The other thing I've got implemented is a concept of a default card file if a game is started without actually giving a card file name. This default file is then used and ultimately deleted. I haven't personally tested on my side to see how it's handling the case we're discussing.

The frontend would only need to update the text file that houses the current card file name.
 
I think it will allow for a no card loop with nothing inserted. I would guess it times out at some point.

I'm more curious what happens if you take a blank card from the hopper and try inserting that during the time you tell the game you have a card.

However, you bring up a good point. Perhaps the script just simply shouldn't "insert" the blank card.
this seems like the best solution as it prevents the player from playing with out their data and having to start a new default car that would be wiped.
 
I think it will allow for a no card loop with nothing inserted. I would guess it times out at some point.

I'm more curious what happens if you take a blank card from the hopper and try inserting that during the time you tell the game you have a card.

However, you bring up a good point. Perhaps the script just simply shouldn't "insert" the blank card.
this seems like the best solution as it prevents the player from playing with out their data and having to start a new default car that would be wiped.
As I've been thinking through the workflow, the default card file is necessary because the script cannot prevent someone from telling the game they want a new card. The script has no control over that. That's the game assuming there are cards in stock, because the script tells it so, so it will allow you to purchase one even if you don't specify a card file name. In that case it needs some way to go through the motions when it gets a command to write data.
 
also cant tell the system it is out of cards because the game would have to have a reset of the card reader in the test menu to fix the issue. ok remembering now.
 
From my recent testing in WMMT, the card workflow is:

Start game
Do you have a card? - If yes, insert card, if no move wheel to no and hit gas.

If no - do you want to purchase a card: yes or no: If yes, game establishes a new card - if no, there is no card established.

So far, my limited testing with the script that uses a temporary default file, it is working for the scenario where no card name is given to the script and a game with new card is started.

The default could be handled a couple of different ways:
1. The same filename keeps getting used over and over, and the file is deleted after use. This is how it currently is. If the person started without interacting with the frontend, then its likely they wouldn't know how to claim a card.
2. The default name iterates (i.e. default.car1, default.car2) and keeps generating new files.
2a. The frontend could allow some means of claiming a card by simply renaming it. You would know the highest number is the file you last started.
 
if eventually going with 2 or 2a would it be possible to have the "device" delete the excess default cars on reboot or boot up?

I like option 1 so far because it doesnt leave a paper trail that would have to be cleaned up every so often.
 
if eventually going with 2 or 2a would it be possible to have the "device" delete the excess default cars on reboot or boot up?

I like option 1 so far because it doesnt leave a paper trail that would have to be cleaned up every so often.
Let's assume this is running on a Raspberry Pi. It would be feasible to set up a scheduled process (weekly, daily, whatever) that cleans out files with a given name.

So far I like option 1 since I've got it working. :P
 
to speak specifically to the card flow from the machine's point of view, here are the things that happen with NAOMI-based IDAS.

the available options are dictated by the previously polled card hopper state [such as, don't suggest that a card can be purchased when the hopper is empty]. this state is polled upon each attract loop, at the segarosso logo.

machine prompts "do you have a card?"
have a card:
machine prompts "insert card"
machine polls the CRW for sensor state [0x20], checking the status bitfield for card position
if a card is detected at the right position, the CRW is instructed to pull in the card, then close the shutter [0xD0]. once loaded, magnetic data is read [0x33]
if a card is not detected at the right position, the CRW is instructed to close the shutter [0xD0], and new car selection begins

don't have a card:
CRW is instructed to close the shutter [0xD0]
machine prompts "do you want to purchase a card?"
yes:
requests a blank card from the hopper [0xB0] and positions it within the reader
new car selection begins
racer data entered
no:
new car selection begins

some time ago, i spent a good bit of races on my machines, performing game changes [IDASv1 to IDASv2, IDASv2 to IDASv3] with different regions. this testing and racing led me to modify the script in several ways. i don't claim to write python, so, some things [like creating the right bitfields on the fly to CRW state] aren't done in a mature way. i'm a sysadmin, not a programmer. i did, however, analyse the SANWA documentation in regards to how the bitfields and commands were used on the CRP CRW windows DLLs. lots of commands explained in the SANWA documentation, which further explained what the script was doing.

list of things this script now does in comparison to the original:

a bit more CRW state tracking. whether or not the shutter is open or closed, whether or not the card moved within the reader, whether or not a card is busy, or waiting. the game reading the CRW state now does not "virtually" have the shutter and card in wrong positions from read to read. state is more consistent.

annotations of the script commands, so that it is clear what these commands are doing, and what they mean.

when an empty file is supplied to it, the card flow does not assume when the game is talking to the CRW that it now needs to start simulating CRW actions of a new card [which led to a confused script, and a pissed off game]
when an empty file is supplied to it, and the racer elects to not purchase a card on that game launch, the card flow does not get lost and keep expecting a new card to have been requested. a new game launch will re-present the same choice, because the card flow preserves that there was no card loaded from hopper or inserted into it, same as a normal CRW.
when 0x7A [CRWRegisterFont] commands are received, reply appropriately, ingesting the supplied font payload data [not currently saving it for future rendering/use]. this is needed when doing multiple font bank changes when writing to a card face to update.
when 0x7C [CRWPrintL] commands are received, reply appropriately, simulating printing onto the card face. previously, if you had the nerve to race and complete multiple courses on one play [akina and akagi, for example], the script wouldn't know how to handle multiple print commands, and the code would freak, resulting in the game erroring out. not knowing how to rescue where the game thought the CRW should be resulted in losing your gameplay.
the script can now complete the CRW test within the settings menu on all versions! caution, supply a blank file, because it will load a new card from hopper and overwrite.
the script can now complete the CRW clean within the settings menu on all versions! enters a special card clean loop when command 0xA0 [CRWCleaning] is requested. some JP games, upon game change, will block game start, saying a card cleaning must be done, and won't allow boot to continue. [had to hastily implement this when trying to play IDASv1 JP for the first time]

card migrations work! card renewals work! this required significant decoupling of magic sequences within the script to break them out more into specific CRW function calls. flows such as "CRWRegisterFont, CRWSetPrint, CRWPrintL, CRWDischargeCard, CRWTakenCardDispenser" now all work appropriately. tested all forward migrations to all versions in all regions. tested card renewals on all versions in all regions. this includes migrations with pending renewals.

it took so long for me to even write this message because this code still isn't done. life and work has gotten in the way many many times. i have a CRW implementation in progress for an ATMega-based board, to allow a small board to track all of the CRW logic, and the only thing a computer would have to do is push and receive card data to the board. there's still too much magic in the code.

i attached both the SANWA CRP DLL documentation [6806A05.pdf], along with a version i forced through google translate [6806A05_translated.pdf], to better understand what we were doing and why.

i get that this version may have diverged quite a bit from what people are trying to do personally. sorry. hope this helps.

i had video/image logged a bit of this development on my instagram, b0psaturnnights. lots of NAOMI/system 573 testing on there [along with some car stuff].
 

Attachments

  • ID3CARDEMU_rewrite.zip
    5.4 KB · Views: 112
  • 6806A05.pdf
    262 KB · Views: 112
  • 6806A05_translated.pdf
    548.1 KB · Views: 136
@saturnnights - Awesome! Yes - the original ID3 card script was junk. I was going to retool it after everything I've learned with the others. I'll definitely check yours out. Thanks for sharing!

The one I have for ID4-8, which I haven't released publicly, is the one where I think I got it right. It manages the sensor bits and even has the capacity to successfully reply to commands even if I never logged them (i.e. builds out a reply using the command code plus status replies).

At the moment I'm building up a RPi server with a frontend that manages card emulators and netbooting. I've got WMMT integrated so far, and will be retooling and incorporating the other scripts into it.

@saturnnights, am I remembering that you're the one who was attempting to interpret print commands? That's a goal of mine. I'm in touch with someone who is able to provide me with many of the unique cards available for ID1-3, WMMT1-3 and Mario Kart. My idea is to scan the cards and use them as a background behind an image generated from print commands.

In other news, I will hopefully soon have my hands on WMMT3 and card reader to put together a script for that game. :thumbsup:
 
Hi @winteriscoming - I have a full set of cards for WMMT as well as MK that I can scan and send you - if you don’t get them from your other contact.
 
Here's a scenario I think I've gotten myself into:

The user accesses a web-based frontend and basically is just establishing a card file name that the script will use when reading and writing data as needed.

As soon as an eject command is issued, the in-use card file is saved and the script reverts to a no card in use state. After that, if someone starts a game without establishing a card file to use, the script goes on to write to a temp file that will be removed.

A bad scenario comes up from a card transfer process. The game essentially ejects the card (script will revert to temp file) and then writes data to a new card (i.e. script would likely write new data to the temp file).

My prior scripts simply kept the same filename in use until the script was restarted.

I don't want to leave it up to users to manually swap in-use card files, because the next person who plays the game without interacting with the frontend will end up using the previous user's card.

A crude solution might be to set up a timer after initial eject and the in-use card name is purged after the timer. I'll have to check logs, but I doubt I'll be lucky enough that there's a unique command sequence for transfers that differs from an eject and starting new game with new card. I suppose a difference would be that in a transfer, there's no polling for an inserted card.
 
What if you had a 'key'? So let's assume you have multiple users playing. Before your script starts, could you load a user profile, this way if the user profile matches, use the same card, if it doesn't, you create a new temp card? Or will the timing on the card load script not allow this kind of validation?
 
What if you had a 'key'? So let's assume you have multiple users playing. Before your script starts, could you load a user profile, this way if the user profile matches, use the same card, if it doesn't, you create a new temp card? Or will the timing on the card load script not allow this kind of validation?
In thinking this could end up in a more public place, I'm not sure what approach to take. I had thought about user profiles, but there may be a simpler route without having to manage a user database and user admin (i.e user forgets password if passwords are required).

The pages are PHP, so there's the potential to store a cookie (perhaps a randomly generated value) on the user's browser. Then the frontend authenticates against that cookie and reserves the seat for that user and manages which card file will be used. That card file stays in use until the user gives up the seat. There would have to be a contingency, maybe a timeout period after eject if the user walks away without logging out (clear the cookie) where the seat would open up again for use by another user.

I just don't want to get too complex. At the moment, any user would have access to load up any card.

I may want to reserve seats anyway so multiple users aren't accessing the same instance of the script for a given cabinets, but there may ultimately be a simpler way for the script to know it's doing a transfer rather than ejecting and ending the game. At the very least, I think transfers happen at the beginning of the game, so perhaps a timer between card insertion and eject would suffice. If the card is ejected very soon after being inserted, either it's an incompatible file being reject right away, or it's likely a transfer, and the script can keep the same file in-use. I'll have to set up a test scenario for this.

For the moment, I'm just focusing on figuring this all out for wmmt prior to expanding to the other card scripts. I recall with WMMT I was able to rewrite the counter on the file, so that would be one way to avoid the issue, but I'd rather figure it out because I don't think I can do that with the card files from the ID series.
 
Another idea I just had is to perhaps make the user interact with the frontend to better replicate the physical experience. For example: the game ejects the card, but the act of removing the card requires the user to do so from the frontend. The user might be presented with options that are applicable to the situation: take card and leave or take card and choose a different file to use immediately after eject. That might be the simplest solution to handle all possible scenarios. You'd just have to be an educated user to know which scenario is required. If you're doing a transfer and choose take card and walk away, your new transfer data is going to get saved to a temp file that gets deleted. If you're doing a transfer and choose take card and use a different existing (or even the same) file, then that chosen file is going to be overwritten with new transfer data.
 
When a card is migrated or renewed, the old card is ejected. Before that, a print command is sent that prints INVALID on the card face. That would be one way to know whether or not to swap. Check the last print before eject.
 
That's going to depend on the game, but it's a good point. If I interpret last print command and I know what a given game prints on an expired card, I can react accordingly.

WMMT3 is my next target for scripting and that one seems to have a complex workflow that allows expired cards to be used to create new cards, and there's the concept of creating a Present Card that can be gifted to someone to give them a good starting vehicle. That one's going to be fun to figure out!
 
Back
Top