Files
CydandClaude Opus 4.8 4abbf8879f Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:

- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies

Removed stale Subversion metadata and added .gitignore/.gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 07:59:51 -05:00

288 lines
6.8 KiB
C++

#include <windows.h>
#include <assert.h>
#include "L4SERIAL.h"
HANDLE InitSerialPort(WORD rate, WORD format, const char* port, bool overlapped)
{
HANDLE hComm = INVALID_HANDLE_VALUE;
hComm = CreateFileA(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, overlapped ? FILE_FLAG_OVERLAPPED : NULL, NULL);
if(hComm == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
DEBUG_STREAM << "ERROR: CreateFileA() failed [GetLastError() = " << GetLastError() << "]!\n" << std::flush;
return INVALID_HANDLE_VALUE;
}
DCB control;
memset(&control, 0, sizeof(control));
control.DCBlength = sizeof(control);
control.EvtChar = (char)0xFF;
if(rate == PCS_300)
control.BaudRate = 300;
else if(rate == PCS_1200)
control.BaudRate = 1200;
else if(rate == PCS_2400)
control.BaudRate = 2400;
else if(rate == PCS_9600)
control.BaudRate = 9600;
else if(rate == PCS_19P2)
control.BaudRate = 19200;
else if(rate == PCS_38P4)
control.BaudRate = 38400;
else if(rate == PCS_115K)
control.BaudRate = 115200;
else
{
DEBUG_STREAM << "ERROR: Invalid Baud Rate!\n" << std::flush;
CloseHandle(hComm);
return INVALID_HANDLE_VALUE;
}
if((format & PCSMAP) == PCSNP)
control.Parity = NOPARITY;
else if((format & PCSMAP) == PCSOP)
control.Parity = ODDPARITY;
else if((format & PCSMAP) == PCSEP)
control.Parity = EVENPARITY;
else if((format & PCSMAP) == PCSMP)
control.Parity = MARKPARITY;
else if((format & PCSMAP) == PCSSP)
control.Parity = SPACEPARITY;
else
{
DEBUG_STREAM << "ERROR: Invalid Parity!\n" << std::flush;
CloseHandle(hComm);
return INVALID_HANDLE_VALUE;
}
if((format & PCSMD) == PCS8D)
control.ByteSize = 8;
else if((format & PCSMD) == PCS6D)
control.ByteSize = 6;
else if((format & PCSMD) == PCS7D)
control.ByteSize = 7;
else if((format & PCSMD) == PCS8D)
control.ByteSize = 8;
else
{
DEBUG_STREAM << "ERROR: Invalid Byte Size!\n" << std::flush;
CloseHandle(hComm);
return INVALID_HANDLE_VALUE;
}
if((format & PCSMS) == PCS1S)
control.StopBits = ONESTOPBIT;
else if((format & PCSMS) == PCS2S)
control.StopBits = TWOSTOPBITS;
else
{
DEBUG_STREAM << "ERROR: Invalid Stop Bits!\n" << std::flush;
CloseHandle(hComm);
return INVALID_HANDLE_VALUE;
}
if(!SetCommState(hComm, &control))
{
DEBUG_STREAM << "ERROR: SetCommState() failed [rate = " << control.BaudRate;
DEBUG_STREAM << ", dataBits = " << control.ByteSize;
DEBUG_STREAM << ", stopBits = " << control.StopBits;
DEBUG_STREAM << ", parity = " << control.Parity << "!\n";
CloseHandle(hComm);
return INVALID_HANDLE_VALUE;
}
//Non-blocking
COMMTIMEOUTS timeout;
timeout.ReadIntervalTimeout = MAXDWORD;
timeout.ReadTotalTimeoutConstant = 0;
timeout.ReadTotalTimeoutMultiplier = 0;
timeout.WriteTotalTimeoutConstant = 0;
timeout.WriteTotalTimeoutMultiplier = 0;
if(!SetCommTimeouts(hComm, &timeout))
{
DEBUG_STREAM << "ERROR: SetCommTimeouts() failed!\n";
CloseHandle(hComm);
return INVALID_HANDLE_VALUE;
}
PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
return hComm;
}
//Win32 Serial support: ADB 01/11/07
PCSerial::PCSerial(WORD rate, WORD format, const char* port)
//PCSerial(DWORD rate, BYTE dataBits, BYTE stopBits, BYTE parity, const WCHAR* port)
{
enabled = 0;
mOverlappedOb.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
mOverlappedOb.Internal = 0;
mOverlappedOb.InternalHigh = 0;
mOverlappedOb.Offset = 0;
mOverlappedOb.OffsetHigh = 0;
//PCSerialInit(this, rate, format, port, int_num);
hComm = InitSerialPort(rate, format, port, true);
if(hComm != INVALID_HANDLE_VALUE)
enabled = 1;
}
PCSerial::~PCSerial()
{
if (this == NULL)
{
std::cout << "~PCSerial has been passed a NULL pointer\n" << std::flush;
}
else
{
WaitForSingleObject(mOverlappedOb.hEvent,INFINITE);
CloseHandle(mOverlappedOb.hEvent);
CloseHandle(hComm);
hComm = INVALID_HANDLE_VALUE;
enabled = 0;
}
}
//Win32 Serial support: ADB 01/15/07
Logical PCSerial::TestInstance()
{
//return PCSerialTestInstance(this);
return 1;
}
//Win32 Serial support: ADB 01/15/07
int PCSerial::ReceiveString(char *destPtr, int maxLen) // returns length
{
//TODO: Do overlapped reads if we ever need this function again
assert(FALSE);
//return PCSerialReceive(this, destPtr, maxLen)
DWORD bytesRead;
ReadFile(hComm, (void *)destPtr, maxLen, &bytesRead, NULL);
return (int)bytesRead;
}
//Win32 Serial support: ADB 01/15/07
void PCSerial::FlowControlEnable(Logical onOff)
{
//STUBBED: Serial ADB 01/15/07
//VERIFY: Probably not used
//PCSerialFlowControl(this, (int) onOff);DCB control;
}
Logical PCSerial::CanDraw()
{
return (WaitForSingleObject(mOverlappedOb.hEvent, 0) == WAIT_OBJECT_0);
}
//Win32 Serial support: ADB 01/15/07
void PCSerial::SendString(char *srcPtr, int length)
{
//PCSerialSend(this, srcPtr, length);
WaitForSingleObject(mOverlappedOb.hEvent, INFINITE);
DWORD bytesWritten;
WriteFile(hComm, (void*)srcPtr, length, &bytesWritten, &mOverlappedOb);
}
//Win32 Serial support: ADB 01/15/07
int PCSerial::ReceiveCharCount()
{
//return PCSerialReceiveCount(this);
COMMPROP props;
if(!GetCommProperties(hComm, &props))
{
DEBUG_STREAM << "ERROR: GetCommProperties() failed in TransmitCharCount()! GetLastError() = " << GetLastError() << std::endl;
return 0;
}
return props.dwCurrentRxQueue;
}
//Win32 Serial support: ADB 01/15/07
int PCSerial::TransmitCharCount()
{
//return PCSerialTransmitCount(this);
COMMPROP props;
if(!GetCommProperties(hComm, &props))
{
DEBUG_STREAM << "ERROR: GetCommProperties() failed in TransmitCharCount()! GetLastError() = " << GetLastError() << std::endl;
return 0;
}
return props.dwCurrentTxQueue;
}
//Win32 Serial support: ADB 01/15/07
int PCSerial::Errors() // returns error value, clears it
{
//return PCSerialErrors(this);
DWORD errors;
if(!ClearCommError(hComm, &errors, NULL))
{
DEBUG_STREAM << "ERROR: GetCommError() failed!\n";
return PCS_ERR_OTHER;
}
int outError = 0;
if(errors & CE_OVERRUN)
{
outError |= PCS_ERR_OVERRUN;
errors ^= CE_OVERRUN;
}
if(errors & CE_RXPARITY)
{
outError |= PCS_ERR_PARITY;
errors ^= CE_RXPARITY;
}
if(errors & CE_FRAME)
{
outError |= PCS_ERR_FRAMING;
errors ^= CE_FRAME;
}
if(errors & CE_BREAK)
{
outError |= PCS_ERR_BREAK;
errors ^= CE_BREAK;
}
if(errors & CE_RXOVER)
{
outError |= PCS_ERR_RXOVER;
errors ^= CE_RXOVER;
}
if(errors & CE_TXFULL)
{
outError |= PCS_ERR_TXOVER;
errors ^= CE_TXFULL;
}
//other error
if(errors)
outError |= PCS_ERR_OTHER;
return outError;
}
//Win32 Serial support: ADB 01/15/07
int PCSerial::IsActive()
{
//return PCSerialActive(this);
return enabled;
}
//Win32 Serial support: ADB 01/15/07
int PCSerial::ModemStatus()
{
//return PCSerialModemStatus(this);
DWORD modem;
if(!GetCommModemStatus(hComm, &modem))
{
DEBUG_STREAM << "ERROR: GetCommModemStatus() failed!\n";
return 0;
}
return modem;
}