Physical Button Board Code!

This commit is contained in:
2025-06-17 03:30:17 +00:00
parent a8c3267249
commit e8e41ee7e7
9 changed files with 205 additions and 57 deletions

3
.vscode/launch.json vendored
View File

@@ -23,7 +23,8 @@
{ "name": "__GL_LOG_MAX_ANISO", "value": "0" },
{ "name": "__GL_FSAA_MODE", "value": "0" },
{ "name": "LD_PRELOAD", "value": "/g3/libvidsync.so" },
{ "name": "DISPLAY", "value": ":0" } // adjust if needed
{ "name": "DISPLAY", "value": ":0" }, // adjust if needed
{ "name": "GAMEBOARD_SERIAL", "value": "/dev/ttyACM0"}
],
/* Run gdb over SSH on the run VM */

View File

@@ -186,14 +186,15 @@ int InpLoop(void)
//
// process jamma board
//
if((i=JammaLoop())<0) // every-loop processing for Jamma
{
if (i != -2) // for some reason, this error will happen
SysLog("JammaLoop() failed %d, resetting jamma\n",i);
if((i=JammaOp(JAMMAOP_RESET))<0)
SysLog("JammaOp(JAMMAOP_RESET) failed %d\n",i);
}
// DISABLE THE JAMMA BLAH BLAH. WE WILL WORRY ABOUT IT LATER.
// TODO: Add jamma support back at some point. But don't forget!
// if((i=JammaLoop())<0) // every-loop processing for Jamma
// {
// if (i != -2) // for some reason, this error will happen
// SysLog("JammaLoop() failed %d, resetting jamma\n",i);
// if((i=JammaOp(JAMMAOP_RESET))<0)
// SysLog("JammaOp(JAMMAOP_RESET) failed %d\n",i);
// }
#if PRODUCTION
if(i>0)
SysG.proflags|=M_SYSG_PROFLAGS_JAMMALIVES2;

View File

@@ -433,7 +433,7 @@ BAIL:
while(((i=glGetError())!=GL_NO_ERROR)&&(x++<100))
{
s=(void*)gluErrorString(i);
BP(BP_IMGLOAD5); // tell Joe there is an OpenGL error in imgLoad
//BP(BP_IMGLOAD5); // tell Joe there is an OpenGL error in imgLoad
} // while
}

View File

@@ -4248,7 +4248,7 @@ void dond_randomizeCases(int ignoreCaseNum)
for (i = 0; i < NUM_CASES; i++)
{
possibleTotal += caseState[i];
// printf("case %02i : %i\n", i, caseState[i]);
//printf("case %02i : %i\n", i, caseState[i]);
}
}
@@ -6455,6 +6455,7 @@ void dond_onLptSwitchHit(int snum)
dond_lptUpdateIO(1);
}
// So, does this mean hitting double deal will always kill the attract loop at any time?
if ((snum == 18) && (dondGameState == DOND_ATTRACT_LOOP))
{
dond_quickExitAttract();
@@ -6462,6 +6463,16 @@ void dond_onLptSwitchHit(int snum)
dond_lptUpdateIO(1);
}
// J added this, my custom controller will send code 20 to start
if ((snum == 20) && (dondGameState == DOND_ATTRACT_LOOP || dondGameState == DOND_TITLE_PAGE)){
// Kill the attract loop if it's running
if (dondGameState == DOND_ATTRACT_LOOP) {
dond_quickExitAttract();
}
dond_onStartButton();
dond_lptUpdateIO(1);
}
// - check for a SECRET CODE!
/*

View File

@@ -959,7 +959,7 @@ void *dond_lptWriteThreadCont(void *arg)
pthread_exit(NULL);
#endif
}
}
// -------------------------------------------------------------------

View File

@@ -1,43 +1,161 @@
// Dummy LPT driver.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h> /* usleep for the animation threads */
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <pthread.h>
/* ---------------------------- state ----------------------------- */
static uint8_t lptLampBank[3] = { 0xFF, 0xFF, 0xFF }; /* active-low */
static uint8_t lptSwitchBank[3] = { 0xFF, 0xFF, 0xFF }; /* always “off”*/
static uint8_t dond_lptSwitchCount[24] = { 0 };
static int dond_lptUpdating = 0;
/* --------------- threads ----------------*/
static pthread_t poll_thread;
static pthread_mutex_t switch_mutex = PTHREAD_MUTEX_INITIALIZER;
/* ---------------- helpers --------------------------------------- */
/* ---------------- state ---------------- */
static uint8_t lptLampBank[3] = { 0xFF, 0xFF, 0xFF };
static uint8_t dond_lptSwitchCount[24] = { 0 };
static int dond_lptUpdating = 0;
/* 22 button states */
static int dond_switchState[24] = { 0 };
static int dond_switchState_prev1[24] = { 0 };
static int dond_switchState_prev2[24] = { 0 };
static int bufferedLptInput[24] = { 0 };
/* Serial */
static int serial_fd = -1;
/* ---------------- helpers ---------------- */
static void lpt_dump_banks(void)
{
/* Emits one line; great for “tail -f” or log capture. */
printf("[LPT] bank0=%02X bank1=%02X bank2=%02X\n",
lptLampBank[0], lptLampBank[1], lptLampBank[2]);
fflush(stdout);
}
/* ---------------- public API unchanged signatures ------------- */
static void try_open_serial(void)
{
if (serial_fd > 0) return; // Should only be called if there's no serial.
const char* dev = getenv("GAMEBOARD_SERIAL");
if (!dev) dev = "/dev/ttyUSB0";
serial_fd = open(dev, O_RDWR | O_NOCTTY | O_SYNC);
if (serial_fd < 0) {
printf("[BUTTONBOARD] Warning: could not open serial port %s: %s\n", dev, strerror(errno));
return;
}
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(serial_fd, &tty) != 0) {
printf("[BUTTONBOARD] tcgetattr error: %s\n", strerror(errno));
close(serial_fd);
serial_fd = -1;
return;
}
cfsetospeed(&tty, B115200);
cfsetispeed(&tty, B115200);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag = 0;
tty.c_oflag = 0;
tty.c_lflag = 0; // no echo, no canonical
tty.c_cc[VMIN] = 3; // block until 3 bytes
tty.c_cc[VTIME] = 1; // 100ms timeout
tty.c_cflag |= CREAD | CLOCAL;
tty.c_cflag &= ~(PARENB | CSTOPB | CRTSCTS);
if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
printf("[BUTTONBOARD] tcsetattr error: %s\n", strerror(errno));
close(serial_fd);
serial_fd = -1;
}
}
static void* serial_poll_loop(void* arg)
{
(void)arg;
uint8_t last_valid[3] = {0};
while (1) {
try_open_serial();
if (serial_fd < 0) {
usleep(500 * 1000);
continue;
}
uint8_t cmd = 0x01;
ssize_t w = write(serial_fd, &cmd, 1);
if (w != 1) {
printf("[BUTTONBOARD] Failed to write poll byte. Reopening.\n");
close(serial_fd);
serial_fd = -1;
usleep(500 * 1000);
continue;
}
fd_set readfds;
struct timeval timeout = {0, 100 * 1000}; // 100ms
FD_ZERO(&readfds);
FD_SET(serial_fd, &readfds);
int sel = select(serial_fd + 1, &readfds, NULL, NULL, &timeout);
if (sel <= 0) {
// Timeout or error
if (sel < 0) perror("[BUTTONBOARD] select()");
usleep(50 * 1000);
continue;
}
uint8_t buf[3] = {0};
ssize_t r = read(serial_fd, buf, 3);
if (r != 3) {
printf("[BUTTONBOARD] Partial read (%zd). Dropping frame.\n", r);
usleep(50 * 1000);
continue;
}
memcpy(last_valid, buf, 3);
pthread_mutex_lock(&switch_mutex);
int i;
for (i = 0; i < 22; i++) {
int byte = i / 8;
int bit = i % 8;
dond_switchState[i] = (buf[byte] >> bit) & 1;
}
pthread_mutex_unlock(&switch_mutex);
usleep(20 * 1000); // 50 Hz
}
return NULL;
}
/* ---------------- core I/O logic ---------------- */
void dond_lptInit(void)
{
/* Nothing to initialise on a PC; just report the reset state. */
static int started = 0;
if (!started) {
pthread_create(&poll_thread, NULL, serial_poll_loop, NULL);
started = 1;
}
lpt_dump_banks();
}
int dond_lptUpdateIO(int writeFlag)
{
/* writeFlag==0 → “read” phase. We have no inputs always idle.*/
if (!writeFlag) return 0;
if (dond_lptUpdating) return 0;
dond_lptUpdating = 1;
lpt_dump_banks(); /* single place where we talk to host */
lpt_dump_banks();
dond_lptUpdating = 0;
return 0;
}
@@ -47,17 +165,14 @@ void dond_lptSetLamp(int lnum, int state)
int bank = lnum / 8;
int bit = lnum % 8;
/* Original hardware is active-low: 0=ON, 1=OFF */
if (state) lptLampBank[bank] &= ~(1U << bit); /* turn ON */
else lptLampBank[bank] |= (1U << bit); /* turn OFF */
if (state) lptLampBank[bank] &= ~(1U << bit);
else lptLampBank[bank] |= (1U << bit);
/* Immediately push the change behaviour identical to original */
(void)dond_lptUpdateIO(1);
}
void dond_lptSetLamp_diag(int lnum, int state)
{
/* Same as normal SetLamp but *does not* flush immediately. */
int bank = lnum / 8;
int bit = lnum % 8;
@@ -67,32 +182,55 @@ void dond_lptSetLamp_diag(int lnum, int state)
int dond_lptGetSwitch(int snum)
{
/* Always “not pressed” (active-low -> returns 1). */
return 1;
return dond_switchState[snum] ? 0 : 1; // Active-low behavior
}
int dond_lptSwitchCheck(int writeHits)
{
/* Nothing changes, therefore no hits. */
(void)writeHits;
int i;
int local_switchState[24];
writeHits = 1; // DBG override
pthread_mutex_lock(&switch_mutex);
memcpy(local_switchState, dond_switchState, sizeof(dond_switchState));
pthread_mutex_unlock(&switch_mutex);
for (i = 0; i < 22; i++) {
if (local_switchState[i] && !dond_switchState_prev1[i] && !dond_switchState_prev2[i]) {
bufferedLptInput[i] = 1;
}
}
if (writeHits) {
for (i = 0; i < 22; i++) {
if (bufferedLptInput[i]) {
dond_lptSwitchCount[i]++;
dond_onLptSwitchHit(i);
bufferedLptInput[i] = 0;
}
}
}
for (i = 0; i < 22; i++) dond_switchState_prev2[i] = dond_switchState_prev1[i];
for (i = 0; i < 22; i++) dond_switchState_prev1[i] = local_switchState[i];
return 0;
}
int dond_lptGetSwitchCount(int snum) { (void)snum; return 0; }
int dond_lptCountSwitches(void) { return 0; }
/* -----------------------------------------------------------------
* The remaining functions drive animations (fade-ins, attract mode,
* etc.). They still run so that higher-level game logic keeps the
* same timing, but they merely call the stubbed SetLamp(). *
* ----------------------------------------------------------------- */
/* Remaining stub functions unchanged */
int dond_lptGetSwitchCount(int snum){ return dond_lptSwitchCount[snum]; }
int dond_lptCountSwitches(void) {
int count = 0;
int i;
for (i = 0; i < 22; i++) {
if (dond_switchState[i]) count++;
}
return count;
}
/* Animation and slow-path thread stubs left unchanged */
static void * nop_thread(void *arg) { (void)arg; return NULL; }
/* Each animation collapses to a minimal stub. If you *want* output
* spam that shows every intermediate lamp frame, simply keep the
* original bodies the SetLamp() calls already print each change. */
#define MAKE_THREAD(fn) \
void *fn(void *arg) { return nop_thread(arg); }
@@ -103,16 +241,14 @@ MAKE_THREAD(dond_lptThreadFadeRedOut)
MAKE_THREAD(dond_lptAttractAnim)
MAKE_THREAD(dond_lptTestThread)
MAKE_THREAD(dond_lptTestThread2)
MAKE_THREAD(dond_lptWriteThread) /* instant no I/O delays */
MAKE_THREAD(dond_lptWriteThreadCont) /* while(1) loop removed */
MAKE_THREAD(dond_lptWriteThread)
MAKE_THREAD(dond_lptWriteThreadCont)
/* Spawn helpers become no-ops because the threads above do nothing. */
void dond_lptSpawnTestThread(void) {}
void dond_lptSpawnWriteThread(void) {}
void dond_lptSpawnWriteThreadCont(void) {}
void dond_lptSpawnThread(int t) { (void)t; }
void dond_lptSpawnThread(int t) { (void)t; }
/* Slow path helpers (reads/writes used only by diagnostics) stubbed */
int dond_lptReadSlow(void) { return 0; }
void dond_lptWriteSlow(void) {}
void dond_lptWriteCaseBanks(void) {}

View File

@@ -634,7 +634,6 @@ int GameStart(void)
goto BAIL;
// - intialize the dongle checking system
printf("Harware dongle disabled!");
//BankerOfferInitialize();
//

View File

@@ -22,7 +22,7 @@
#define GAME_NUMBER 6 // game number
#ifndef NEW_JERSEY
#define GAME_FULL_NAME "Deal or No Deal D&B" // used to print name onscreen
#define GAME_FULL_NAME "Deal or No Deal" // used to print name onscreen
#endif
#ifdef NEW_JERSEY

View File

@@ -1,4 +1,4 @@
01.07.03 D&B
EXE Version 01.07.03 D&B
01.07.03
EXE Version 01.07.03
Release Date: Tuesday, February 3rd, 2009
9