Main Restorations Software Audio/Jukebox/MP3 Everything Else Buy/Sell/Trade
Project Announcements Monitor/Video GroovyMAME Merit/JVL Touchscreen Meet Up Retail Vendors
Driving & Racing Woodworking Software Support Forums Consoles Project Arcade Reviews
Automated Projects Artwork Frontend Support Forums Pinball Forum Discussion Old Boards
Raspberry Pi & Dev Board controls.dat Linux Miscellaneous Arcade Wiki Discussion Old Archives
Lightguns Arcade1Up Try the site in https mode Site News

Unread posts | New Replies | Recent posts | Rules | Chatroom | Wiki | File Repository | RSS | Submit news

  

Author Topic: Mame hacks that make driving games play better with mouse/spinner/360wheel  (Read 25720 times)

0 Members and 1 Guest are viewing this topic.

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
For some reason i can get the hdrivairp game to load up the first warp level but the game acts like i am offroad all the time. Never used to load for me. Thought it might be something to do with the diagnostic jumper.



« Last Edit: April 29, 2024, 12:53:22 pm by Yolo_Swaggins »

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
That's cool! So what do you think are the main differences are between hdrivairp and hdrivair? Looks like the dash has had a make over on hdrivairp...

Good work btw on the nvram work. I wasn't able to write new CNTSPTRN and PATCEN values to the nvram files for hard drivin, race drivin or street drivin. When I load the game, my edited nvram files just get ignored and I go straight into the service / wheel calibration mode (As if no nvram files existed). Are you able to write new CNTSPTRN and PATCEN values with your script without them being ignored then? Probably have a bug in my script, I wrote it pretty quick :)

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
I'm using the HxD hex editor to make the changes to the combined nvram file then splitting it back up into the 2 original files and it works. Did you check if it's combining the files in the right order? the one that works for me is combined_high_200e_low_210e but not combined_high_210e_low_200e. When i look at it in a hex editor i can see the names for the high scores.

This is the script i use to combine them

Code: [Select]
def combine_high_low(high_bytes, low_bytes):
    """Combines two byte arrays where the first array provides the high byte
    and the second array provides the low byte for each 16-bit word."""
    if len(high_bytes) != len(low_bytes):
        raise ValueError("Both files must have the same length.")
    combined = []
    for hb, lb in zip(high_bytes, low_bytes):
        # Combine into a 16-bit word
        combined_word = (hb << 8) | lb
        # Append high byte
        combined.append(combined_word >> 8)
        # Append low byte
        combined.append(combined_word & 0xFF)
    return bytes(combined)

def read_file(file_path):
    """Reads a file and returns its contents as a byte array."""
    with open(file_path, 'rb') as file:
        return file.read()

def write_file(file_path, data):
    """Writes binary data to a file."""
    with open(file_path, 'wb') as file:
        file.write(data)

def read_address(data, address):
    """Reads a 16-bit value from the combined data at a specified address."""
    # Each address points to two bytes forming a 16-bit value
    index = address * 2
    return data[index] << 8 | data[index + 1]

def main():
    # Paths to the input files
    path_200e = 'F:/Desktop/MAME/nvram/harddrivcb/mainpcb_200e'
    path_210e = 'F:/Desktop/MAME/nvram/harddrivcb/mainpcb_210e'
   
    # Read the files
    data_200e = read_file(path_200e)
    data_210e = read_file(path_210e)
   
    # Combine files: High byte from 200e, low byte from 210e
    combined_high_200e_low_210e = combine_high_low(data_200e, data_210e)
    # Combine files: High byte from 210e, low byte from 200e
    combined_high_210e_low_200e = combine_high_low(data_210e, data_200e)
   
    # Save the combined data to new files
    write_file('F:/Desktop/MAME/nvram/harddrivcb/combined_high_200e_low_210e', combined_high_200e_low_210e)
    write_file('F:/Desktop/MAME/nvram/harddrivcb/combined_high_210e_low_200e', combined_high_210e_low_200e)

    # Read specific addresses
    address_212 = read_address(combined_high_200e_low_210e, 0x212)
    address_213 = read_address(combined_high_200e_low_210e, 0x213)
    print(f"Address 0x212: {address_212} (0x{address_212:04X})")
    print(f"Address 0x213: {address_213} (0x{address_213:04X})")
   
    print("Files combined successfully and saved.")

if __name__ == '__main__':
    main()

Then this is the one i use to split it up.

Code: [Select]
def read_combined_file(file_path):
    """Reads the combined file and returns its contents as a byte array."""
    with open(file_path, 'rb') as file:
        return file.read()

def split_combined_file(data):
    """Splits the combined data back into high and low byte arrays."""
    high_bytes = []
    low_bytes = []
    for i in range(0, len(data), 2):  # Process two bytes at a time
        high_byte = data[i]           # High byte (from the first file)
        low_byte = data[i + 1]        # Low byte (from the second file)
        high_bytes.append(high_byte)
        low_bytes.append(low_byte)
    return bytes(high_bytes), bytes(low_bytes)

def write_file(file_path, data):
    """Writes binary data to a file."""
    with open(file_path, 'wb') as file:
        file.write(data)

def main():
    # Path to the combined file
    combined_path = 'F:/Desktop/MAME/nvram/harddrivcb/combined_high_200e_low_210e'
   
    # Read the combined file
    combined_data = read_combined_file(combined_path)
   
    # Split the combined file back into original high and low files
    high_data, low_data = split_combined_file(combined_data)
   
    # Save the split data back to original file paths
    write_file('F:/Desktop/MAME/nvram/harddrivcb/mainpcb_200e', high_data)
    write_file('F:/Desktop/MAME/nvram/harddrivcb/mainpcb_210e', low_data)
   
    print("Files have been successfully split and saved.")

if __name__ == '__main__':
    main()

If i write a value into a place it shouldn't be it makes the test menu pop up on boot. if i just copy the section that contains the calibration info or alter it it works fine and i can see the changes it makes when i enter the test menu.
« Last Edit: April 29, 2024, 02:32:52 pm by Yolo_Swaggins »

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
From:   KIM::MARGOLIN     17-JUL-1991 16:33:59.46
To:   RAY,MONCRIEF,SMITHSON
CC:   MARGOLIN
Subj:   BM


1. The only problem I can think of relates to the use of the new OptoCoupler
Pot. When this pot is used, Resistors R182, R183, and R184 mut be removed.
(They do not appear on the production parts list.)

2. In the Driver, one of the 8 bit A/D inputs was connected to a half wave,
unfiltered sample from one of the transformer secondaries. In Self-Test I
calculated RMS by appropriate MultiPlies and Square Root routines.

The routines were never installed in a MultiSync and would take time to
convert. The harness and power supply board would have to be modified to
provide this additional signal.

The following is a description of the Opto Reader:

   
Optocoupler Decoding Means
--------------------------
The quadrature outputs of the Optocoupler are latched at 8 MHz in 185U.
These latched outputs (NEWQ0 and NEWQ1) are once again latched at 8 MHz to
provide a delayed version of the signals (OLDQ0 and OLDQ1).

The reason for creating delayed versions of the signals is to permit the
detection of signal edges by PROM 195U.

The PROM determines whether a counter should be clocked, and if so, in
what direction.

The Latch/PROM do not constitute a state machine since there is no feedback
from the PROM.

If an illegal state is produced, the PROM will not clock the counter.

One 8 MHz clock after Q0 and Q1 from the OptoCoupler produce a valid sequence
the circuit will operate. It cannot get hung up.


   SECTION PROGRAM


_______________________________________


I think this is referring to Steel talons but i thought i'd share it incase it was something that wasn't known before, been looking through the internal atari emails from around 1990/1991.


Just found this one too.

From:   KIM::MILTY        18-JUL-1991 08:06:16.14
To:   @ENCODER.LIS
CC:   
Subj:   OPTICAL ENCODER USES


 I HAVE BEEN ASSIGNED THE TASK OF DESIGNING THE NEXT GENERATION "TESTER"
FOR THE OPTICAL ROTARY ENCODER (THE LITTLE GUY ,ABOUT THE SIZE OF OUR 5K
POT ).
 "I NEED INPUT"..HOW IS THIS ENCODER ENVISIONED BEING USED ?
I MEAN ,IN TERMS OF RESOLUTION.....HOW FAST WILL IT SPIN...?
THE OUTPUT RATE IS 128 PULSES/REVOLUTION PER CHANNEL (2 CHANNELS
IN QUADRATURE 90 DEGREES APART )
"BADLANDS STEERING" WAS 1:1 WITH A 58 PULSES/REVOLUTION RATE.
"WHIRLY-GIG          IS 1:1 WITH A 72   "        "        "
"RACE DRIVIN (COMPACT)" 1:1 WITH A 72   "        "        "
"ROADBLASTERS"      WAS GEARED 1:4 WITH A 36 P/R RATE....BUT THEN
                    THE STEERING WAS RESTRICTED TO 1/2 TURN,SO A
                    TOTAL OF 72 PULSES WOULD BE "SEEN" FROM
                    LOCK TO LOCK OF THE STEERING CONTROL.
....SOOO,LOOKING DOWN THE ROAD,...HOW MUCH "RESOLUTION" COULD WE
USE ,...
"GUMBALL RALLY" HAD AN ENCODER ON EACH MOTOR WHICH COULD SPIN AS FAST
AS 3600 RPM WITH 24 PULSES/ROTATION (1440 PULSES/SEC )...TO DO THE
SAME JOB THIS NEW ENCODER WOULD NEED TO SPIN AT 675 RPM.
 IS THIS A TYPICAL APPLICATION ????
I UNDERSTAND LETA GETS INVOLVED IN THE CIRCUIT,...RUSTY,WHAT LIMITATIONS
MIGHT BE ENCOUNTERED? IS IT JUST PROCESSOR SPEED LIMITED?

IS THERE ANY REASON TO PURSUE 1,000 PULSES / MILLISECOND ?



IF YOU HAVE ANY REQUIREMENTS,POSSIBLE APPLICATIONS,IDEAS,PERTINENT INFO OR DATA PLEASE
REPLY TO THIS ADDRESS.

         MILTY
__________________
« Last Edit: April 29, 2024, 05:12:22 pm by Yolo_Swaggins »

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
>>If i write a value into a place it shouldn't be it makes the test menu pop up on boot. if i just copy the section that contains the calibration info or alter it it works fine and i can see the changes it makes when i enter the test menu.

Hm, so I think you are copying a block of bytes? My script just changes 2 bytes for CNTSPTRN, and 2 bytes for PATCEN. I'm pretty sure it is editing/saving the nvrams correctly. After it changes the 4 bytes to something new (stopping the nvrams from working), I can use my script to revert back the 4 bytes back to what they were, and then it works. No big deal this I guess, but it would be handy if it worked :)


Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!


Pretty sure it's just that 04 00 probobly don't need to copy the whole block. Look at the address on the side. File starts at 00000000 and ends at 00000fff and has 16 rows on the right. It's right above the first set of high score names that get saved in the nvram.

« Last Edit: April 29, 2024, 05:05:50 pm by Yolo_Swaggins »

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Hm, I've checked what my script is writing and all looks good to me in HxD... I'm still not ruling out me doing something silly though lol!

So in those 6 bytes you've highlighted, I reckon if you change just that 04 byte to an 02 (Which should change cntsptrn from 1024 to 512), then the nvram won't load, change it back to 04 and it will.

Maybe because you were copying a few extra bytes other than the ones specifically for cntsptrn and patcen then this why its working for you?

:)

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Yeah your right for some reason the other couple of bytes are needed for it to load up properly, i never properly tested it yesterday because i was messing around trying to get the stuff from the other prototype rom to load up in the one that works properly and it did work but the roads are missing collision detection so you fall through the track and cant drive up any hills and it acts like your offroad all the time. I had to make cheats to disable the timers so i could drive around and have a look. I'd like to be able to get the stuff from that non-working rom lol. I noticed you don't need to load the data into the  ds3xdsp chip the game still works fine without it i was trying to see if i removed it if the emulation would speed up to the same speed as street drivin' but i think it's all the extra special effects like the weather changing and the fog that makes it lag.
« Last Edit: April 30, 2024, 03:13:31 am by Yolo_Swaggins »

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Look what i got working. https://youtube.com/live/--kRpvhdtOg?feature=share

I was messing around swapping rom files around thought i had it working but the collision detection didn't work in the extra level that is "under construction"

Had another look today and notice discrepencies in how the 2 systems roms are loaded into the arcade machine. Changed hdrivairp to load up the roms correctly in the right format and in the right chip and now the levels work with collision detection in all the levels without having to do any rom hacking. Got sidetracked on this hoping you could maybe figure out the steering wheel bug. It could actually be a similar problem causing that when i think about it.......might need the right roms loaded to the correct chip that handles that stuff? :dunno

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Really good work Yolo!

I must admit I haven't made much progress on the airborne front. I've been doing some tidying of the steering changes for hard/race and street drivin'. I think I'm going to start a thread on the bannister mame forum ( https://forums.bannister.org/ubbthreads.php?ubb=postlist&Board=1 ) and ask the mame team for a bit of guidance on how to add a few options that I think we need.

Some interesting-ish things:

- I've noticed the IPT_POSITIONAL control option seems like a good compromise for both mouse and joystick. For mouse it acts like the IPT_DIAL does, and for joystick it acts like an IPT_PADDLE does...
Code: [Select]
PORT_START("mainpcb:12BADC.0")       /* 400000 - steering wheel */
PORT_BIT( 0xfff, 0x800, IPT_POSITIONAL ) PORT_POSITIONS(0xfff) PORT_WRAPS PORT_SENSITIVITY(50) PORT_KEYDELTA(1) PORT_NAME("Steering Wheel")

- Regarding editing the nvram, and the 6 bytes that seem to change when you calibrate your wheel (2 bytes for CNTSPTRN, 2 bytes for PATCEN and finally 2 weird bytes). I think I've worked out those weird bytes are a combination of the CNTSPTRN and PATCEN, added to a strange number. I've posted the latest version of the script below, I've called the weird 2 bytes the 'Edge', and the strange number the  CNTSPTRN and PATCEN are added to I've called the 'Edge base'. I don't really know what they are used for. Anyways, this is handy, because for strreet drivin we are now able to edit the nvram and change the default -98 patcen to 0. I can't seem to change street drivin' CNTSPTRN from 512 to 1024. I can change the nvram, and it gets loaded/accepted by the game ok, but I can tell when I play the game the CNTSPTRN is still fixed to 512.

- Finally, I might take another look at those strange numbers I was reading from another register a while ago (That seemed to change based on steering). I'm wondering if they have something to do with force feedback... maybe...

:)

Code: [Select]
import sys

BYTES_EXPECTED = 2048
EDGE_BASE_HARDDRIV = 0x2C1D
EDGE_BASE_STRTDRIV = 0x295D


def load_byte_array(filename):

    global BYTES_EXPECTED

    with open(filename, mode='rb') as file: # b is important -> binary
        fileContent = file.read().hex()

    data = []
    byte_count = 0
    this_byte = ""
    for c in fileContent:
        this_byte += c
        if len(this_byte) == 2:
            data.append(int(this_byte, 16))
            this_byte = ""
            byte_count += 1

    if byte_count != BYTES_EXPECTED:
        print("Error! Unexpected number of bytes in {}. Expecting={}, actual={} ".format(filename, BYTES_EXPECTED, byte_count))
        exit(1)

    #print("{}".format((fileContent)))
    return data


def save_byte_array(filename, byte_array):
    # make file
    newFile = open(filename, "wb")
    # write to file
    newFileByteArray = bytearray(byte_array)
    newFile.write(newFileByteArray)


def load_nvram(nvram_path):

    global BYTES_EXPECTED

    mainpcb_200e = load_byte_array(nvram_path + "mainpcb_200e")
    mainpcb_210e = load_byte_array(nvram_path + "mainpcb_210e")

    # Combine the data...
    nvram = []
    for i in range(0, BYTES_EXPECTED):
        nvram.append((mainpcb_200e[i] << 8) | mainpcb_210e[i])

    return nvram

def save_nvram(nvram_path, nvram):

    global BYTES_EXPECTED

    mainpcb_200e = []
    mainpcb_210e = []

    # split the data...
    for i in range(0, BYTES_EXPECTED):
        mainpcb_200e.append((nvram[i] >> 8)&0xff)
        mainpcb_210e.append(nvram[i]&0xff)

    save_byte_array(nvram_path + "mainpcb_200e", mainpcb_200e)
    save_byte_array(nvram_path + "mainpcb_210e", mainpcb_210e)


def patcen_to_int(patcen):
    if (patcen&0xf000) == 0xf000:
        return -1 * (0x1000 - patcen&0x0fff)
    else:
        return patcen


def int_to_patcen(i_patcen):

    if i_patcen < 0:
        return 0xf000 | (0x1000 + i_patcen)
    else:
        return i_patcen


def get_edge(cntsptrn, patcen, start_edge, undo=False):

    edge = start_edge
    i_patcen = patcen_to_int(patcen)

    # Leave the sign 'as is' when undoing, flip the sign when redoing...
    cntsptrn *= 1 if undo else -1
    i_patcen *= 1 if undo else -1

    edge += cntsptrn
    edge += i_patcen

    return edge


def validate_edge_base(edge_base, exit_on_error=True):

    if edge_base == EDGE_BASE_HARDDRIV:
        print("Hard/Race Drivin' style edge detected - OK".format(hex(edge_base)))
    elif edge_base == EDGE_BASE_STRTDRIV:
        print("Street Drivin' style edge detected - OK".format(hex(edge_base)))
    else:
        print("Error! Unexpected edge base {} detected. Expecting either Hard/Race Drivin' edge base {} or Street Drivin' edge base {})".format(hex(edge_base),hex(EDGE_BASE_HARDDRIV), hex(EDGE_BASE_HARDDRIV)))
        if exit_on_error:
            if input('Continue anyway?') != 'y':
                exit(0)


def do_read(nvram_path):

    nvram = load_nvram(nvram_path)
    cntsptrn = "?"
    patcen = "?"
    edge = "?"

    for i in range(0, BYTES_EXPECTED):
    #for i in range(0x210, 0x218):
        temp = "ADDR:0x{:04X} - 0x{:04X} {:<8}".format(i, nvram[i], f"({nvram[i]})")
        if i == 0x212:
            temp = temp + " CNTSPTRN"
            cntsptrn = nvram[i]
        elif i == 0x213:
            temp = temp + " PATCEN"
            patcen = nvram[i]
        elif i == 0x214:
            temp = temp + " EDGE"
            edge = nvram[i]

        print(temp)

    i_patcen = patcen_to_int(patcen)
    print(f"Read complete. CNTSPTRN:{hex(cntsptrn)} ({cntsptrn})     PATCEN:{hex(patcen)} ({i_patcen})  EDGE:{hex(edge)}")

    # Check the edge looks right...
    edge_base = get_edge(cntsptrn, patcen, edge, undo=True)
    validate_edge_base(edge_base, exit_on_error=False)


def do_diff(nvram_path_a, nvram_path_b):

    global BYTES_EXPECTED

    a = load_nvram(nvram_path_a)
    b = load_nvram(nvram_path_b)

    diff_count = 0
    for i in range(0, BYTES_EXPECTED):
        if a[i] != b[i]:
            temp = "ADDR:0x{:04X} - A:0x{:04X} {:<8} DIFF B:0x{:04X} {:<8}".format(i, a[i], f"({a[i]})", b[i], f"({b[i]})")
            if i == 0x212:
                temp = temp + " CNTSPTRN"
            elif i == 0x213:
                temp = temp + " PATCEN"
            diff_count += 1
            print(temp)

    print(f"{diff_count} differences detected.")


def do_reset(nvram_path, cntsptrn, i_patcen):

    nvram = load_nvram(nvram_path);

    # Check the edge looks right and if it doesn't, ask user if they want to continue...
    edge_base = get_edge(nvram[0x212], nvram[0x213], nvram[0x214], undo=True)
    validate_edge_base(edge_base, exit_on_error=True)

    cntsptrn = cntsptrn
    patcen = int_to_patcen(i_patcen)
    edge = get_edge(cntsptrn, patcen, edge_base, undo=False)

    nvram[0x212] = cntsptrn
    nvram[0x213] = int_to_patcen(i_patcen)
    nvram[0x214] = edge

    save_nvram(nvram_path, nvram)

    print(f"CNTSPTRN reset to {cntsptrn}, PATCEN reset to {i_patcen}. OK")

def clean_path(my_path):
    if not my_path.endswith('/'):
        my_path = my_path + '/'
    return my_path

def show_usage():
    print("Nvram Helper")
    print("------------")
    print("")
    print("Usage:")
    print("    python3 nvram_helper.py read  <nvram_directory>")
    print("    python3 nvram_helper.py diff  <nvram_directory_a> <nvram_directory_b>")
    print("    python3 nvram_helper.py reset <nvram_directory> <cntsptrn> <patcen>")

    print("Examples:")
    print("    python3 nvram_helper.py read nvram/harddrivcb")
    print("    python3 nvram_helper.py diff nvram/harddrivcb nvram/strtdriv")
    print("    python3 nvram_helper.py reset nvram/harddrivcb 1024 0")
    print("    python3 nvram_helper.py reset nvram/racedrivcb 1024 0")
    print("    python3 nvram_helper.py reset nvram/strtdriv 512 0")
    exit(0)


#print("{}".format(sys.argv))

if len(sys.argv) < 2:
    show_usage()

cmd = sys.argv[1]
if cmd == 'read':
    if len(sys.argv) < 3:
        print(f"Not enough arguments.")
        exit(1)
    do_read(clean_path(sys.argv[2]))

elif cmd == 'diff':
    if len(sys.argv) < 4:
        print(f"Not enough arguments.")
        exit(1)
    do_diff(clean_path(sys.argv[2]), clean_path(sys.argv[3]))

elif cmd == 'reset':
    if len(sys.argv) < 5:
        print(f"Not enough arguments.")
        exit(1)
    do_reset(clean_path(sys.argv[2]), int(sys.argv[3]), int(sys.argv[4]))

elif cmd.lower() in ["h", "-h", "help", "/help", "/h", "?", "--h"]:
    show_usage()

else:
    print(f"Unknown command '{cmd}'.")
    show_usage()

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Hi Geecab, i hope you can figure it all out! I was playing around with swapping rom files from the compact hard drivin and race drivin' into the street drivin hardware on mame and can almost get it to work i was trying it out because the sound works much better on street drivin compared to hard drivin' and race drivin emulated hardware and the sound roms seem to be the exact same as race drivin' compact and race drivin' panorama share a lot of roms with street drivin' too! How do i run that script you made for the nvram files? I just do it in python again? Getting the steering as accurate as possible to the arcade would be really nice. I worked out what roms files contain the police car and the extra stock car track in street drivin', somebody good at decompiling and modding assembly code could maybe hack in the gear shifter to work as i find playing with the gears in the compact version is much more fun!

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
From reading the internal emails from Atari back when all these games were being made i can see that sometimes the test menu wasn't even completed before the game was. Maybe theres a chance that the cntrspn doesn't work because the code in the test menu isnt there to load it up? i kinda got this feeling from my discovery that the hacked ema wheel value i tried sending to street drivin specifically at the start of the game which would be much lower than the real value untill it average itself out over a few seconds makes the steering not work at all but if you reset the machine it will then work.  Makes me think that the game code dynamically adjusts that stuff based on the input range fed to it through mame? Airborne doesn't exhibit that behaviour and just seems to act like it's set in stone. It was 2 different teams that atari got to do street drivin and airborne and they would pick out the best one for release but it was already dated by the time all was said and done and they abandoned them both. It might explain why theres different steering behaviour between the 2 games.  Street drivin doesn't have any off the wheel being off center issues it was just the normal range of steering from the portminmax that the other games used was too big for street drivin i guess because the patcen isnt right? Maybe we need a dump of the original saved data from the street drivin and hard drivin's airborne to understand it more and make it work? What if the data was reset by somebody who got hold of the machines at a later date and this is what is causing it? I'm probobly wrong about it all but it's interesting trying to figure out whats going on and i hope you can fix it eventually it would be a really cool achievement and more people could get to test them out and see what might have been.

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Cool! That's interesting stuff Yolo!

Regarding those strange values I was reading in the hd68k_wr2_write() function, they definitely indicate steering wheel force feedback. The value indicates the amount of force that its trying to rotate the wheel (with either clockwise or anti clockwise)). I'll post more about this in a bit.

Regarding the script, yes its just python again. Create a file called, say, nvram_helper.py in the same directory as your mame.exe and copy that code into it. Run it without any parms and try one of the examples. Fingers crossed its work for you, not tested it on windows, only Linux so far.

:)

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Hi Yolo!

Thought I'd post my hack of the  hd68k_wr2_write() to read steering wheel force feedback. If you're interested, just replace the existing hd68k_wr2_write()  function with this one, and when holding the 'F' key in-game you can see the feedback trying to do its thing. Something that is pretty cool is watching the attract mode and viewing the force feedback, you can see how the game is trying to rotate the wheel when it hits the corners (You do need to enable the Steering During Attract Mode option for that though, I explain how to do that in the massive comment in the function).

Code: [Select]
void harddriv_state::hd68k_wr2_write(offs_t offset, uint16_t data)
{
    /*
    Observations
    ============

    The 'data' repeats every 4 times this function is called.
    Offset always seems to be zero.
    Combining the 1st and 3rd byte of data gives you the steering
    wheel force feedback.

    When the game does not want to rotate the wheel in any direction,
    0xE000 is read.

    When the game wants the wheel to rotate clockwise, you see this:
        0xE000 increment to 0xE01F,
        then jumps to 0xE100 which increments to 0xE11F,
        then jumps to 0xE200 which increments to 0xE21F,
        then jumps to 0xE300 which increments to 0xE31F,
        etc...

    When the game wants the wheel to rotate anticlockwise, you see this:
        0xE000 jumps to 0xFF1F which decrements to 0xFF00,
        then jumps to 0xFE1F which decrements to 0xFE00,
        then jumps to 0xFD1F which decrements to 0xFD00,
        then jumps to 0xFC1F which decrements to 0xFC00,
        etc...

    Bits 0 to 7 never go above 32 (0x1f). Thus Bits 5 to 7 are unused.

    If bits 12 to 15 are 0xE this indicates the game is trying to turn
    the wheel clockwise. If they are 0xF, it is trying to turn the
    wheel anticlockwise.

    Shifting bits 8 to 11 right 3 places, gives you a value that
    increments/decrements logically.

    Testing
    =======

    In service mode, view the OPERATOR SCREENS and go to the 2nd page
    where there are 2 interesting options:
        Steering During Attract Mode
        Steering Wheel Force

    When Steering During Attract Mode is enabled, when you watch the
    attract mode, you'll see the the m_wheel_force change value as the
    game attempts to move the steering wheel while the car is moving around
    the track.

    When Steering Wheel Force is set to 'Very light' you'll see
    m_wheel_force in the range -70 to 70. When set to 'Stiff' you'll see
    m_wheel_force in the range -127 to 127.
    */

    static unsigned int static_count = 0;
    static uint8_t static_data[4];

    //printf("wr2 offset=%04X data=%04X\n", offset, data);

    //Store the data in this array (Must be a better way to do read this stuff...)
    static_data[static_count] = data;
    static_count++;
    if (static_count > 3)
    {
        uint16_t force_combined, force_shifted;
        int m_wheel_force;

        static_count = 0;

        //Combine the force (1st and 3rd byte)
        force_combined = ((static_data[2]<<8)&0xff00) | (static_data[0]&0x00ff);

        //Shift the force so that it logically increments/decrements
        force_shifted = (((force_combined)>>3)&0x01f0) | (force_combined&0xf01f);

        //Use the force
        if ((force_shifted&0xf000) == 0xe000)
        {
            m_wheel_force = int(force_shifted&0x0fff);          //Clockwise force (+ive number)
        }
        else
        {
            m_wheel_force = int(force_shifted&0x0fff) - 511;    //Anticlockwise force (-ive number)
        }


        if (machine().input().code_pressed(KEYCODE_F))
        {
            popmessage("wr2 wheel=0x%04X force=%d", m_hdc68k_last_wheel, m_wheel_force);
        }
    }
}

:)

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Hi Yolo!

Thought I'd post my hack of the  hd68k_wr2_write() to read steering wheel force feedback. If you're interested, just replace the existing hd68k_wr2_write()  function with this one, and when holding the 'F' key in-game you can see the feedback trying to do its thing. Something that is pretty cool is watching the attract mode and viewing the force feedback, you can see how the game is trying to rotate the wheel when it hits the corners (You do need to enable the Steering During Attract Mode option for that though, I explain how to do that in the massive comment in the function).

Code: [Select]
void harddriv_state::hd68k_wr2_write(offs_t offset, uint16_t data)
{
    /*
    Observations
    ============

    The 'data' repeats every 4 times this function is called.
    Offset always seems to be zero.
    Combining the 1st and 3rd byte of data gives you the steering
    wheel force feedback.

    When the game does not want to rotate the wheel in any direction,
    0xE000 is read.

    When the game wants the wheel to rotate clockwise, you see this:
        0xE000 increment to 0xE01F,
        then jumps to 0xE100 which increments to 0xE11F,
        then jumps to 0xE200 which increments to 0xE21F,
        then jumps to 0xE300 which increments to 0xE31F,
        etc...

    When the game wants the wheel to rotate anticlockwise, you see this:
        0xE000 jumps to 0xFF1F which decrements to 0xFF00,
        then jumps to 0xFE1F which decrements to 0xFE00,
        then jumps to 0xFD1F which decrements to 0xFD00,
        then jumps to 0xFC1F which decrements to 0xFC00,
        etc...

    Bits 0 to 7 never go above 32 (0x1f). Thus Bits 5 to 7 are unused.

    If bits 12 to 15 are 0xE this indicates the game is trying to turn
    the wheel clockwise. If they are 0xF, it is trying to turn the
    wheel anticlockwise.

    Shifting bits 8 to 11 right 3 places, gives you a value that
    increments/decrements logically.

    Testing
    =======

    In service mode, view the OPERATOR SCREENS and go to the 2nd page
    where there are 2 interesting options:
        Steering During Attract Mode
        Steering Wheel Force

    When Steering During Attract Mode is enabled, when you watch the
    attract mode, you'll see the the m_wheel_force change value as the
    game attempts to move the steering wheel while the car is moving around
    the track.

    When Steering Wheel Force is set to 'Very light' you'll see
    m_wheel_force in the range -70 to 70. When set to 'Stiff' you'll see
    m_wheel_force in the range -127 to 127.
    */

    static unsigned int static_count = 0;
    static uint8_t static_data[4];

    //printf("wr2 offset=%04X data=%04X\n", offset, data);

    //Store the data in this array (Must be a better way to do read this stuff...)
    static_data[static_count] = data;
    static_count++;
    if (static_count > 3)
    {
        uint16_t force_combined, force_shifted;
        int m_wheel_force;

        static_count = 0;

        //Combine the force (1st and 3rd byte)
        force_combined = ((static_data[2]<<8)&0xff00) | (static_data[0]&0x00ff);

        //Shift the force so that it logically increments/decrements
        force_shifted = (((force_combined)>>3)&0x01f0) | (force_combined&0xf01f);

        //Use the force
        if ((force_shifted&0xf000) == 0xe000)
        {
            m_wheel_force = int(force_shifted&0x0fff);          //Clockwise force (+ive number)
        }
        else
        {
            m_wheel_force = int(force_shifted&0x0fff) - 511;    //Anticlockwise force (-ive number)
        }


        if (machine().input().code_pressed(KEYCODE_F))
        {
            popmessage("wr2 wheel=0x%04X force=%d", m_hdc68k_last_wheel, m_wheel_force);
        }
    }
}

:)


Very cool and great work! If force feedback could become a native thing in mame for these games it would make life a lot easier as when i tried the force feedback plugin thats out there i never figured out how to get it to work for these games. Obviously i was doing something wrong on my end. I just found out that Race Drivin Panorama has the extra stock car track from Street Drivin' so i was thinking maybe i could swap the roms from that version into the Street Drivin' hardware driver in mame and get to play with the gear shifter and have the less glitchy audio and maybe run faster?  I almost had the Race Drivin' compact working on that hardware but some of the files were not compatible. I did manage to get the Race Drivin logo and credits to appear. I wish they never gave up on this game and made more of them with the same graphics style.

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
The 3rd and 4th roms* in the mainpcb:maincpu on street drivin' are the test menu roms that are both interleaved so technically it's 1 rom.
« Last Edit: May 10, 2024, 12:43:14 pm by Yolo_Swaggins »

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Hi Yolo!

Well, I’m convinced after much testing Airborne’s steering re-centering is entirely different to hard/race/street drivin’. The centering encoder signals are completely ignored. For Airborne, when your car re-spawns after crashing, whatever the wheel position your steering wheel is in at that time becomes the new center (regardless of angle). The center position can also self adjust during play should you oversteer (Say that you rotate the wheel 3 times clockwise to go round a tight turn. You’ll only need to do roughly one anit-clockwise rotation for the car to go in a straight line again).

I came to the conclusion that this game can only really be enjoyed with a mouse/spinner. Even then it would need force feedback so you had a feeling of where the steering center is.

Then I had a thought which was followed by a hack which might help...

I modified hdc68k_wheel_r() for airborne. I took out the steering latching stuff. I’ve added a key ‘S’ that can hold to adjust your steering wheel back to center during play. Here’s how it works:

Say that you are playing the game, you want the car to go straight, your steering wheel is in its central position but the car is pulling to the right.  To fix this you need to turn your steering wheel left (Until the car is moving in a straight line), then press and hold the ‘S’ key,  then turn your steering wheel to its central position, and release the ‘S’ key. That’s it.

I know its not really an ideal solution, but it might improve the game experience and help us get better laps times :)

In hardriv.cpp, in the "static INPUT_PORTS_START( hdrivair )" section, I've changed this line:-
Code: [Select]
PORT_BIT(0xfff, 0x200, IPT_PADDLE) PORT_MINMAX(0x000, 0x3ff) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_REVERSE PORT_NAME("Steering Wheel")
to this...
Code: [Select]
PORT_BIT( 0xfff, 0x000, IPT_POSITIONAL ) PORT_POSITIONS(0xfff) PORT_WRAPS PORT_SENSITIVITY(50) PORT_KEYDELTA(1) PORT_REVERSE PORT_NAME("Steering Wheel")

Then in harddriv_m.cpp, replace the hdc68k_wheel_r() function with this...

Code: [Select]
uint16_t harddriv_state::hdc68k_wheel_r()
{
// grab the new wheel value
uint16_t new_wheel, raw_wheel = m_12badc[0].read_safe(0xffff);
int wheel_diff = 0;
bool is_wheel_increasing = false;
static uint8_t wheel_snapshot = 0;
static uint8_t wheel_offset = 0;
static bool steering_enabled = true;

if (machine().input().code_pressed(KEYCODE_S))
{
if (steering_enabled)
{
popmessage("Steering disabled (Re-center your wheel now...)");
steering_enabled = false;
wheel_snapshot = (m_hdc68k_last_wheel+wheel_offset)&0xff;
}

return ((wheel_snapshot << 8) | 0xff);
}
else
{
if (!steering_enabled)
{
popmessage("Steering enabled");
steering_enabled = true;
wheel_offset = (wheel_snapshot - raw_wheel)&0xff;
m_hdc68k_last_wheel = raw_wheel;
}
}

// Work out which way the wheel is spinning
if((m_hdc68k_last_wheel < 0x400) && (raw_wheel > 0xC00))        is_wheel_increasing = false;    //Wrapped from bottom to top
else if ((m_hdc68k_last_wheel > 0xC00) && (raw_wheel < 0x400))  is_wheel_increasing = true;     //Wrapped from top to bottom
else if(m_hdc68k_last_wheel > raw_wheel)                        is_wheel_increasing = false;
else if(m_hdc68k_last_wheel < raw_wheel)                        is_wheel_increasing = true;

//Steering damping:
//Ensure we don't jump from one encoder value to another too quickly confusing the game
//The game is aware only of changes to m_12badc's lower byte. This means the game can get easily confused if you where to move
//the wheel very quickly from say position 0x800 to 0xC12 in one cycle (Which was perhaps physically impossible using the
//actual arcade encoder). The game would be under the impression the wheel has moved only 0x12 values, rather than 0x412 values.
//If we detect a large change, slowly feed that information back to the game in managemtble amounts.
new_wheel = m_hdc68k_last_wheel;
while(new_wheel != raw_wheel)
{
if (is_wheel_increasing)
{
if (new_wheel >= 0xFFF) new_wheel = 0x000;
else new_wheel++;
}
else
{
if (new_wheel <= 0x000) new_wheel = 0xFFF;
else new_wheel--;
}

//Lets say the encoder can't move more that 32 teeth per cycle...
if (wheel_diff++ > 0x10) break;
}

if (machine().input().code_pressed(KEYCODE_LSHIFT))
{
popmessage("wheel=0x%04X", new_wheel);
}

m_hdc68k_last_wheel = new_wheel;
return ((new_wheel+wheel_offset) << 8) | 0xff;
}



Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Hi Yolo!

Well, I’m convinced after much testing Airborne’s steering re-centering is entirely different to hard/race/street drivin’. The centering encoder signals are completely ignored. For Airborne, when your car re-spawns after crashing, whatever the wheel position your steering wheel is in at that time becomes the new center (regardless of angle). The center position can also self adjust during play should you oversteer (Say that you rotate the wheel 3 times clockwise to go round a tight turn. You’ll only need to do roughly one anit-clockwise rotation for the car to go in a straight line again).

I came to the conclusion that this game can only really be enjoyed with a mouse/spinner. Even then it would need force feedback so you had a feeling of where the steering center is.

Then I had a thought which was followed by a hack which might help...

I modified hdc68k_wheel_r() for airborne. I took out the steering latching stuff. I’ve added a key ‘S’ that can hold to adjust your steering wheel back to center during play. Here’s how it works:

Say that you are playing the game, you want the car to go straight, your steering wheel is in its central position but the car is pulling to the right.  To fix this you need to turn your steering wheel left (Until the car is moving in a straight line), then press and hold the ‘S’ key,  then turn your steering wheel to its central position, and release the ‘S’ key. That’s it.

I know its not really an ideal solution, but it might improve the game experience and help us get better laps times :)

In hardriv.cpp, in the "static INPUT_PORTS_START( hdrivair )" section, I've changed this line:-
Code: [Select]
PORT_BIT(0xfff, 0x200, IPT_PADDLE) PORT_MINMAX(0x000, 0x3ff) PORT_SENSITIVITY(100) PORT_KEYDELTA(5) PORT_REVERSE PORT_NAME("Steering Wheel")
to this...
Code: [Select]
PORT_BIT( 0xfff, 0x000, IPT_POSITIONAL ) PORT_POSITIONS(0xfff) PORT_WRAPS PORT_SENSITIVITY(50) PORT_KEYDELTA(1) PORT_REVERSE PORT_NAME("Steering Wheel")

Then in harddriv_m.cpp, replace the hdc68k_wheel_r() function with this...

Code: [Select]
uint16_t harddriv_state::hdc68k_wheel_r()
{
// grab the new wheel value
uint16_t new_wheel, raw_wheel = m_12badc[0].read_safe(0xffff);
int wheel_diff = 0;
bool is_wheel_increasing = false;
static uint8_t wheel_snapshot = 0;
static uint8_t wheel_offset = 0;
static bool steering_enabled = true;

if (machine().input().code_pressed(KEYCODE_S))
{
if (steering_enabled)
{
popmessage("Steering disabled (Re-center your wheel now...)");
steering_enabled = false;
wheel_snapshot = (m_hdc68k_last_wheel+wheel_offset)&0xff;
}

return ((wheel_snapshot << 8) | 0xff);
}
else
{
if (!steering_enabled)
{
popmessage("Steering enabled");
steering_enabled = true;
wheel_offset = (wheel_snapshot - raw_wheel)&0xff;
m_hdc68k_last_wheel = raw_wheel;
}
}

// Work out which way the wheel is spinning
if((m_hdc68k_last_wheel < 0x400) && (raw_wheel > 0xC00))        is_wheel_increasing = false;    //Wrapped from bottom to top
else if ((m_hdc68k_last_wheel > 0xC00) && (raw_wheel < 0x400))  is_wheel_increasing = true;     //Wrapped from top to bottom
else if(m_hdc68k_last_wheel > raw_wheel)                        is_wheel_increasing = false;
else if(m_hdc68k_last_wheel < raw_wheel)                        is_wheel_increasing = true;

//Steering damping:
//Ensure we don't jump from one encoder value to another too quickly confusing the game
//The game is aware only of changes to m_12badc's lower byte. This means the game can get easily confused if you where to move
//the wheel very quickly from say position 0x800 to 0xC12 in one cycle (Which was perhaps physically impossible using the
//actual arcade encoder). The game would be under the impression the wheel has moved only 0x12 values, rather than 0x412 values.
//If we detect a large change, slowly feed that information back to the game in managemtble amounts.
new_wheel = m_hdc68k_last_wheel;
while(new_wheel != raw_wheel)
{
if (is_wheel_increasing)
{
if (new_wheel >= 0xFFF) new_wheel = 0x000;
else new_wheel++;
}
else
{
if (new_wheel <= 0x000) new_wheel = 0xFFF;
else new_wheel--;
}

//Lets say the encoder can't move more that 32 teeth per cycle...
if (wheel_diff++ > 0x10) break;
}

if (machine().input().code_pressed(KEYCODE_LSHIFT))
{
popmessage("wheel=0x%04X", new_wheel);
}

m_hdc68k_last_wheel = new_wheel;
return ((new_wheel+wheel_offset) << 8) | 0xff;
}

Hi Geecab,that is a really good solution for the Hard Drivin' Airborne off center bug. I'll need to try it out and see! I'm thinking it would be more responsive when turning the wheel compared to the EMA buffering code I'm currently using to stop it going off center because it adds a very slight latency to the wheel.

Just thought I'd mention this because you seem to be confused about Street Drivin's steering wheel behaviour. Street Drivin's steering is different from Race Drivin' Compact, Hard Drivin' Compact, the cockpit versions AND different from Airborne.

Street Drivin' doesn't have the "steering going off-center bug" when you crash or when you go offroad or even if you turn the wheel too fast etc, it never goes out of alignment. Only the compact versions have that and Airborne. The only reason it seemed to be happening in Street Drivin' before is because the steering range was the same as the others (0x010, 0xff0), when it was changed it to 0x000, 0x3ff it completely fixed the steering, it stops the bug that happens when you steer to the maximum left or right. The change of the PORT_MINMAX to (0x000, 0x3ff) fixed that bug for Airborne too but Airborne has the same bugs that the compact versions have but unfortunately your solution for the compact versions doesn't fix it for Airborne.


BTW I'm now sure that Street Drivin's ROM is actually a cockpit version and I'm even more certain of that now because if you look at the ROM's that get loaded into the main program memory it shares ROM's with Race Drivin' Panorama which on MAME is a cockpit ROM and not a compact. None of the cockpit ROMs are compatible with the compact except the sound ROM's and Jed Margolin even mentions that fact on his website. You can try it for yourself, Street Drivin' already plays perfectly!

Just thought I'd mention it because it could help narrow down the problem Airborne is having because they both have the same steering wheel range in common but Street Drivin' doesn't do the wheel edge/centering stuff the same as any of the others and that is why it doesn't have the bug you were experiencing on the compact versions or Airborne.


I noticed the first set of ROM's in the main program seem to be the ones that contain the test menu code. I was able to load up the Race Drivin Panorama version of the test menu in Street Drivin' by swapping the ROM's over but it made the screen garbled too. It was all readable and seemed to work but had strange values and the writing just looked weird like the resolution is set wrong or something.

I've gave up on my mission of trying to make Street Drivin' have gears by fiddling with the ROM's because today I found out that the Race Drivin' Panorama has the extra stock car track and even has the drone cars from Street Drivin' on it. The only problem i noticed with it was the frame rate even when using my overclock. I fixed this by loading up only the main PCB ROM's and not the left and right PCB ROM's using the Race Drivin' cockpit machine configuration and now the game plays smooth. I think it's because there is a hack in the MAME source code that's used to get the 3 screens in sync and even when you choose 1 screen only in the MAME video options it still seems to be using that hack and using the side PCB's.
« Last Edit: May 11, 2024, 10:43:06 am by Yolo_Swaggins »

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Hi Yolo!

>>that is a really good solution for the Hard Drivin' Airborne off center bug. I'll need to try it out and see! I
Cool, hope it helps :)

I have to say, I do think Street Drivin is a compact model (Uses 2 optical encoders). It recenters the steering the same as Hard Drivin and Race Drivin compacts. I can simulate it. The main difference is that Hard/Race Drivin Compacts have a CNTSPTRN value around 1024. Street Drivin has a CNTSPTRN value of around 512.

By having your control setup as IPT_PADDLE with PORT_MINMAX to (0x000, 0x3ff), starting at position 0x200, you'll never see Street Drivin try to recenter. You are limiting your turning values to -512 anti clockwise, +512 clockwise (Thus you are not allowing yourself to complete a 1 full rotation in either direction). You have to turn quite a bit beyond a full rotation to cause a recenter. I think this is why it appears setting PORT_MINMAX(0x000, 0x3ff) might have fixed things for you.

Another thing to remember with your Street Drivin setup, if your hdc68k_wheel_r is set to trigger a 'centre edge' only at 0x000, 0x400, 0x800 & 0xC00, you never see a center edge triggered within that control range you have specified. You could manually trigger one at 0x200 and watch your steering offset by -98 (because -98 is the default patcen for street drivin. Unless you've editted the nvram and changed patcen to 0 that is...).

You could do something similar with Hard/Race Drivin' and see the same thing IPT_PADDLE with PORT_MINMAX to (0x000, 0x8ff), starting at position 0x400, You are limiting your turning values to -1024 anti clockwise, +1024 clockwise (Thus you are not allowing yourself to complete a 1 full rotation in either direction). That is assuming you've got an nvram CNTSPTRN set to 1024 patcen set to 0.

I guess in the end though, it doesn't really matter, it nice to know what's going on behind the scenes, but what works for you works for you :)

Btw. New observation (Which desn't really help us but worth mentioning): I noticed when editing nvrams, I couldn't change street drivin's CNTSPTRN from 512 to 1024. Similarly, I couldn't change Hard/Race Drivin's CNTSPTRN from 1024 to 512 (The nvrams are loaded ok, but the new values are ignored). I summarised that the CNTSPTRN value can't be changed massively. Changing the CNTSPTRN works fine if you change them +/- say 100.

Btw. Another observation: I think the compact games don't 'have' to see a center edge always. With the original hardware it would be possible to miss that one single notch on the encoder disk (So the programmers wouldn't want the game to freak out if it were to miss one). Without triggering a center edge at all, the game would just calculate where the rotational center of wheel is based on its CNTSPTRN values, and it would assume the position of the wheel at first reading would be the center position.

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Hi geecab i think im confused because of the code changes you made recently on the version your working on because it changes the behaviour of the emulated machine to be more accurate for the latchbit and there was another factor at play too.

I deleted my NVRAM and used the version of mame thats available for download just now and when you load up street drivin' and calibrate the brake then go into the game the car can do a full turn the steering appears not to be limited, i compared it to the arcade doing a full turn the car turns just as sharp there is a video on youtube of a car doing a full turn to the left at the start in hard drivin and if you compare that to what you see in street drivin the car turns the same as that video with the port_minmax set to 0x000,0x3ff and im using a logitech wheel set to 900 degrees. Car can crash and go offroad and does not exhibit the steering bug that was in the compact version of race drivin and hard drivin.

That is when the code in harddriv_m.cpp was like this so the behaviour you are describing would never have been seen by myself or others using the default code.

   
Code: [Select]
/* merge in the wheel edge latch bit */
if (m_hdc68k_wheel_edge)
result ^= 0x4000;

m_hdc68k_last_port1 = result;
return result;
}


uint16_t harddriv_state::hda68k_port1_r()
{
uint16_t result = m_a80000->read();

/* merge in the wheel edge latch bit */
if (m_hdc68k_wheel_edge)
result ^= 0x4000;

return result;
}


uint16_t harddriv_state::hdc68k_wheel_r()
{
/* grab the new wheel value */
uint16_t new_wheel = m_12badc[0].read_safe(0xffff);

/* hack to display the wheel position */
if (machine().input().code_pressed(KEYCODE_LSHIFT))
popmessage("%04X", new_wheel);

/* if we crossed the center line, latch the edge bit */
if ((m_hdc68k_last_wheel / 0xf00) != (new_wheel / 0xf00))
m_hdc68k_wheel_edge = 1;

/* remember the last value and return the low 8 bits */
m_hdc68k_last_wheel = new_wheel;
return (new_wheel << 8) | 0xff;
}


There is another thing that was adding to the confusion. On my own build of harddriv.cpp  i still had a 0x400 range of steering but i was using 0x800 as the center point and and my code looked like this

Code: [Select]
PORT_BIT(0xfff, 0x800, IPT_PADDLE) PORT_CONDITION("mainpcb:SW1", 0x700, EQUALS, 0x100) PORT_MINMAX(0x600, 0xa00) PORT_SENSITIVITY(1) PORT_KEYDELTA(0) PORT_NAME("Original MAME")
Now this was being used in conjunction with the latch bit fixes you made in your previous code changes which resulted in my wheel never going off center even with a 0x400 range of motion and the default nvram because the center point was still 0x800..........

When i change my harddriv.cpp to have the 0x000 as the starting point and 0x400 as the end point and using 0x200 as the center AND your code fix for the latchbit behaviour i get exactly the same behaviour you describe. This behavior still happens with your modified code even if i change this ((m_hdc68k_last_wheel & 0xc00) != (new_wheel & 0xc00)) to  ((m_hdc68k_last_wheel & 0xf00) != (new_wheel & 0xf00)) which is the default on mame right now because the latchbit behaviour above that part of the code was fixed by you in your version so now i understand what the discrepancy has been between what you observed and what i observed!  ;D

I just spent some time trying to figure it out because something seemed off to me now it makes perfect sense!
« Last Edit: May 11, 2024, 03:07:00 pm by Yolo_Swaggins »

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Hi Geecab i just tried your code and it seems to be totally not working at all for me. The steering wheel doesn't behave normal at all and starts pulling to the side etc. How is it your testing this code? On a controller? It doesn't seem to work at all for a steering wheel. Maybe im doing something wrong?

Code: [Select]
    // Merge in the wheel edge latch bit
    if (m_hdc68k_wheel_edge)
    {
        result ^= 0x4000;
        printf("hdc68k_port1_r: merge latch result=%04X m_hdc68k_last_wheel=%04X\n", result, m_hdc68k_last_wheel);
        m_hdc68k_wheel_edge = 0;
    }


    m_hdc68k_last_port1 = result;
    return result;
}
   

uint16_t harddriv_state::hda68k_port1_r()
{
    uint16_t result = m_a80000->read();

   if (m_hdc68k_wheel_edge)
    {
        result ^= 0x4000;
        printf("hda68k_port1_r: merge latch result=%04X m_hdc68k_last_wheel=%04X\n", result, m_hdc68k_last_wheel);
        m_hdc68k_wheel_edge = 0;
    }

    return result;
}

uint16_t harddriv_state::hdc68k_wheel_r()
{
// grab the new wheel value
uint16_t new_wheel, raw_wheel = m_12badc[0].read_safe(0xffff);
int wheel_diff = 0;
bool is_wheel_increasing = false;
static uint8_t wheel_snapshot = 0;
static uint8_t wheel_offset = 0;
static bool steering_enabled = true;

if (machine().input().code_pressed(KEYCODE_S))
{
if (steering_enabled)
{
popmessage("Steering disabled (Re-center your wheel now...)");
steering_enabled = false;
wheel_snapshot = (m_hdc68k_last_wheel+wheel_offset)&0xff;
}

return ((wheel_snapshot << 8) | 0xff);
}
else
{
if (!steering_enabled)
{
popmessage("Steering enabled");
steering_enabled = true;
wheel_offset = (wheel_snapshot - raw_wheel)&0xff;
m_hdc68k_last_wheel = raw_wheel;
}
}

// Work out which way the wheel is spinning
if((m_hdc68k_last_wheel < 0x400) && (raw_wheel > 0xC00))        is_wheel_increasing = false;    //Wrapped from bottom to top
else if ((m_hdc68k_last_wheel > 0xC00) && (raw_wheel < 0x400))  is_wheel_increasing = true;     //Wrapped from top to bottom
else if(m_hdc68k_last_wheel > raw_wheel)                        is_wheel_increasing = false;
else if(m_hdc68k_last_wheel < raw_wheel)                        is_wheel_increasing = true;

//Steering damping:
//Ensure we don't jump from one encoder value to another too quickly confusing the game
//The game is aware only of changes to m_12badc's lower byte. This means the game can get easily confused if you where to move
//the wheel very quickly from say position 0x800 to 0xC12 in one cycle (Which was perhaps physically impossible using the
//actual arcade encoder). The game would be under the impression the wheel has moved only 0x12 values, rather than 0x412 values.
//If we detect a large change, slowly feed that information back to the game in managemtble amounts.
new_wheel = m_hdc68k_last_wheel;
while(new_wheel != raw_wheel)
{
if (is_wheel_increasing)
{
if (new_wheel >= 0xFFF) new_wheel = 0x000;
else new_wheel++;
}
else
{
if (new_wheel <= 0x000) new_wheel = 0xFFF;
else new_wheel--;
}

//Lets say the encoder can't move more that 32 teeth per cycle...
if (wheel_diff++ > 0x10) break;
}

if (machine().input().code_pressed(KEYCODE_LSHIFT))
{
popmessage("wheel=0x%04X", new_wheel);
}

m_hdc68k_last_wheel = new_wheel;
return ((new_wheel+wheel_offset) << 8) | 0xff;
}

I'm trying this on a Logitech wheel at 900 degrees for input and having no luck at all.
« Last Edit: May 11, 2024, 01:10:08 pm by Yolo_Swaggins »

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Ah jeez, that doesn't sound good. I tested it with mouse and also a flight yoke. Have you made this change too...

In hardriv.cpp, in the "static INPUT_PORTS_START( hdrivair )" section, change the ITP_PADDLE steering control for:
PORT_BIT( 0xfff, 0x000, IPT_POSITIONAL ) PORT_POSITIONS(0xfff) PORT_WRAPS PORT_SENSITIVITY(50) PORT_KEYDELTA(1) PORT_REVERSE PORT_NAME("Steering Wheel")

When you say it not working,  is that even without pressing the S key at all?


Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Ah jeez, that doesn't sound good. I tested it with mouse and also a flight yoke. Have you made this change too...

In hardriv.cpp, in the "static INPUT_PORTS_START( hdrivair )" section, change the ITP_PADDLE steering control for:
PORT_BIT( 0xfff, 0x000, IPT_POSITIONAL ) PORT_POSITIONS(0xfff) PORT_WRAPS PORT_SENSITIVITY(50) PORT_KEYDELTA(1) PORT_REVERSE PORT_NAME("Steering Wheel")

When you say it not working,  is that even without pressing the S key at all?

Yeah i did that it just totally messes up the steering and makes it unplayable, a flight yoke has a much narrower range of movement than a driving steering wheel i guess thats the problem with the code? Pressing the S key doesnt help at all because the wheel goes out of alignment as soon as you start the game even on the menu where you choose to skip flight training it doesn't work just starts acting really weird. It goes way out of alignment even when not moving it fast at all and just acts really bugged tbh it's unplayable. If you can try it with a 900 degree wheel give it a go and see what happens. I made a account on the bannisters forum you linked here but it seems like the admins not going to approve it and it was 23 hours ago i made the account and it says if it's not approved in 24 hours it gets deleted.
« Last Edit: May 11, 2024, 05:53:03 pm by Yolo_Swaggins »

geecab

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 250
  • Last login:May 13, 2024, 06:19:08 am
Hm, I built the mame code straight from github with only those 2 changes I mentioned (No other hacks). Worked ok for me. Weird, I double check the code tonight.

As the physical controls we are testing with are different, I guess that's why we are seeing different results.

As we both have mouses though, perhaps see how it plays with your mouse ("mame hdrivair -mouse")? At least you should see what I tried to achieve :)

Yolo_Swaggins

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 36
  • Last login:May 13, 2024, 10:54:58 am
  • I want to build my own arcade controls!
Can ports be wrapped for IPT_PADDLE? I think that could fix it for the steering wheel? I'll have another try today with it on different controllers and see what happens, i have a xbox one controller and a PS5 controller too.