1
0
mirror of synced 2025-02-17 10:38:32 +01:00

Add roel's JVS pass through code

This commit is contained in:
Bobby Dilley 2023-11-13 22:45:51 +00:00
parent 031044c5bd
commit f494984cdc
6 changed files with 334 additions and 50 deletions

View File

@ -7,6 +7,7 @@
"time.h": "c",
"stdarg.h": "c",
"ioctl.h": "c",
"segaeax.h": "c"
"segaeax.h": "c",
"passthrough.h": "c"
}
}

View File

@ -1,27 +1,16 @@
#include <stdio.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <linux/serial.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <stdlib.h> /* Standard library functions like malloc, free, exit, and atoi */
#include "baseboard.h"
#include "config.h"
#include "jvs.h"
#include "serial.h"
#include "passthrough.h"
#define SERIAL_STRING "FE11-X018012022X"
@ -83,21 +72,21 @@ int initBaseboard()
printf("Error: Cannot open %s\n", sramPath);
return 1;
}
fclose(sram);
sram = fopen(sramPath, "rb+");
fseek(sram, 0, SEEK_SET);
if (getConfig()->emulateJVS == 0 && strcmp(getConfig()->jvsPath, "none") != 0)
{
jvsFileDescriptor = open(getConfig()->jvsPath, O_RDWR | O_NOCTTY | O_SYNC | O_NDELAY);
jvsFileDescriptor = openJVSSerial(getConfig()->jvsPath);
if (jvsFileDescriptor < 0)
{
printf("Error: Failed to open %s for JVS\n", getConfig()->jvsPath);
return -1;
}
setSerialAttributes(jvsFileDescriptor, B115200);
initJVSSerial(jvsFileDescriptor);
startJVSFrameThread(&jvsFileDescriptor);
}
return 0;
@ -206,11 +195,9 @@ int baseboardIoctl(int fd, unsigned int request, void *data)
}
else if (jvsFileDescriptor >= 0)
{
write(jvsFileDescriptor, inputBuffer, jvsCommand.srcSize);
for (int i = 0; i < jvsCommand.srcSize; i++)
{
write(jvsFileDescriptor, &inputBuffer[i], 1);
if (inputBuffer[i] == 0xF0)
{
setSenseLine(3);
@ -270,14 +257,11 @@ int baseboardIoctl(int fd, unsigned int request, void *data)
}
else if (jvsFileDescriptor >= 0)
{
int count = readBytes(jvsFileDescriptor, &sharedMemory[jvsCommand.destAddress], 255);
if (count == -1)
count = 0;
JVSFrame frame = readJVSFrameFromThread();
memcpy(&sharedMemory[jvsCommand.destAddress], frame.buffer, frame.size);
_data[2] = jvsCommand.destAddress;
_data[3] = count;
_data[1] = (count > 0); // Success if we receive any sort of data back
_data[3] = frame.size;
_data[1] = frame.ready;
}
}
break;

View File

@ -88,7 +88,7 @@ FGAPI void FGAPIENTRY glutGameModeString(const char *string)
Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int class, Visual *visual, unsigned long valueMask, XSetWindowAttributes *attributes)
{
Window (*_XCreateWindow)(Display * display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int class, Visual *visual, unsigned long valueMask, XSetWindowAttributes *attributes) = dlsym(RTLD_NEXT, "XCreateWindow");
Window (*_XCreateWindow)(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int class, Visual *visual, unsigned long valueMask, XSetWindowAttributes *attributes) = dlsym(RTLD_NEXT, "XCreateWindow");
width = getConfig()->width;
height = getConfig()->height;
@ -112,7 +112,7 @@ Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int
int XGrabPointer(Display *display, Window grab_window, Bool owner_events, unsigned int event_mask, int pointer_mode, int keyboard_mode, Window confine_to, Cursor cursor, Time time)
{
int (*_XGrabPointer)(Display * display, Window grab_window, Bool owner_events, unsigned int event_mask, int pointer_mode, int keyboard_mode, Window confine_to, Cursor cursor, Time time) = dlsym(RTLD_NEXT, "XGrabPointer");
int (*_XGrabPointer)(Display *display, Window grab_window, Bool owner_events, unsigned int event_mask, int pointer_mode, int keyboard_mode, Window confine_to, Cursor cursor, Time time) = dlsym(RTLD_NEXT, "XGrabPointer");
int returnValue = _XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, time);
XUngrabPointer(display, time);
return returnValue;
@ -120,7 +120,7 @@ int XGrabPointer(Display *display, Window grab_window, Bool owner_events, unsign
int XGrabKeyboard(Display *display, Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode, Time time)
{
int (*_XGrabKeyboard)(Display * display, Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode, Time time) = dlsym(RTLD_NEXT, "XGrabKeyboard");
int (*_XGrabKeyboard)(Display *display, Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode, Time time) = dlsym(RTLD_NEXT, "XGrabKeyboard");
int returnValue = _XGrabKeyboard(display, grab_window, owner_events, pointer_mode, keyboard_mode, time);
XUngrabKeyboard(display, time);
return returnValue;
@ -133,7 +133,7 @@ int XDefineCursor(Display *display, Window w, Cursor cursor)
int XStoreName(Display *display, Window w, const char *window_name)
{
int (*_XStoreName)(Display * display, Window w, const char *window_name) = dlsym(RTLD_NEXT, "XStoreName");
int (*_XStoreName)(Display *display, Window w, const char *window_name) = dlsym(RTLD_NEXT, "XStoreName");
char gameTitle[256] = {0};
strcat(gameTitle, getGameName());
strcat(gameTitle, " (X11)");
@ -143,8 +143,15 @@ int XStoreName(Display *display, Window w, const char *window_name)
int XNextEvent(Display *display, XEvent *event_return)
{
int (*_XNextEvent)(Display * display, XEvent * event_return) = dlsym(RTLD_NEXT, "XNextEvent");
int (*_XNextEvent)(Display *display, XEvent *event_return) = dlsym(RTLD_NEXT, "XNextEvent");
int returnValue = _XNextEvent(display, event_return);
// Return now if we're not emulating JVS
if (!getConfig()->emulateJVS)
{
return returnValue;
}
switch (event_return->type)
{
@ -231,7 +238,7 @@ int XNextEvent(Display *display, XEvent *event_return)
int XSetStandardProperties(Display *display, Window window, const char *window_name, const char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints)
{
int (*_XSetStandardProperties)(Display * display, Window window, const char *window_name, const char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints) = dlsym(RTLD_NEXT, "XSetStandardProperties");
int (*_XSetStandardProperties)(Display *display, Window window, const char *window_name, const char *icon_name, Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints) = dlsym(RTLD_NEXT, "XSetStandardProperties");
char gameTitle[256] = {0};
strcat(gameTitle, getGameName());
strcat(gameTitle, " (X11)");
@ -245,30 +252,36 @@ Bool XF86VidModeSwitchToMode(Display *display, int screen, XF86VidModeModeInfo *
typedef unsigned int uint;
int glXSwapIntervalSGI(int interval) {
int glXSwapIntervalSGI(int interval)
{
return 0;
}
int glXGetVideoSyncSGI(uint *count) {
int glXGetVideoSyncSGI(uint *count)
{
static unsigned int frameCount = 0;
//TODO: Framecount should depend on current system time
*count = (frameCount++)/2; // NOTE: Keeps the same frame for 2 calls
// TODO: Framecount should depend on current system time
*count = (frameCount++) / 2; // NOTE: Keeps the same frame for 2 calls
return 0;
}
int glXGetRefreshRateSGI(unsigned int * rate) { //TODO: need an actual prototype
*rate = 60; //TODO: what does this function return?
int glXGetRefreshRateSGI(unsigned int *rate)
{ // TODO: need an actual prototype
*rate = 60; // TODO: what does this function return?
return 0;
}
void glGenFencesNV(int n, uint *fences) {
void glGenFencesNV(int n, uint *fences)
{
static unsigned int curf = 1;
while(n--) {
while (n--)
{
*fences++ = curf++;
}
return;
}
void glDeleteFencesNV(int a, const uint *b) {
void glDeleteFencesNV(int a, const uint *b)
{
return;
}

View File

@ -598,6 +598,13 @@ JVSStatus writePacket(JVSPacket *packet)
return JVS_STATUS_SUCCESS;
}
/**
* Gets the sense line value
*
* Values are:
* 3 = no device, after a RESET
* 1 = address assigned
*/
int getSenseLine()
{
return senseLine;
@ -635,6 +642,7 @@ int setAnalogue(JVSInput channel, int value)
return 1;
}
void setSenseLine(int _senseLine) {
void setSenseLine(int _senseLine)
{
senseLine = _senseLine;
}

258
src/lindbergh/passthrough.c Normal file
View File

@ -0,0 +1,258 @@
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ioctl.h> /* Ioctl function to control device drivers in the kernel */
#include <stdlib.h> /* Standard library functions like malloc, free, exit, and atoi */
#include <pthread.h> /* POSIX threads API to create and manage threads in the program */
#include "passthrough.h"
#define TIMEOUT_SELECT 200
#define CTS_ON_RETRY 20
// Used to read JVS frame in a non-blocking way
JVSFrame jvsFrameBuffer;
pthread_mutex_t jvsBuffer_lock = PTHREAD_MUTEX_INITIALIZER;
/**
* Open the serial interface and return a file descriptor
* @param jvsPath The serial port path. Ex: "/dev/ttyS3"
* @return A file descriptor
*/
int openJVSSerial(char *jvsPath) {
int jvsFileDescriptor = -1;
// TODO: check O_NOCTTY declaration
jvsFileDescriptor = open(jvsPath, O_RDWR | O_NOCTTY);
if (jvsFileDescriptor < 0) {
printf("Failed to open '%s' for JVS.\n", jvsPath);
}
return jvsFileDescriptor;
}
/**
* Init a serial port (using file descriptor) so it behaves correctly for JVS usage
* @param fd
* @return 0|1
*/
int initJVSSerial(int fd) {
struct termios options;
int status;
// Get the current options
if (tcgetattr(fd, &options) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
return 1;
}
// Set rates
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
/* From doc:
* If the CLOCAL flag for a line is off, the hardware carrier detect (DCD) signal is significant,
* an open(2) of the corresponding terminal will block until DCD is asserted, unless the O_NONBLOCK
* flag is given. If CLOCAL is set, the line behaves as if DCD is always asserted. The software
* carrier flag is usually turned on for local devices, and is off for lines with modems.
*/
// options.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines
options.c_cflag |= CREAD; // Turn on READ, let ctrl lines work
options.c_cflag &= ~PARENB; // Clear parity bit & disable parity
options.c_cflag &= ~CSTOPB; // Clear stop field, 1 stop bit
options.c_cflag &= ~CSIZE; // Clear all bits that set the data size
options.c_cflag |= CS8; // 8 bits
options.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control
options.c_lflag &= ~ICANON; // Disable canonical mode, so no input processing is performed
options.c_lflag &= ~ECHO; // Disable echo
options.c_lflag &= ~ECHOE; // Disable erasure
options.c_lflag &= ~ECHONL; // Disable new-line echo
options.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR |
ICRNL); // Disable any special handling of received bytes
options.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
options.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
// Set VMIN and VTIME to 0, so it returns immediately when no data are present
// options.c_cc[VMIN] = 0;
// options.c_cc[VTIME] = 0;
// With threaded serial read we should rely on a blocking read() function so the loop doesn't run crazy => read() could block indefinitely.
// options.c_cc[VMIN] = 1;
// options.c_cc[VTIME] = 0;
// Block until either VMIN characters have been received or VTIME **after first character** has been received
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 1;
tcsetattr(fd, TCSANOW, &options);
/* No use ? Save it for later
// Set the serial port to non-blocking mode
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
*/
return 0;
}
/**
* The DCD (Data Carrier Detect) status of a serial port indicates whether a carrier is present on the line, meaning that a connection has been established with another device.
* @param fd File descriptor of JVS (serial) port
* @return 0|1 According to control line status
*/
int getDCD(int fd) {
int status;
ioctl(fd, TIOCMGET, &status);
return (status & TIOCM_CAR) != 0;
}
/**
* The DSR (Data Set Ready) status of a serial port indicates whether the device at the other end of the connection is ready to receive data.
* @param fd File descriptor of JVS (serial) port
* @return 0|1 According to control line status
*/
int getDSR(int fd) {
int status;
ioctl(fd, TIOCMGET, &status);
return (status & TIOCM_DSR) != 0;
}
/**
* The CTS (Clear To Send) status of a serial port indicates whether the device at the other end of the connection is ready to accept data.
* @param fd File descriptor of JVS (serial) port
* @return 0|1 According to control line status
*/
int getCTS(int fd) {
int status;
ioctl(fd, TIOCMGET, &status);
return (status & TIOCM_CTS) != 0;
}
/**
* In charge of reading serial port and bufferize JVS frame
* @param arg
* @return
*/
void *readJVSFrameThread(void * arg)
{
int fd = *((int *) arg);
int byteCount, bytesRead, ackSize, waitForEnd;
int ctsRetry = CTS_ON_RETRY;
char localBuffer[JVSBUFFER_SIZE];
while (1)
{
// Reset local variable
byteCount = 0;
ackSize = 0;
waitForEnd = 0;
do {
// printf("SERIAL thread debug: trying to read byte.\n");
// Try to read a byte from serial, this call will be blocking if VMIN > 0 and VTIME = 0
bytesRead = read(fd, &localBuffer[byteCount], 1);
// If nothing on serial and CTS is ON, we try to read "CTS_ON_RETRY" times
ctsRetry = CTS_ON_RETRY;
while (bytesRead < 1 && --ctsRetry > 0 && jvsFrameBuffer.ready == 0) {
bytesRead = read(fd, &localBuffer[byteCount], 1);
// printf("SERIAL: Retry number %d.\n", ctsRetry);
}
if (bytesRead > 0) {
// Sync byte, we will stick in the loop
if (byteCount == 0 && localBuffer[byteCount] == (char) 0xE0) {
waitForEnd = 1;
}
// Size byte
if (byteCount == 2) {
ackSize = localBuffer[byteCount] + 3;
}
// Start counting bytes only if SYNC has been found
if (waitForEnd) {
byteCount++;
}
// Reached the end of the message
if (byteCount == ackSize) {
waitForEnd = 0;
}
}
} while (waitForEnd);
// Lock the buffer while we write to it
pthread_mutex_lock(&jvsBuffer_lock);
memcpy(jvsFrameBuffer.buffer, localBuffer, byteCount);
jvsFrameBuffer.size = byteCount;
jvsFrameBuffer.ready = 1;
ctsRetry = CTS_ON_RETRY;
pthread_mutex_unlock(&jvsBuffer_lock);
}
return NULL;
}
/**
* Init the thread in charge of reading serial port
* @param fd
* @return 0|1
*/
int startJVSFrameThread(int * fd) {
int fdlocal = *((int *) fd);
printf("SERIAL: starting thread.\n");
// Clean shared JVS frame buffer
jvsFrameBuffer.ready = 0;
jvsFrameBuffer.size = 0;
memset(jvsFrameBuffer.buffer, 0, JVSBUFFER_SIZE);
pthread_t jvsFrameThread;
int ret = pthread_create(&jvsFrameThread, NULL, readJVSFrameThread, fd);
if (ret != 0)
{
printf("SERIAL: Failed to create reader thread\n");
return 1;
}
return 0;
}
/**
* Return a JVSFrame structure with empty or full data, no in between
* @return
*/
JVSFrame readJVSFrameFromThread() {
JVSFrame frame;
// Lock while reading/writing to shared frame
pthread_mutex_lock(&jvsBuffer_lock);
// Check if we have a valid frame
if (jvsFrameBuffer.ready == 1) {
frame = jvsFrameBuffer;
// It has been red, we disable this frame
jvsFrameBuffer.ready = 0;
} else {
frame.ready = 0;
frame.size = 0;
memset(frame.buffer, 0, JVSBUFFER_SIZE);
}
pthread_mutex_unlock(&jvsBuffer_lock);
return frame;
}

View File

@ -0,0 +1,20 @@
#define JVSBUFFER_SIZE 1024
typedef struct {
int ctsCounter;
int ready;
int size;
char buffer[JVSBUFFER_SIZE];
} JVSFrame;
int getDCD(int fd);
int getDSR(int fd);
int getCTS(int fd);
JVSFrame readJVSFrameFromThread();
int startJVSFrameThread(int * fd);
void * readJVSFrameThread(void * arg);
int openJVSSerial(char *jvsPath);
int initJVSSerial(int fd);
int readJVSFrame(int fd, unsigned char *buffer);