8 Commits

Author SHA1 Message Date
Stephanie Gawroriski
e8f6529bec Initial attempt at serial port support. 2024-06-14 22:44:19 -04:00
Stephanie Gawroriski
5e5e21e302 Move up definition. 2024-06-14 19:13:52 -04:00
Stephanie Gawroriski
8223b6fd76 No longer crash the Qt interface if it could not initialize audio. 2024-06-14 18:56:56 -04:00
Stephanie Gawroriski
dee65d0d1a Fill initial RAM with garbage so PalmOS is much more likely to find it invalid; Add RetroArch run command if it exists in PATH. 2024-06-14 18:49:21 -04:00
LibretroAdmin
865acf3a28 Update Makefile.libretro 2023-11-01 19:20:58 -07:00
Stephanie Gawroriski
15bb26daa5 Merge pull request #29 from warmenhoven/dev/warmenhoven/tvos
Add tvos build
2023-05-27 18:38:29 -04:00
Eric Warmenhoven
dc854cef9e Add tvos build 2023-05-27 17:43:15 -04:00
Stephanie Gawroriski
91a46734dd Merge pull request #28 from libretro/wip-macosarmfix
Attempt fix of macOS ARM build (Fixes #27).
2023-01-23 08:55:17 -05:00
21 changed files with 1732 additions and 1281 deletions

View File

@@ -58,6 +58,10 @@ include:
- project: 'libretro-infrastructure/ci-templates'
file: '/ios-arm64.yml'
# tvOS
- project: 'libretro-infrastructure/ci-templates'
file: '/tvos-arm64.yml'
################################## CONSOLES ################################
# Dingux (GCW Zero)
- project: 'libretro-infrastructure/ci-templates'
@@ -192,6 +196,12 @@ libretro-build-ios-arm64:
- .libretro-ios-arm64-make-default
- .core-defs
# tvOS
libretro-build-tvos-arm64:
extends:
- .libretro-tvos-arm64-make-default
- .core-defs
################################### CONSOLES #################################
# Dingux (GCW Zero)
libretro-build-dingux-mips32:

View File

@@ -17,6 +17,10 @@ message("that you are resting well.")
message(" -- Your friend, Stephanie")
message("******************************")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(EMU_DEBUG=1)
endif()
# Main project sources
add_subdirectory(src)

View File

@@ -710,6 +710,7 @@ static void setUstcnt2(uint16_t value){
registerArrayWrite16(USTCNT2, value);
updateUart2Interrupt();
updateUart2PortState();
}
static void setTstat1(uint16_t value){

View File

@@ -404,6 +404,9 @@ static void dbvzEndClk32(void){
updateUart1Interrupt();
updateUart2Interrupt();
updateUart1PortState();
updateUart2PortState();
checkInterrupts();
}

View File

@@ -45,13 +45,15 @@ static void debugLog(char* str, ...){};
//config options
#define EMU_FPS 60
#define DBVZ_SYSCLK_PRECISION 2000000//the amount of cycles to run before adding SYSCLKs, higher = faster, higher values may skip timer events and lower audio accuracy
#define AUDIO_SAMPLE_RATE 48000
#define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLE_RATE / EMU_FPS)
#define AUDIO_SPEAKER_RANGE 0x6000//prevent hitting the top or bottom of the speaker when switching direction rapidly
#define SD_CARD_NCR_BYTES 1//how many 0xFF bytes come before the R1 response
#define SAVE_STATE_VERSION 0x00000001
//shared constants
#define AUDIO_SAMPLES_PER_FRAME (AUDIO_SAMPLE_RATE / EMU_FPS)
#define SD_CARD_BLOCK_SIZE 512//all newer SDSC cards have this fixed at 512
#define SD_CARD_BLOCK_DATA_PACKET_SIZE (1 + SD_CARD_BLOCK_SIZE + 2)
#define SD_CARD_RESPONSE_FIFO_SIZE (SD_CARD_BLOCK_DATA_PACKET_SIZE * 3)
@@ -107,7 +109,7 @@ enum{
};
//types
typedef struct{
typedef struct {
bool enable;
bool enableParity;
bool oddParity;
@@ -213,7 +215,11 @@ extern void (*palmSerialDataFlush)(void);//called by the emulator to delete
extern void (*palmGetRtcFromHost)(uint8_t* writeBack);//[0] = hours, [1] = minutes, [2] = seconds
//functions
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t palmRomSize, uint8_t* palmBootloaderData, uint32_t palmBootloaderSize, bool syncRtc, bool allowInvalidBehavior);
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
uint32_t palmRomSize, uint8_t *palmBootloaderData,
uint32_t palmBootloaderSize, bool syncRtc,
bool allowInvalidBehavior, const char *serialPortDev);
void emulatorDeinit(void);
void emulatorHardReset(void);
void emulatorSoftReset(void);

18
include/serial.h Normal file
View File

@@ -0,0 +1,18 @@
//
// Created by stephanie on 6/14/24.
//
#ifndef MU_SERIAL_H
#define MU_SERIAL_H
#include "emulator.h"
/**
* Opens and initializes the serial port.
*
* @param path The path of the serial port.
* @since 2024/06/14
*/
void mu_serial_open_and_init(const char* path);
#endif // MU_SERIAL_H

View File

@@ -14,6 +14,10 @@ add_library(mu_libretro SHARED
# Remove the "lib" prefix always, RetroArch does not name in this way
set_target_properties(mu_libretro PROPERTIES PREFIX "")
# Define these
target_compile_definitions(mu_libretro PUBLIC
__LIBRETRO__=1)
# Bring all the sub-modules as needed
target_link_libraries(mu_libretro
MuCore)
@@ -32,6 +36,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL Windows)
set(MU_LIBRETRO_DIR "$ENV{APPDATA}/RetroArch")
endif()
else()
find_program(RETROARCH_APP retroarch)
if(RETROARCH_APP)
get_filename_component(MU_LIBRETRO_DIR "${RETROARCH_APP}" DIRECTORY)
endif()
set(MU_LIBRETRO_EXTENSION "")
endif()

View File

@@ -186,6 +186,8 @@ else ifeq ($(platform), tvos-arm64)
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk appletvos Path)
endif
CC = clang -arch arm64 -isysroot $(IOSSDK)
CXX = clang++ -arch arm64 -isysroot $(IOSSDK)
# Theos iOS
else ifeq ($(platform), theos_ios)
@@ -391,7 +393,9 @@ else ifneq (,$(findstring armv,$(platform)))
# Emscripten
else ifeq ($(platform), emscripten)
TARGET := $(TARGET_NAME)_libretro_emscripten.bc
AR=emar
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# GCW0
else ifeq ($(platform), gcw0)
@@ -535,9 +539,7 @@ all: $(TARGET)
$(TARGET): $(OBJECTS)
@echo "** BUILDING $(TARGET) FOR PLATFORM $(platform) **"
ifeq ($(platform), emscripten)
$(CC) $(CFLAGS) $(OBJOUT)$@ $^
else ifeq ($(STATIC_LINKING_LINK), 1)
ifeq ($(STATIC_LINKING_LINK), 1)
ifneq (,$(findstring msvc,$(platform)))
$(LD) $(LINKOUT)$@ $(OBJECTS)
else

File diff suppressed because it is too large Load Diff

View File

@@ -221,6 +221,7 @@ SOURCES += \
../../src/audio/blip_buf.c \
../../src/dbvz.c \
../../src/emulator.c \
../../src/serial.c \
../../src/fileLauncher/launcher.c \
../../src/flx68000.c \
../../src/m5XXBus.c \

File diff suppressed because it is too large Load Diff

View File

@@ -54,7 +54,9 @@ public:
EmuWrapper();
~EmuWrapper();
uint32_t init(const QString& assetPath, const QString& osVersion, bool syncRtc = false, bool allowInvalidBehavior = false, bool fastBoot = false);
uint32_t init(const QString &assetPath, const QString &osVersion,
bool syncRtc = false, bool allowInvalidBehavior = false,
bool fastBoot = false, const QString &serialPortDev = "");
void exit();
void pause();
void resume();

View File

@@ -47,6 +47,7 @@ MainWindow::MainWindow(QWidget* parent) :
stateManager = new StateManager(this);
emuDebugger = new DebugViewer(this);
refreshDisplay = new QTimer(this);
audioDevice = new QAudioOutput(format, this);
audioOut = audioDevice->start();
@@ -226,7 +227,10 @@ void MainWindow::updateDisplay(){
ui->display->repaint();
//audio
audioOut->write((const char*)emu.getAudioSamples(), AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
if (audioOut != NULL) {
audioOut->write((const char*)emu.getAudioSamples(),
AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
}
//power LED
ui->powerButtonLed->setStyleSheet(emu.getPowerButtonLed() ? "background: lime" : "");
@@ -329,7 +333,14 @@ void MainWindow::on_center_released(){
void MainWindow::on_ctrlBtn_clicked(){
if(!emu.isInited()){
QString sysDir = settings->value("resourceDirectory", "").toString();
uint32_t error = emu.init(sysDir, settings->value("palmOsVersionString", "Palm m515/Palm OS 4.1").toString(), settings->value("featureSyncedRtc", false).toBool(), settings->value("featureDurable", false).toBool(), settings->value("fastBoot", false).toBool());
uint32_t error = emu.init(
sysDir,
settings->value("palmOsVersionString", "Palm m515/Palm OS 4.1")
.toString(),
settings->value("featureSyncedRtc", false).toBool(),
settings->value("featureDurable", false).toBool(),
settings->value("fastBoot", false).toBool(),
settings->value("serialPortDev", "").toString());
if(error == EMU_ERROR_NONE){
emu.setCpuSpeed(settings->value("cpuSpeed", 1.00).toDouble());

View File

@@ -31,6 +31,10 @@ SettingsManager::SettingsManager(QWidget* parent) :
ui->featureSyncedRtc->setChecked(settings->value("featureSyncedRtc", false).toBool());
ui->featureDurable->setChecked(settings->value("featureDurable", false).toBool());
ui->serialPortDev->setText(settings->value("serialPortDev",
"").toString());
connect(ui->serialPortDev, &QLineEdit::textChanged, this, &SettingsManager::on_serialPortDev_textChanged);
setKeySelectorState(-1);
updateButtonKeys();
}
@@ -166,3 +170,7 @@ void SettingsManager::on_palmOsVersion_currentIndexChanged(int index){
settings->setValue("palmOsVersionIndex", index);
settings->setValue("palmOsVersionString", ui->palmOsVersion->itemText(index));
}
void SettingsManager::on_serialPortDev_textChanged(const QString& arg1) {
settings->setValue("serialPortDev", ui->serialPortDev->text());
}

View File

@@ -51,6 +51,8 @@ private slots:
void on_cpuSpeed_valueChanged(double arg1);
void on_palmOsVersion_currentIndexChanged(int index);
void on_serialPortDev_textChanged(const QString& arg1);
private:
Ui::SettingsManager* ui;
QSettings* settings;

View File

@@ -29,9 +29,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<y>-284</y>
<width>613</width>
<height>444</height>
<height>705</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
@@ -430,6 +430,16 @@
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="serialPortDevLabel">
<property name="text">
<string>Serial Port Device</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="serialPortDev"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View File

@@ -3,6 +3,7 @@ add_library(MuCore STATIC
ads7846.c
dbvz.c
emulator.c
serial.c
flx68000.c
m5XXBus.c
pdiUsbD12.c

View File

@@ -475,17 +475,26 @@ uint8_t dbvzGetRegister8(uint32_t address){
//PDSEL lacks the bottom 4 bits but that is handled on write
return registerArrayRead8(address);
case URX1:
case URX1 + 1:
case URX2:
case URX2 + 1:
return registerArrayRead16(address);
default:
printHwRegAccess(address, 0, 8, false);
//bootloader
if(address >= 0xE00)
return registerArrayRead8(address);
printHwRegAccess(address, 0, 8, false);
return 0x00;
}
}
uint16_t dbvzGetRegister16(uint32_t address){
uint16_t bit;
#if !defined(EMU_NO_SAFETY)
if((address & 0x0000F000) != 0x0000F000){
dbvzSetBusErrorTimeOut(address, false);
@@ -520,6 +529,16 @@ uint16_t dbvzGetRegister16(uint32_t address){
}
case UTX1:{
#if defined(EMU_DEBUG)
printHwRegAccess(address, 0, 16, false);
#endif
uint16_t dataFlag = 0;
if (palmIrDataSize != NULL)
if (palmIrDataSize() > 0) {
dataFlag = 0x4000; // byte swapped
updateUart1Interrupt();
}
uint16_t uart1TxStatus = registerArrayRead16(UTX1);
uint8_t entrys = uart1TxFifoEntrys();
@@ -527,10 +546,20 @@ uint16_t dbvzGetRegister16(uint32_t address){
uart1TxStatus |= (entrys < 4) << 14;
uart1TxStatus |= (entrys < 8) << 13;
return uart1TxStatus;
return uart1TxStatus | dataFlag;
}
case UTX2:{
#if defined(EMU_DEBUG)
printHwRegAccess(address, 0, 16, false);
#endif
uint16_t dataFlag = 0;
if (palmSerialDataSize != NULL)
if (palmSerialDataSize() > 0) {
dataFlag = 0x4000; // byte swapped
updateUart2Interrupt();
}
uint16_t uart2TxStatus = registerArrayRead16(UTX2);
uint8_t entrys = uart2TxFifoEntrys();
@@ -538,7 +567,7 @@ uint16_t dbvzGetRegister16(uint32_t address){
uart2TxStatus |= (entrys < 4) << 14;
uart2TxStatus |= (entrys < 8) << 13;
return uart2TxStatus;
return uart2TxStatus | dataFlag;
}
case PLLFSR:
@@ -599,11 +628,12 @@ uint16_t dbvzGetRegister16(uint32_t address){
return registerArrayRead16(address);
default:
printHwRegAccess(address, 0, 16, false);
//bootloader
if(address >= 0xE00)
return registerArrayRead16(address);
printHwRegAccess(address, 0, 16, false);
return 0x0000;
}
}
@@ -668,6 +698,7 @@ void dbvzSetRegister8(uint32_t address, uint8_t value){
if((registerArrayRead16(USTCNT2) & 0xA000) == 0xA000){
uart2TxFifoWrite(value);
updateUart2Interrupt();
updateUart2PortState();
}
return;
@@ -1128,6 +1159,7 @@ void dbvzSetRegister16(uint32_t address, uint16_t value){
if((registerArrayRead16(USTCNT2) & 0xA000) == 0xA000){
uart2TxFifoWrite(value & 0x1000 ? value & 0xFF : EMU_SERIAL_BREAK);
updateUart2Interrupt();
updateUart2PortState();
}
return;

View File

@@ -11,6 +11,7 @@
#include "ads7846.h"
#include "pdiUsbD12.h"
#include "sdCard.h"
#include "serial.h"
#include "silkscreen.h"
#include "portability.h"
#if defined(EMU_SUPPORT_PALM_OS5)
@@ -99,8 +100,28 @@ static void patchOsRom(uint32_t address, char* patch){
swap16BufferIfLittle(&palmRom[swapBegin], swapSize);
}
/**
* Fills the initial RAM with garbage.
*
* @param ram The RAM to fill.
* @param size The size of RAM.
* @since 2024/06/14
*/
void mu_garbage_fill(uint8_t* ram, uint32_t size) {
uint32_t i;
uint8_t vis;
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t palmRomSize, uint8_t* palmBootloaderData, uint32_t palmBootloaderSize, bool syncRtc, bool allowInvalidBehavior){
vis = 179;
for (i = 0; i < size; i++) {
ram[i] = vis;
vis = ((vis << 1) | ((vis >> 7) & 1)) ^ 0xFF;
}
}
uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t *palmRomData,
uint32_t palmRomSize, uint8_t *palmBootloaderData,
uint32_t palmBootloaderSize, bool syncRtc,
bool allowInvalidBehavior, const char *serialPortDev) {
if(emulatorInitialized)
return EMU_ERROR_RESOURCE_LOCKED;
@@ -115,13 +136,19 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t pal
palmIrDataReceive = NULL;
palmIrDataSend = NULL;
palmIrDataFlush = NULL;
palmSerialSetPortProperties = NULL;
palmSerialDataSize = NULL;
palmSerialDataReceive = NULL;
palmSerialDataSend = NULL;
palmSerialDataFlush = NULL;
palmGetRtcFromHost = NULL;
// Setup serial port
palmSerialSetPortProperties = NULL;
palmSerialDataSize = NULL;
palmSerialDataReceive = NULL;
palmSerialDataSend = NULL;
palmSerialDataFlush = NULL;
if (serialPortDev != NULL) {
mu_serial_open_and_init(serialPortDev);
}
#if defined(EMU_SUPPORT_PALM_OS5)
palmEmulatingTungstenT3 = emulatedDevice == EMU_DEVICE_TUNGSTEN_T3;
@@ -173,7 +200,9 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t pal
//allocate buffers, add 4 to memory regions to prevent SIGSEGV from accessing off the end
palmRom = malloc(M5XX_ROM_SIZE + 4);
palmRam = malloc((palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) + 4);
palmRam = malloc((emulatorGetRamSize()) + 4);
palmFramebuffer = malloc(160 * 220 * sizeof(uint16_t));
palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
@@ -191,7 +220,10 @@ uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t pal
if(palmRomSize < M5XX_ROM_SIZE)
memset(palmRom + palmRomSize, 0x00, M5XX_ROM_SIZE - palmRomSize);
swap16BufferIfLittle(palmRom, M5XX_ROM_SIZE / sizeof(uint16_t));
memset(palmRam, 0x00, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
memset(palmRam, 0x00, emulatorGetRamSize());
mu_garbage_fill(palmRam, emulatorGetRamSize());
dbvzLoadBootloader(palmBootloaderData, palmBootloaderSize);
memcpy(palmFramebuffer + 160 * 160, silkscreen160x60, 160 * 60 * sizeof(uint16_t));
memset(palmAudio, 0x00, AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
@@ -262,7 +294,7 @@ void emulatorHardReset(void){
}
else{
#endif
memset(palmRam, 0x00, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
memset(palmRam, 0x00, emulatorGetRamSize());
emulatorSoftReset();
sdCardReset();
dbvzSetRtc(0, 0, 0, 0);
@@ -330,7 +362,7 @@ uint32_t emulatorGetStateSize(void){
size += sed1376StateSize();
size += ads7846StateSize();
size += pdiUsbD12StateSize();
size += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;//system RAM buffer
size += emulatorGetRamSize();//system RAM buffer
#if defined(EMU_SUPPORT_PALM_OS5)
}
#endif
@@ -402,9 +434,9 @@ bool emulatorSaveState(uint8_t* data, uint32_t size){
offset += pdiUsbD12StateSize();
//memory
memcpy(data + offset, palmRam, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
swap16BufferIfLittle(data + offset, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
offset += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
memcpy(data + offset, palmRam, emulatorGetRamSize());
swap16BufferIfLittle(data + offset, (emulatorGetRamSize()) / sizeof(uint16_t));
offset += emulatorGetRamSize();
#if defined(EMU_SUPPORT_PALM_OS5)
}
#endif
@@ -526,9 +558,9 @@ bool emulatorLoadState(uint8_t* data, uint32_t size){
offset += pdiUsbD12StateSize();
//memory
memcpy(palmRam, data + offset, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
swap16BufferIfLittle(palmRam, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
offset += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
memcpy(palmRam, data + offset, emulatorGetRamSize());
swap16BufferIfLittle(palmRam, (emulatorGetRamSize()) / sizeof(uint16_t));
offset += emulatorGetRamSize();
#if defined(EMU_SUPPORT_PALM_OS5)
}
#endif
@@ -608,7 +640,9 @@ uint32_t emulatorGetRamSize(void){
if(palmEmulatingTungstenT3)
return TUNGSTEN_T3_RAM_SIZE;
#endif
return palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
if (palmEmulatingM500)
return M500_RAM_SIZE;
return M515_RAM_SIZE;
}
bool emulatorSaveRam(uint8_t* data, uint32_t size){
@@ -621,11 +655,11 @@ bool emulatorSaveRam(uint8_t* data, uint32_t size){
}
else{
#endif
if(size < (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE))
if(size < (emulatorGetRamSize()))
return false;
memcpy(data, palmRam, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
swap16BufferIfLittle(data, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
memcpy(data, palmRam, emulatorGetRamSize());
swap16BufferIfLittle(data, (emulatorGetRamSize()) / sizeof(uint16_t));
#if defined(EMU_SUPPORT_PALM_OS5)
}
#endif
@@ -643,11 +677,11 @@ bool emulatorLoadRam(uint8_t* data, uint32_t size){
}
else{
#endif
if(size < (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE))
if(size < (emulatorGetRamSize()))
return false;
memcpy(palmRam, data, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
swap16BufferIfLittle(palmRam, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
memcpy(palmRam, data, emulatorGetRamSize());
swap16BufferIfLittle(palmRam, (emulatorGetRamSize()) / sizeof(uint16_t));
#if defined(EMU_SUPPORT_PALM_OS5)
}
#endif

View File

@@ -1,5 +1,6 @@
EMU_DEFINES :=
EMU_SOURCES_C := $(EMU_PATH)/emulator.c \
$(EMU_PATH)/serial.c \
$(EMU_PATH)/m5XXBus.c \
$(EMU_PATH)/dbvz.c \
$(EMU_PATH)/flx68000.c \

255
src/serial.c Normal file
View File

@@ -0,0 +1,255 @@
//
// Created by stephanie on 6/14/24.
//
#include <stdio.h>
#include <string.h>
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#include <windows.h>
#else
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#endif
#include "emulator.h"
#define MU_SERIAL_DEBUG
#define MU_SERIAL_BUF_SIZE 4096
static const char* mu_serial_path = NULL;
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#else
static int mu_serial_fd = -1;
#endif
static uint8_t mu_serial_buf[MU_SERIAL_BUF_SIZE];
static int32_t mu_serial_buf_len;
static serial_port_properties_t mu_serial_properties;
void mu_serial_palmSerialSetPortProperties(serial_port_properties_t* properties)
{
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#else
struct termios tty;
#endif
// Always use base properties
if (properties == NULL) {
properties = &mu_serial_properties;
}
// Did the properties not actually change?
if (0 == memcmp(properties, &mu_serial_properties,
sizeof(mu_serial_properties))) {
return;
}
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial PROPERTIES\n");
#endif
// Write over new properties
memmove(&mu_serial_properties, properties,
sizeof(mu_serial_properties));
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#else
if (properties->enable && mu_serial_fd < 0) {
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial OPEN %s\n", mu_serial_path);
#endif
mu_serial_fd = open(mu_serial_path,
O_RDWR | O_EXCL | O_NONBLOCK);
if (mu_serial_fd < 0) {
fprintf(stderr, "Serial FAIL %s\n",
strerror(errno));
return;
}
mu_serial_buf_len = 0;
} else if (!properties->enable && mu_serial_fd >= 0) {
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial CLOSE %s\n", mu_serial_path);
#endif
close(mu_serial_fd);
mu_serial_fd = -1;
mu_serial_buf_len = 0;
}
if (mu_serial_fd >= 0) {
memset(&tty, 0, sizeof(tty));
cfsetspeed(&tty, properties->baudRate);
if (properties->enableParity) {
tty.c_cflag |= PARENB;
}
if (properties->oddParity) {
tty.c_cflag |= PARODD;
}
if (properties->stopBits > 1) {
tty.c_cflag |= CSTOPB;
} else {
tty.c_cflag &= (~CSTOPB);
}
if (properties->use8BitMode) {
tty.c_cflag |= CS8;
} else {
tty.c_lflag &= (~CSIZE);
tty.c_cflag |= CS7;
}
}
#endif
}
uint32_t mu_serial_palmSerialDataSize(void)
{
int32_t read_count;
// Do not read any more data if there is any
if (mu_serial_buf_len > 0) {
return mu_serial_buf_len;
}
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#else
if (mu_serial_fd >= 0) {
// Try reading in as much as possible
if (mu_serial_buf_len < MU_SERIAL_BUF_SIZE) {
read_count = read(mu_serial_fd,
&mu_serial_buf[mu_serial_buf_len],
MU_SERIAL_BUF_SIZE - mu_serial_buf_len);
if (read_count > 0) {
mu_serial_buf_len += read_count;
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial FLOW %d < %d\n",
mu_serial_buf_len, read_count);
#endif
}
}
}
#endif
return mu_serial_buf_len;
}
uint16_t mu_serial_palmSerialDataReceive(void)
{
uint8_t data;
uint32_t buf_len;
// Get size of current buffer
buf_len = mu_serial_palmSerialDataSize();
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial RECV TRY %d\n", mu_serial_buf_len);
#endif
// No data to read?
if (buf_len == 0 || mu_serial_buf_len == 0) {
return 0;
}
// Read in next byte
data = mu_serial_buf[0];
// Shift over
memmove(&mu_serial_buf[0], &mu_serial_buf[1],
mu_serial_buf_len - 1);
mu_serial_buf_len -= 1;
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial RECV %02x %c\n", data, data);
#endif
// Give the byte we read
return data;
}
void mu_serial_palmSerialDataSend(uint16_t data)
{
uint8_t part;
// Only need to send the lower bit
part = data & 0xFF;
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#else
if (mu_serial_fd >= 0) {
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial SEND %02x %c\n", part, part);
#endif
write(mu_serial_fd, &part, 1);
fsync(mu_serial_fd);
}
#endif
}
void mu_serial_palmSerialDataFlush(void)
{
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#else
if (mu_serial_fd >= 0) {
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial DROP\n");
#endif
tcflush(mu_serial_fd, TCIFLUSH);
}
#endif
}
void mu_serial_open_and_init(const char* path)
{
mu_serial_path = strdup(path);
#if defined(__LIBRETRO__)
#elif defined(_WIN32)
#else
mu_serial_fd = -1;
#endif
#if defined(MU_SERIAL_DEBUG)
// Debug
fprintf(stderr, "Serial PORT %s\n", mu_serial_path);
#endif
// Set functions to use
palmSerialSetPortProperties = mu_serial_palmSerialSetPortProperties;
palmSerialDataSize = mu_serial_palmSerialDataSize;
palmSerialDataReceive = mu_serial_palmSerialDataReceive;
palmSerialDataSend = mu_serial_palmSerialDataSend;
palmSerialDataFlush = mu_serial_palmSerialDataFlush;
}