What's new
It's not entirely clear to me if you want to be master or slave, but let's assume you're a slave (IO board).

Sense is point-to-point, from the wiki :) "The slave that picks up the request sends an ACK back to the master, and pulls it’s output sense to 0." . Se when you are offered a node id, send an empty ack back to master and pull the sense line low. That way the master knows there are no more IO boards on the bus.
Also incredibly important when doing this stuff is to control the DE/RE pins, you need to switch back to read immediately after the bytes are on the wire (FIFO empty) - it could be that the master is actually trying to send stuff, but you're not picking it up.
 
let's assume you're a slave (IO board).
Yes, this is the case. I want to make an IO board.

I don't think making a master is necessary, since if I wanted to poll digital and analog switches, I could just do that when they're wired up to the Arduino without any JVS protocol, and pass the values on to a PC.

Also incredibly important when doing this stuff is to control the DE/RE pins
I've currently got it driving the DE/RE pins high whenever a byte is sent and bringing it low directly after.

This is actually different in my code from the TeensyJVS as the Teensy apparently has a built in transmitterEnable feature of a serial port where you just define pin that drives it, and I guess the hardware takes care of the rest. This is apparently not available in the Mega 2560, so I've been manually driving the output by making it high or low accordingly, defaulting to low unless transmitting.

Se when you are offered a node id, send an empty ack back to master and pull the sense line low.
I'll play around with the order of operations for this. Since I'm driving DE/RE differently and handling Sense in a different way from TeenyJVS, I may be doing something incorrectly.
 
I've currently got it driving the DE/RE pins high whenever a byte is sent and bringing it low directly after.
Are you sure, as in - do you check that the fifo is actually empty, or do you just switch to read after the command that fills the fifo is done - in which case you will be corrupting your own packet. I did this :)
 
Worst-case scenario: I buy a freakin' $25 Teensy 3.2 and get the stock TeensyJVS code running on the hardware it was programmed for, and work from there. :P

The Teensy has a 32-bit processor vs the Mega's 8-bit... However, I like the footprint of the Mega and all the I/Os and analog ports available... I see there's an Arduino Due with a 32-bit processor, with the same footprint and pins as the Mega, though I'd likely be in the same boat having to manually drive DE/RE pins and I think I'd be working with 5v TTL and have to handle sense the same way I need to with the Mega.

All-in-all, I'd expect the Mega to be up to the task, but I can't say for sure that it is.
 
Are you sure, as in - do you check that the fifo is actually empty, or do you just switch to read after the command that fills the fifo is done - in which case you will be corrupting your own packet. I did this
Well, I've apparently got some learning to do... :whistling:

Thanks for the advice!
 
Great news! I've got the Mega communicating with the Chihiro as an IO board! 8o
do you check that the fifo is actually empty, or do you just switch to read after the command that fills the fifo is done - in which case you will be corrupting your own packet. I did this
So apparently this was the issue. In the TeensyJVS code, ACKs are built into a byte array, and when transmitting, the code is just looping through that array. I changed it so that DE/RE output pin is high at the very beginning of the loop and low at the end after a 5ms delay. I'm honestly not sure what else to do here to manage this better, but it seems to be working now. Thanks a ton for the advice!

I'll have to play around more with the Sense line because I'm back in the setup where I have one 5v output divided into 2.5v, sitting on the Sense line with another driving a MOSFET to pull Sense to ground. It seems to be the case, but I'd have to do more testing, that the Main Board wants 2.5v on the line during Reset command, and then pulled low during Set Address. What I'm not sure of is if it's necessary to pull it to ground or if it's sufficient to just have the 2.5v output set to low. I'll also confirm if its actually needing any voltage from the IO board on the Sense line or if it's sufficient just to not pull it low during reset and pull it low during Set Address. There's definitely a voltage being generated on the Sense line from the Main Board, so maybe it's not necessary to generate one and I'm over-complicating it?

The other semi-issue that I'm seeing is that the Chihiro isn't picking up the board name. That string is sitting blank in the JVS menu. Again, I'm still on relatively stock TeensyJVS code, so I haven't changed the way the name is being sent. Currently it still has the default value of:
ReplyString("www.github.com/charcole;A Teensy JVS IO Device;Version 1.0;Charlie's JVS emulator");

I'll dig into that some more.

I'm very pleased to have made it this far! :D


Next steps are ensuring digital switches are registering and then expanding to analog input and lamp outputs.
 
maybe it's a limitation of certain specific implementations of the spec? I seem to recall in my testing the NAOMI not recognizing more than 4 nodes.
It occurred to me that this limitation may exist, not due to the spec, but due to frequency/speed of polling. I can't recall off hand where I read it, but somewhere indicated that an I/O board might be polled 60 times a second. I suppose it's possible that polling a bunch of boards each 60 times a second would become infeasible.

If the 60 times per second rule is relatively true, with 1 board, that allows about 16.67ms to send each polling command and get a response, if my math is correct. Assuming the main board has to wait for an ACK before sending a command to the next board, with 4 boards, that's about 4.17ms per board. I'm not sure how fast all of this is able to happen when sending a command and getting a reply, but it does seem like eventually you'd need to be polling faster than the command could be sent and the reply generated and received. So, sure, up to 32 nodes including main board may be possible within the RS-485 spec, but I'd expect the communication frequency would have to be slowed down, maybe slower than would be ideal for arcade controls. Thinking about my current code, I've got a 5ms delay after my reply, so even 4 I/O boards wouldn't be possible with that coded in.
 
Regarding the transmission buffer, this sounds like it might be a better way of handling it:
https://www.arduino.cc/en/Serial/Flush


Description
Waits for the transmission of outgoing serial data to complete.
I would guess I could call this, instead of my arbitrary and perhaps too long 5ms delay, and it would delay only as long as necessary to transmit, and then set it to turn off DE/RE. I'll give it a try.
 
I guess it's important to flush! :P

Apparently my arbitrary 5ms delay was not long enough to transmit the name.

Test screen.png
 
Ok, so I think my latest test confirms that Sense just needs to be pulled to ground during Set Address. No voltage needs to be applied to it. I had my 2.5v output turned off. The only potential factor at this point is that the Sense is still connected to a 10k ohm resistor (half of the voltage divider for the 2.5v output) to ground. This may come into play because the first diagram I posted, showed the Sense line going through 4 diodes to ground OR the transistor driven by an output. In this case the 10k ohm resistor might be standing in for the diodes, if the main board in fact cares about this. I can test by removing that resistor. Unfortunately I'm all soldered in to a perf board, which makes changes no fun... I need to transfer all of this to a breadboard during these testing stages.

I have so far confirmed I can get switches to read, and I have added P2 to the features.
 
I worked on this a bit more today and have figured out integration of a test switch (i.e. the switch to get into the service menu). This is an aspect that I haven't seen, or I missed, in the few open source JVS projects I've come across. I guess they were not interested in test and service buttons in favor of the on-board buttons due to using the motherboard in a more consolized fashion.

I'll do my best to document my findings as I go for anyone interested in the info.
 
Great work winter. :thumbsup:

I'll do my best to document my findings as I go for anyone interested in the info.
that would be awesome. as this project will more than likely help me in the future with a homebrew card reader for the TTX
 
Well I had a nice thorough digital input rundown typed up here, but my browser bugged out and a draft apparently didn't get saved.... I don't have a ton of motivation to type it all up again from scratch at the moment.

Here's a translated switch input chart:
JVS input chart.png


Here's the type 1 JVS I/O digital pinout. The orange box shows the P1 and P2 switches, each with 13. The green shows the System switches that are not associated with a player.
JVS Type 1 digital pinout.png


The chart shows an example where the I/O has 14 switches (or 14 bits) per player, but the Type 1 I/O has only 13, so button 8 can be ignored in the chart. Otherwise the chart aligns with how the switch input data needs to be reported. When replying to a command for switch inputs, Byte 1 contains the system switches, including test. Bytes 2 and 3 are P1. Bytes 4 and 5 are P2.

Coins are handled in a separate command and acknowledgement and are not treated as digital inputs.
 
Here's a bit of supplemental info I had typed up before to kind of pull it all together with regards to the digital inputs.

When the I/O board is initialized, one of the things that happens is the motherboard requests the features of the I/O board so that it knows what it can expect from it. For example, if you reported that the I/O board has no analog inputs, then the motherboard would know not to bother sending an analog read command to the board, but a game may very well require analog inputs so it would likely generate an error that the I/O is incompatible.

One of the pieces of information sent during the feature reply is the number of players and bits (or buttons) per player. This is something that can be viewed on the JVS Information menu in the test menu. The Type 1 I/O shows up as 2 Players 13 bits.

The motherboard then frequently sends a read digital inputs request and the board replies with byte or 8-bit chunks. If we're saying that a player has more than 8 bits of data, then the motherboard would know that the overflow would come in the next byte.

So, like what is shown in the chart, the reply to a digital input request involves sending bytes of data, where each bit within a byte corresponds to a specific input.

Some examples:
For player 1, if button 1 was the only input triggered, the 2 byte reply for it would be:
00000001
00000000
This would be displayed on the Player 1 input test in two Hex bytes as:
0100

If start is the only button hit, the reply would be:
10000000
00000000
This would be displayed on the Player 1 input test in two Hex bytes as:
8000


If start and button 4 are hit, the reply would be:
10000000
01000000
This would be displayed on the Player 1 input test in two Hex bytes as:
8040

My assumption based on the chart is that if you had 8 bits or less, the motherboard still expects switch inputs to be designated per the chart, so if you reported that there are 8 bits per player you'd be limited to Start, Service, Up, Down, Left, Right, Button 1 and Button 2. If you wanted to implement a solution that used only Start, Up, Down, Button 1, Button 2, and Button 3, you wouldn't likely be able to do that in a single 8 bit chunk due to the way the bits are assigned pre-determined values. In the event that you wanted to use Buttons 1-3 and nothing after 3, you would tell the motherboard that you have 1 player (or 2 if you want) with 9 bits, and for any button that you are not using, just report a 0 for it. You would still have to report the data in 2 separate byte chunks.

The System inputs are the Test and 3 Tilt switches. The Type 1 I/O only has 1 Tilt switch, so I assume it just responds with 0's for the non-existent switches. I don't believe the system switches are configurable in the features reply so the motherboard probably expects an appropriate reply for these in the first byte that is sent, regardless of whether or not the switches exist. If you were implementing a solution that does not have a test or tilt switch, you would just reply with 0s in byte 1. I won't be mapping a tilt switch since I don't care about it, but I do have a test switch so I can get into the test menu.

So when we have 2 players worth of data at more than 8 bits each, we have to reply to a read digital switches command with an acknowledgement that includes the following in order:
Byte 1 - System Switches
Byte 2 - P1 1st part
Byte 3 - P1 2nd part
Byte 4 - P2 1st part
Byte 5 - P2 2nd part

Note that the service button ends up in P1's set of buttons. There's actually one for P2 as well, but I would guess many cabinets don't have it wired up. So the Test input is located in the system input section of the reply, but the service ends up in byte 2, P1's first set of switch data.

So what happens in the Arduino code is that you simply designate pins as the various inputs, and when requested for digital inputs, just read through your switches and reply with the appropriate bits according to the chart. Any input that is triggered gets a 1 and any that are not get a 0.

When I get to the point of having dynamic button mappings, it's really just going to be a matter of reporting the correct bits in the right spots for the game I'm booting.
 
Somehow I'm getting a draft restored now, so here's the original digital switch info I had typed up:


JVS I/O Lesson 1: Digital Switches

Note that my understanding of things could be incorrect, but I'm reporting what I am seeing and how I am understanding it.


Here's a translated chart from the Japanese PDF linked to in an earlier post:
index.php


When a JVS I/O board is initialized the motherboard asks for a feature set so that it knows what the board is capable of. One of the parts of the reply to the feature request is to indicate how many players and how many bits of data per player. This allows the motherboard to know what is coming in when the i/o board reports switch inputs.

The Type 1 Sega I/O has 2 Players with 13 bits. This is something that can be seen on the JVS Information screen in the test menu.

Here is a pinout of the digital connector on the Type 1 board. The pins surrounded in orange are the inputs in question. The top side contains 13 P1 inputs and the bottom side contains 13 P2 inputs. Each pin is counted as a bit in a binary number. 1 is on, 0 is off. So that equates to 13 bits per player. The pins surrounded in green are special System input pins, not associated with a player. The motherboard just assumes these are present and expects them to be included in requests for digital inputs. The couple of open source JVS projects handle these system inputs by just replying with 0s. *Note that coins are not included as part of the switch inputs.





So if you look at the chart and the pinout, there's a correlation. Though the chart shows an example where P1 and P2 have 14 bits. The Type1 I/O does not have a switch 8 for P1 and P2, so let's ignore that one.

The JVS I/O replies to switch commands in bytes or chunks of 8 bits.

Per the chart above, you can see that first row represents byte 1 and includes Test and 3 Tilts. In the case of Type 1 I/O, there is only one tilt switch, so it would likely only report a 1 for one of those values if the tilt switch was activated and report a 0 for the non-existent ones. I don't care about tilt, so I don't have any plans to investigate it further and integrate an actual switch for it. I'll be replying 0 for all tilt bytes. I do, however, want a Test switch to be able to get into the test menu, since my implementation is an I/O replacement in an actual cabinet. Therefore having to go to the back of the cabinet to push a button on the motherboard just to get into the test menu would be a pain.

The 2nd row is byte 2 and includes the first 8 bits of P1 switch data. Since we've got more than 8 bits worth of data, the rest go into byte 3 on the following row.

Then P2 data would be in bytes 4 and 5.

Notice how the columns are labeled starting from the left with bit0. This is the order each bit must be reported to be registered as the associated input. In the first row, according to chart, the Test switch is the left most bit. So in the event that the Test switch is triggered, the reply for byte 1 would be 10000000. When you go to the JVS input test in the test menu and push the test button using the Type 1 I/O, you can see a hex value for the System showing 80. So whenever my designated Test switch is hit, I reply 0x80 (10000000) in the first byte and the motherboard recognizes that the switch has been hit. So that's taken care of.

Now let's move on to P1. In the input test menu P1's bits get shown as a series of hex bytes. The chart aligns with what I'm getting on the input test. 1P Start is the left most bit in the 2nd byte. So if only that switch was triggered the reply for byte 2 would be 10000000 or 0x80.

So now I can get a good sense of the pin order for P1 when assigning pins on the Mega and reporting the inputs to the motherboard:

As I reply to the read switches command, I scan my assigned pins in the order above, building out a reply for the first 8 bits and then a reply for the remaining 5 bits.

Some examples:
If Button 1 and Button 2 are hit the 2 bytes would be:
00000011
00000000
or as seen in the test menu: 0300

If only Button 3 is hit the 2 bytes would be:
00000000
10000000
or as seen in the test menu: 0080

P2 then works the same way in the same order. It's just a matter of assigning them to different pins on the Mega and replying appropriately in bytes 4 and 5.

So now I'm rocking with digital inputs!
:thumbsup:

Next up: Coins
Coins are not included as switch inputs. They are managed in a completely separate command and acknowledgement. It looks like the motherboard doesn't even register coin switches. It appears to be up the the I/O board to read those and manage the number of coins, replying with how many coins have been inserted. I briefly tested this with the Type 1 I/O. As I triggered a coin switch, the input test menu incremented a number for the coin row rather than showing it as an on or off switch. I haven't gotten that far into it, but I would guess at some point the I/O would be told to subtract a coin. I'll reply with my findings when I get there.

This also leads me to question what's happening with the coin meters. There are some games that will not boot if a coin meter (or a resistor) is not present. I believe Jambo Safari is an example of this as I have a Naomi 1 and a Jambo Safari cart that will not boot in my cab since one of the meters is removed. I would guess the failure to boot is because for some reason the game is expecting a reply that it isn't getting from the I/O. I will need to make sure my replies for coins indicate that everything is in order, inc
 
I haven't dug into coins fully yet, so I'm not ready to type up a lesson, but here's a chart from the PDF and my assumptions by reading the chart and the various info available in the PDF:
JVS Coin Chart.png


Just like the digital inputs, the motherboard sends out frequent requests for Read Coins (0x21). It looks like the motherboard isn't responsible for reading coin switches. That job belongs to the I/O board. The board is responsible for managing adding coins when a coin switch is triggered, and reporting how many coins remain in the designated slots. In the JVS test, the coin lines appear to be showing an incremented coin counter and what I suppose would be the status bit, but they're showing as 0 (Normal), so it's not apparent that you're looking at status bits.

Each coin slot shows up as 2 bytes in the JVS Input test menu. This corresponds to the top chart that shows the left most 2 bits are status bits, while the remaining bits are coin info bits 8-13. Then byte 2 would be bits 0-7. In the case where I was seeing an incremented coin counter and a normal status, it makes sense that I would be seeing something like 0001, 0002, etc.

The number of coin slots is something that gets reported in the features reply.

I assume that if you, for example, wanted to replicate the Type 1 I/O, but did not want to manage coins, you could forever report that there are X amount of credits available or you could put it on free play and report 0s for all slots.

There then appears to be a separate command sent by the motherboard to decrease the coins in a given slot, like when starting a game. This appears as the Subtract Coin command (0x30). *Note that there is also a Coin Add (0x35) command that I suppose would be implemented in a game that awards credits.


I don't want to translate the chart for this one in image form, but the request comes in the form of:

byte 0: Command (30)

byte 1: Slot Number (02)

byte 2: Number to subtract - Upper 8 bits (00) - *probably always 0 or it's subtracting a ton of coins!

byte 3: Number to subtract - Lower 8 bits (01)


An acknowledgement to this command appears to be a simple 01 reply similar to that used for many other commands that do not require specific data back.


I believe a lot of games stop counting credits at 99. I wonder if that's simply due to the I/O board stopping at 99 or if the game just doesn't care about anything over 99, so it won't display it. It seems like I recall entering more than 99 coins in a game before, and it was always treated as if there were 99 and not more. So starting a game would bring down to 98 regardless of how many coins past 99 I entered. It appears that there are 14 bits of coin data per slot available, so it seems like the max credits would be 0011111111111111 or 0x3FFF or 16,383, but I guess there's no reason to keep track of them up to that amount.


I'll be able to confirm all of this when I get a chance to play around with the code.

It's also interesting to note that some games will not boot when a coin counter (or resistor) are not present. In this case the read coin reply would be indicating that the coin counter is not present and I guess the various game programmers thought that would be a reason to keep the game from booting. Jambo Safari is an example of a game with this behavior. I current have one of the coin counters removed in my OR2SP cab and cannot get my Naomi 1 and Jambo Safari cart to boot in this state. That means with my Mega I/O, I just need to make sure to report status as 0 and I think I could avoid this booting issue.
 
Look who has analog figured out! This is an aspect that I haven't found in the open source projects.

In this test I've got a potentiometer wired up to an analog input on the Mega and am reporting the values as analog channel 1, while reporting zeros for the other channels.

One screen shows the pot turned down to 1 (it can go to 0 but that wouldn't be a good example since everything else is 0) while the other shows it all the way at the max value of FF.

Jvs_analog1.png
Jvs_analog2.png

More info to follow.
 
JVS I/O Lesson 2: Analog Inputs


I'm skipping coins for now since I haven't gotten to the point of figuring out and verifying the Subtract Coins command. I do have the adding coins for slot 1 and 2 implemented successfully at this point, though.

Anyway, on to analog!

I'm not showing any fancy charts for this one because they aren't going to help much. There's actually not a whole lot that goes on with reporting analog data and I think it's actually easier to report than the digital inputs.

Going back to the features reply that drives a lot of this, one of the things you report in the features of your I/O is that it has analog inputs, how many channels, and the number of bits per channel. The PDF gives examples that make me think it generally wants 16 bits of analog data, though I notice that the Type 1 I/0 is really only showing values for 8 bits. The way I have it implemented is to say that each channel is 16 bits, but only report the leftmost 8, and get results that look the same as the Type1 I/O on the input test menu.

The replies are byte chunks, just like everything else. In the case of 8 channels it's just a matter of replying byte by byte in the order of the channels. Since I'm saying each channel has 16 bits, the reply for each channel takes up 2 bytes.

Replies are like this:
byte 1: Channel 1 first byte (0x00 to 0xFF)
byte 2: Channel 1 2nd byte (all zeros in my case)
byte 3: Channel 2 first byte (0x00 to 0xFF)
byte 4: Channel 2 2nd byte (all zeros in my case)
...
byte 15: Channel 8 first byte (0x00 to 0xFF)
byte 16: Channel 8 2nd byte (all zeros in my case)

And that's it for reporting analog inputs.

The Arduino Mega 2560 reads analog inputs as 10 bit values between 0 and 1023. This has to be converted to either 16 bits (0 to 65535) or 8 bits (0 to 255). In my current implementation, I'm doing the latter and converting them to 8 bits by dividing the initial value by 4 (1023/4 roughly equals 255). I suppose actually reporting 16 bits has the potential for a more sensitive, higher resolution analog input, but I doubt the extra sensitivity would be noticed in a game. The Type1 I/O looks to only be reporting 8 bits per channel and games work fine.

So other considerations might be min and max values typical in a given game. Steering wheels don't generally go from 0 all the way to FF, but have min and max somewhere in-between. I have been able to play most driving games fine with my OR2SP setup, so this may not be much of an issue, but could come into play with some games like 16 Wheeler, which I don't believe I'm able to play successfully, perhaps due to a wheel that is too limited in movement. In that case I may need to have some kind of modifier applied to the values I read and report a greater range of movement.

The other consideration would be inverted steering, like Club Kart defaults to (though it's configurable in the test menu). In that case, I could report inverted values for the steering wheel.

I believe all drivers I've encountered use the same 3 analog channels for steering, brake, and gas, so those likely won't have to be dynamically changed like the digital inputs are, but doing so would just be a matter of reporting the Mega's analog inputs as other specific channels if needed.

Next up: Coins with subtraction factored in OR Outputs

I think I'll be good to go with coins once I figure out handling the subtract command, but the other thing I need to figure out are outputs for the button lights.

I haven't confirmed, but I believe outputs might be handled with the Output GPIO 1 (0x32), Write Analog (0x33), Output GPIO 2 (0x37), or Output GPIO 3 (0x38). Based on poorly translated descriptions, I can't say for sure which of these is typically used for lamp outputs, but Output GPIO 3 seems to be dedicated to ON/OFF bits, so that may be it... I'll likely have to sniff the Type 1 I/O during output tests for a game to verify which one is used.


I can see in the feature reply that there is the potential to report Analog Outputs and GPIO Outputs as available features.

I'll do a write-up on the features reply when I better understand everything that goes into it. It should theoretically be possible to report my I/O as a Type 3 simply by what features I say are available. Then it's just a matter of replying correctly to any feature commands, whether or not I actually implement any of the features.
 
Last edited:
Great progress, the part you're going through now is the most fun imo :)

A note on a analog, the way I understand it, the bits reported in the capabilities query is for informationabout resolution to the game only - 16 bits is reported regardless, and probably explains the odd case of 8 bits resolution where 0 bits is reported (if I got that part correctly from the doc - IIRC that is what's reported by the sega IO).

The way it works is you shift/translate your sample up to 16 bits, so that the AD MSB corresponds to the 16 bit reported MSB, in the case of 10 bits, shift it up 6 bits.
 
Back
Top