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>
This commit is contained in:
@@ -0,0 +1,950 @@
|
||||
#include "mungal4.h"
|
||||
#include <windows.h>
|
||||
#include "L4SERIAL.h"
|
||||
#include "L4PCSPAK.h"
|
||||
#include <assert.h>
|
||||
|
||||
//Win32 Serial support: ADB 02/10/07
|
||||
//------------------------------------------------
|
||||
// COM_INIT macro
|
||||
// Initializes COMBUF structure
|
||||
//------------------------------------------------
|
||||
void PCSerialPacket::COM_INIT(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
buffer->head = 0;
|
||||
buffer->tempHead = 0;
|
||||
buffer->tempTail = 0;
|
||||
buffer->tail = 0;
|
||||
|
||||
buffer->count = 0;
|
||||
buffer->tempIn = 0;
|
||||
buffer->tempOut = 0;
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_PUT_AL macro
|
||||
// 'Temporarily' puts character in AL into COMBUF
|
||||
//------------------------------------------------
|
||||
void PCSerialPacket::COM_PUT_AL(PCSerPackBuf* buffer, BYTE al)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
if(buffer->tempIn > COMBUFSIZE)
|
||||
{
|
||||
#if DIE_ON_OVERFLOW
|
||||
DISABLE_AND_DIE("Serial Packet Buffer Overflow!");
|
||||
#else
|
||||
ReleaseMutex(hMutex);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
buffer->tempIn++; //increment 'tempIn' count
|
||||
|
||||
buffer->data[buffer->tempHead] = al; //write the data
|
||||
|
||||
buffer->tempHead++; //bump 'tempHead'
|
||||
buffer->tempHead &= (COMBUFSIZE-1); //limit it
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_RESTORE_IN macro
|
||||
// Discards characters 'temporarily' placed in COMBUF
|
||||
//------------------------------------------------
|
||||
void PCSerialPacket::COM_RESTORE_IN(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
buffer->tempIn = 0; //clear the 'tempIn' count
|
||||
buffer->tempHead = buffer->head; //restore 'tempHead' index
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_ACCEPT_IN macro
|
||||
// Accepts characters 'temporarily' placed in COMBUF
|
||||
//------------------------------------------------
|
||||
void PCSerialPacket::COM_ACCEPT_IN(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
buffer->count += buffer->tempIn; //add to current count
|
||||
buffer->tempIn = 0;
|
||||
|
||||
buffer->head = buffer->tempHead; //set the new head offset
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_GET_AL macro
|
||||
// 'Temporarily' gets character into AL from COMBUF
|
||||
//------------------------------------------------
|
||||
int PCSerialPacket::COM_GET_AL(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
buffer->tempOut++; //inc 'tempOut' count
|
||||
|
||||
int al = buffer->data[buffer->tempTail]; //read the data
|
||||
|
||||
buffer->tempTail ++; //bump 'tempTail'
|
||||
buffer->tempTail &= (COMBUFSIZE-1); //limit it
|
||||
|
||||
ReleaseMutex(hMutex);
|
||||
return al;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_RESTORE_OUT macro
|
||||
// Restores characters 'temporarily' removed from COMBUF
|
||||
//------------------------------------------------
|
||||
void PCSerialPacket::COM_RESTORE_OUT(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
buffer->tempOut = 0; //clear the 'tempOut' count
|
||||
|
||||
buffer->tempTail = buffer->tail; //restore 'tempTail' index
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_ACCEPT_OUT macro
|
||||
// Discards characters 'temporarily' removed from COMBUF
|
||||
//------------------------------------------------
|
||||
void PCSerialPacket::COM_ACCEPT_OUT(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
buffer->count -= buffer->tempOut; //subtract from current count
|
||||
buffer->tempOut = 0; //clear 'tempOut' count
|
||||
|
||||
buffer->tail = buffer->tempTail; //set the new tail offset
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_EAT_PACKET macro
|
||||
// Discards entire buffer item from COMBUF
|
||||
//------------------------------------------------
|
||||
void PCSerialPacket::COM_EAT_PACKET(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
BYTE command = buffer->data[buffer->tail]; //read the packet command byte
|
||||
|
||||
command &= 0x07; //remove the MSB
|
||||
int length = this->rxLengthPtr[command]; //convert packet command to length
|
||||
length++; //include the command byte
|
||||
buffer->count -= length; //subtract from count
|
||||
|
||||
buffer->tail += length; //move the tail
|
||||
buffer->tail &= (COMBUFSIZE-1); //limit it
|
||||
buffer->tempTail = buffer->tail; //set the new tempTail index
|
||||
|
||||
buffer->tempOut = 0;
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_SPACE_IN macro
|
||||
// Returns input bytes available in COMBUF
|
||||
//------------------------------------------------
|
||||
int PCSerialPacket::COM_SPACE_IN(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
int available = COMBUFSIZE;
|
||||
available -= buffer->count;
|
||||
available -= buffer->tempIn;
|
||||
ReleaseMutex(hMutex);
|
||||
return available;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/13/07
|
||||
//------------------------------------------------
|
||||
// COM_SPACE_OUT macro
|
||||
// Returns output bytes available in COMBUF
|
||||
//------------------------------------------------
|
||||
int PCSerialPacket::COM_SPACE_OUT(PCSerPackBuf* buffer)
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
int output = buffer->count;
|
||||
output -= buffer->tempOut;
|
||||
ReleaseMutex(hMutex);
|
||||
return output;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 06/23/07
|
||||
PCSerialPacket::PCSerialPacket()
|
||||
{
|
||||
}
|
||||
|
||||
void PCSerialPacket::ShutdownRxThread()
|
||||
{
|
||||
//Win32 Serial support: ADB 06/23/07
|
||||
enabled = false;
|
||||
bThreadAbort = TRUE;
|
||||
if (overlapSend.hEvent != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(overlapSend.hEvent);
|
||||
overlapSend.hEvent = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if(hRxAbortEvent != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SetEvent(hRxAbortEvent);
|
||||
CloseHandle(hRxAbortEvent);
|
||||
hRxAbortEvent = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if(hRxThread != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WaitForSingleObject(hRxThread, INFINITE);
|
||||
CloseHandle(hRxThread);
|
||||
hRxThread = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if(hMutex != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hMutex);
|
||||
hMutex = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if(hComm != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hComm);
|
||||
hComm = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
PCSerialPacket::~PCSerialPacket()
|
||||
{
|
||||
if (this == NULL)
|
||||
{
|
||||
std::cout << "~PCSerialPacket() has been passed a NULL pointer\n" << std::flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShutdownRxThread();
|
||||
}
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 01/15/07
|
||||
// Only call Initialize(...) ONCE during the lifetime of the object!
|
||||
int PCSerialPacket::Initialize(WORD rate, WORD format, const char* port, BYTE* rxLengths, BYTE rxCount, BYTE* txLengths, BYTE txCount)
|
||||
{
|
||||
//;-------------------------------------------------------------------------
|
||||
//; PCSPAKInit()
|
||||
//; Constructor for serial packet driver interface
|
||||
//;-------------------------------------------------------------------------
|
||||
//; Enter:
|
||||
//; init_this = pointer to object
|
||||
//; init_port = address of serial port
|
||||
//; init_irq_num = interrupt number
|
||||
//; init_rx_len = pointer to (byte) receive length table
|
||||
//; init_tx_len = pointer to (byte) transmit length table
|
||||
//;-------------------------------------------------------------------------
|
||||
//; Returns:
|
||||
//; 1 if ok,
|
||||
//; -1 if IRQ's all used,
|
||||
//; -2 if DPMI error,
|
||||
//; -3 if really weird bogus error,
|
||||
//; else IIR value
|
||||
//;-------------------------------------------------------------------------
|
||||
|
||||
//DWORD return_status = 0;
|
||||
|
||||
//;--------------------------------------------------------------
|
||||
//; Clear the data buffers
|
||||
//;--------------------------------------------------------------
|
||||
COM_INIT(&rxBuf); //assumes esi points to object
|
||||
COM_INIT(&txBuf); //assumes esi points to object
|
||||
//;--------------------------------------------------------------
|
||||
//; Initialize values
|
||||
//;--------------------------------------------------------------
|
||||
enabled = 0;
|
||||
txHoldOff = 0;
|
||||
txReply = 0;
|
||||
rxFlags = 0;
|
||||
Error = 0;
|
||||
intDataPtr = 0;
|
||||
|
||||
historyIndex = 0;
|
||||
|
||||
txState = TX_IDLE_STATE; //initialize to idle state
|
||||
rxState = RX_IDLE_STATE; //initialize to idle state
|
||||
|
||||
|
||||
txLengthPtr = txLengths; //set dialect transmit table pointer
|
||||
txMaximum = txCount; //set maximum dialect transmit index
|
||||
|
||||
rxLengthPtr = rxLengths; //set dialect receive table pointer
|
||||
rxMaximum = rxCount; //set maximum dialect receive index
|
||||
|
||||
hComm = INVALID_HANDLE_VALUE;
|
||||
hRxAbortEvent = INVALID_HANDLE_VALUE;
|
||||
hRxThread = INVALID_HANDLE_VALUE;
|
||||
hMutex = INVALID_HANDLE_VALUE;
|
||||
bThreadAbort = FALSE;
|
||||
overlapSend.hEvent = INVALID_HANDLE_VALUE;
|
||||
|
||||
hComm = InitSerialPort(rate, format, port, true);
|
||||
if(hComm == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
enabled = 0;
|
||||
DWORD err = GetLastError();
|
||||
DEBUG_STREAM << "ERROR: InitSerialPort() failed [GetLastError() = " << GetLastError() << "]!\n" << std::flush;
|
||||
return PCSPAKWin32Err;
|
||||
}
|
||||
enabled = 1;
|
||||
|
||||
//Setup multi-threading for rx thread
|
||||
hMutex = CreateMutex(NULL, false, NULL);
|
||||
if(hMutex == NULL)
|
||||
{
|
||||
DEBUG_STREAM << "ERROR: CreateMutex() failed [GetLastError() = " << GetLastError() << "]!\n" << std::flush;
|
||||
enabled = 0;
|
||||
return PCSPAKWin32Err;
|
||||
}
|
||||
|
||||
if(!SetCommMask(hComm, EV_RXCHAR))
|
||||
{
|
||||
DEBUG_STREAM << "ERROR: SetCommMask() failed [GetLastError() = " << GetLastError() << "]!\n" << std::flush;
|
||||
enabled = 0;
|
||||
return PCSPAKWin32Err;
|
||||
}
|
||||
hRxAbortEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
hRxThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(&RxThreadProc), this, NULL, NULL);
|
||||
if(hRxThread == NULL)
|
||||
{
|
||||
DEBUG_STREAM << "ERROR: CreateThread() failed [GetLastError() = " << GetLastError() << "]!\n" << std::flush;
|
||||
enabled = 0;
|
||||
return PCSPAKWin32Err;
|
||||
}
|
||||
SetThreadPriority(hRxThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
|
||||
overlapSend.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
overlapSend.Internal = 0;
|
||||
overlapSend.InternalHigh = 0;
|
||||
overlapSend.Offset = 0;
|
||||
overlapSend.OffsetHigh = 0;
|
||||
|
||||
return PCSPAKInitOk;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 01/15/07
|
||||
Logical PCSerialPacket::TestInstance()
|
||||
{
|
||||
//return PCSPAKTestInstance(this);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 02/10/07
|
||||
//-------------------------------------------------------------------------
|
||||
// PCSPAKReceive()
|
||||
// Returns packet if available
|
||||
//-------------------------------------------------------------------------
|
||||
// Enter:
|
||||
// BYTE *destPtr = pointer to 128-byte destination buffer
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns:
|
||||
// int packetSize (or zero if no packet available)
|
||||
//-------------------------------------------------------------------------
|
||||
int PCSerialPacket::ReceivePacket(BYTE *destPtr) // returns len (zero if none)
|
||||
{
|
||||
if(!enabled)
|
||||
return 0;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Check character count: non-zero indicates entire packet
|
||||
//--------------------------------------------------------------
|
||||
if(rxBuf.count == 0)
|
||||
return 0;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Get buffer length
|
||||
//--------------------------------------------------------------
|
||||
BYTE c = COM_GET_AL(&rxBuf); //get character into al
|
||||
//--------------------------------------------------------------
|
||||
// Verify first char is a valid command character
|
||||
//--------------------------------------------------------------
|
||||
if((c & 0x80) == 0)
|
||||
{
|
||||
DISABLE_AND_DIE("Character was not a command character!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
BYTE *overflow = destPtr + COMBUFSIZE - 1;
|
||||
|
||||
*destPtr = c; //save it
|
||||
destPtr++;
|
||||
BYTE length = rxLengthPtr[c & 0x7F]; //translate into length
|
||||
int count = length; //save in edx
|
||||
count++; //return at least one character
|
||||
assert(length < 256);
|
||||
//--------------------------------------------------------------
|
||||
// Transfer data from buffer
|
||||
//--------------------------------------------------------------
|
||||
do
|
||||
{
|
||||
c = COM_GET_AL(&rxBuf); //get character into al
|
||||
*destPtr = c; //save it
|
||||
destPtr++;
|
||||
assert(destPtr < overflow);
|
||||
}while(--length > 0);
|
||||
|
||||
COM_ACCEPT_OUT(&rxBuf); //accept all 'taken' characters
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//Win32 Serial Support
|
||||
//-------------------------------------------------------------------------
|
||||
// PCSPAKSend()
|
||||
// Transmits packet
|
||||
//-------------------------------------------------------------------------
|
||||
// Enter:
|
||||
// BYTE *sp_src = pointer to (up to) 128-byte source buffer
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns:
|
||||
// void
|
||||
//-------------------------------------------------------------------------
|
||||
void PCSerialPacket::SendPacket(BYTE *srcPtr) //sends packet
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
// Wait for sufficient room
|
||||
//--------------------------------------------------------------
|
||||
if(!enabled) //if disabled, don't even try
|
||||
return;
|
||||
|
||||
BYTE cmd = *srcPtr; //get the command byte
|
||||
cmd &= 0x7F; //remove MSB
|
||||
int length = txLengthPtr[cmd]; //get the length in al
|
||||
length++; //add one for command byte
|
||||
|
||||
//This code has been replaced for your sanity:
|
||||
//while(COM_SPACE_IN(&txBuf) < length) //enough room?
|
||||
// DISABLE_AND_DIE("Not enough space in serial packet buffer");
|
||||
|
||||
////--------------------------------------------------------------
|
||||
//// Copy data into tx buffer
|
||||
////--------------------------------------------------------------
|
||||
//do
|
||||
//{
|
||||
// COM_PUT_AL(&txBuf, *srcPtr); //place it in the buffer
|
||||
// srcPtr++; //increment the source pointer
|
||||
//}
|
||||
//while(--length > 0);
|
||||
|
||||
//COM_ACCEPT_IN(&txBuf); //accept all 'placed' characters
|
||||
//
|
||||
////call StartSending ;attempt to start tx interrupt
|
||||
|
||||
//Sane code:
|
||||
BYTE *buffer = new BYTE[length + 1];//add one for the checksum
|
||||
memcpy(&buffer[0], srcPtr, length);//copy packet
|
||||
buffer[length] = 0;//initialize checksum
|
||||
for(int b=0; b<length; b++)//for each byte
|
||||
buffer[length] += buffer[b];//add to checksum;
|
||||
buffer[length] &= 0x007F;//limit checksum;
|
||||
|
||||
if(!WriteFile(hComm, &buffer[0], length + 1, NULL, &overlapSend))
|
||||
{
|
||||
DWORD errNum = GetLastError();
|
||||
if (errNum != ERROR_IO_PENDING)
|
||||
{
|
||||
DEBUG_STREAM << "Could not begin writing data to serial port (GetLastError() = " << GetLastError() << ")!\n" << std::flush;
|
||||
delete buffer;
|
||||
return;
|
||||
}
|
||||
}
|
||||
DWORD bytesWritten;
|
||||
GetOverlappedResult(hComm, &overlapSend, &bytesWritten, TRUE);
|
||||
if(bytesWritten != length + 1)
|
||||
{
|
||||
DEBUG_STREAM << "Not all data was written to serial port!\n" << std::flush;
|
||||
}
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 01/15/07
|
||||
int PCSerialPacket::ReceiveQueueCount()
|
||||
{
|
||||
//return PCSPAKReceiveCount(this);
|
||||
return rxBuf.count;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 01/15/07
|
||||
int PCSerialPacket::TransmitQueueCount()
|
||||
{
|
||||
//return PCSPAKTransmitCount(this);
|
||||
return txBuf.count;
|
||||
}
|
||||
|
||||
//Win32 Serial Support: ADB 02/25/2007
|
||||
void PCSerialPacket::SetDTR(Logical on)
|
||||
{
|
||||
EscapeCommFunction(hComm, on ? SETDTR : CLRDTR);
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 01/15/2007
|
||||
//-------------------------------------------------------------------------
|
||||
// PCSPAKActive()
|
||||
// Returns transmitter 'active' state (=0 when all transmission is done).
|
||||
//-------------------------------------------------------------------------
|
||||
// This function is now deprecated.
|
||||
int PCSerialPacket::IsActive()
|
||||
{
|
||||
//return PCSPAKActive(this);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 01/15/07
|
||||
Word PCSerialPacket::Errors()// returns error value, clears it
|
||||
{
|
||||
//return PCSPAKErrors(this);
|
||||
return Error;
|
||||
}
|
||||
|
||||
//Win32 Serial support: ADB 06/25/07
|
||||
//The folowing code has been ommited for your sanity
|
||||
//-------------------------------------------------------------------------
|
||||
// SendChar - send character through UART
|
||||
// ...called from the interrupt routine and PCSPAK::sendCommand.
|
||||
//-------------------------------------------------------------------------
|
||||
// Enter:
|
||||
// ESI = pointer to PCSPAK structure
|
||||
// DX = UART base address
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns:
|
||||
// (void)
|
||||
//-------------------------------------------------------------------------
|
||||
// Side effects:
|
||||
// registers EAX, EBX, ECX modified
|
||||
//-------------------------------------------------------------------------
|
||||
// void SendChar()
|
||||
// {
|
||||
// //--------------------------------------------------------------
|
||||
// // Send reply character if one is waiting
|
||||
// //--------------------------------------------------------------
|
||||
// if(txReply == 0)//"reply" character waiting?
|
||||
// goto noReply;//no, continue
|
||||
//
|
||||
// TransmitCommChar(hComm, txReply);//yes, send the reply character
|
||||
// txReply = 0;//get and clear the "reply" character
|
||||
// goto sendDone;//done for now.
|
||||
//noReply:
|
||||
// //--------------------------------------------------------------
|
||||
// // Enter the appropriate state handler
|
||||
// //--------------------------------------------------------------
|
||||
// if(txState == TX_IDLE_STATE)//idle state?
|
||||
// goto txIdleState;//yes, go to it
|
||||
//
|
||||
// if(txState == TX_BODY_STATE)//"body" state?
|
||||
// goto txBodyState;//yes, go to it
|
||||
//
|
||||
// if(txState == TX_WAIT_STATE)//"wait" state?
|
||||
// goto txWaitState;//yes, go to it
|
||||
//
|
||||
// if(txState == TX_RESTART_STATE)//restart state?
|
||||
// goto txRestartState;//yes, go to it
|
||||
//
|
||||
// DISABLE_AND_DIE("Unknown Send State!");
|
||||
// goto txWaitState;//must be "wait" state
|
||||
// //--------------------------------------------------------------
|
||||
// // Transmitter idle state
|
||||
// //--------------------------------------------------------------
|
||||
//txIdleState:
|
||||
// if(txHoldOff != 0)//If transmitter 'held off', do nothing
|
||||
// goto txIsIdle;
|
||||
//
|
||||
// if(txBuf.count != 0)//input buffer available?
|
||||
// goto txIdleAvail;//yes, send something
|
||||
//txIsIdle:
|
||||
// //nothing to send, just return
|
||||
// goto sendDone;
|
||||
//
|
||||
//txIdleAvail:
|
||||
// //---------------------------
|
||||
// // Buffer ready, start
|
||||
// //---------------------------
|
||||
// txResetCount = TXMAXRESET;//set the 'reset' counter
|
||||
// txErrorCount = TXMAXERROR;//set the 'error' counter
|
||||
//
|
||||
// //...deliberately fall through into 'txRestartState'
|
||||
//
|
||||
// //--------------------------------------------------------------
|
||||
// // Transmitter restart state
|
||||
// //--------------------------------------------------------------
|
||||
//txRestartState:
|
||||
// BYTE al = COM_GET_AL(&txBuf);//assumes esi points to object
|
||||
//
|
||||
// if(al <= 0x007F)//is it a command?
|
||||
// goto txRestartBad;//no, discard it
|
||||
//
|
||||
// BYTE ah = al & 0x007F;//remove MSB
|
||||
// if(ah < txMaximum)//legitimate command?
|
||||
// goto txRestartOk;//yes
|
||||
//
|
||||
//txRestartBad:
|
||||
// DISABLE_AND_DIE("Unknown Command In Send Queue!");
|
||||
// COM_ACCEPT_OUT(&txBuf);//eat the character
|
||||
// txState = TX_IDLE_STATE;//move to the "idle" state
|
||||
// goto sendDone;
|
||||
//
|
||||
//txRestartOk:
|
||||
// TransmitCommChar(hComm, al);//transmit the command character
|
||||
// txChecksum = al;//begin a new checksum count
|
||||
//
|
||||
// //look up length
|
||||
// //include the command byte
|
||||
// txCount = txLengthPtr[ah] + 1;//save the length
|
||||
//
|
||||
// txState = TX_BODY_STATE;//move to the "body" state
|
||||
// goto sendDone;
|
||||
//
|
||||
// //--------------------------------------------------------------
|
||||
// // Transmitter "body" state
|
||||
// // Send message body, then checksum (unless interrupted by ACK/NAK)
|
||||
// //--------------------------------------------------------------
|
||||
//txBodyState:
|
||||
// //---------------------------
|
||||
// // Interrupted by ACK/NAK?
|
||||
// //---------------------------
|
||||
// if(rxFlags == 0)//flag set?
|
||||
// goto txBodySend;//no, send normal body
|
||||
//
|
||||
// COM_RESTORE_OUT(&txBuf);//interrupted, reset 'out' pointer
|
||||
//
|
||||
// BYTE flags = rxFlags;//get flags
|
||||
// rxFlags = 0;//clear them
|
||||
//
|
||||
// if((flags & RX_ACK_BIT) != 0)//was it an ACK?
|
||||
// goto txBodyNak;//no
|
||||
// Error |= TX_EARLY_ERR;//yes, set error flag
|
||||
//txBodyNak:
|
||||
// //---------------------------
|
||||
// // Restart or die
|
||||
// //---------------------------
|
||||
// txResetCount--;//check the restart count
|
||||
// if(txResetCount <= 0)
|
||||
// goto txBodyGiveUp;//if too many errors, give up
|
||||
// //---------------------------
|
||||
// // Attempt restart
|
||||
// //---------------------------
|
||||
// TransmitCommChar(hComm, (BYTE)RESTART_CHAR);//no, send restart character
|
||||
//
|
||||
// txState = TX_RESTART_STATE;//move to the "restart" state
|
||||
// goto sendDone;
|
||||
// //---------------------------
|
||||
// // Too many errors, die!
|
||||
// //---------------------------
|
||||
//txBodyGiveUp:
|
||||
// Error |= TX_ABANDON;//set error flag
|
||||
// COM_EAT_PACKET(&txBuf);//discard current packet
|
||||
// goto txIdleState;//start another packet
|
||||
// //---------------------------
|
||||
// // Send body or checksum
|
||||
// //---------------------------
|
||||
//txBodySend:
|
||||
// txCount--;//is buffer done?
|
||||
// if(txCount <= 0)
|
||||
// goto txBodyCheck;//yes, send checksum
|
||||
// //---------------------------
|
||||
// // Send a body character
|
||||
// //---------------------------
|
||||
// al = COM_GET_AL(&txBuf);//get a character from the buffer
|
||||
//
|
||||
// if((al & 0x007F) == 0)//legitimate body char?
|
||||
// goto txBodyOk;//yes, continue
|
||||
// DISABLE_AND_DIE("Invalid Body Char In Send Queue!");
|
||||
// al &= 0x007F;//prevent bad data from becoming command
|
||||
//txBodyOk:
|
||||
// TransmitCommChar(hComm, al);
|
||||
// txChecksum += al;//add to the checksum
|
||||
// goto sendDone;
|
||||
// //---------------------------
|
||||
// // End of body, send checksum
|
||||
// //---------------------------
|
||||
//txBodyCheck:
|
||||
// al = txChecksum;//get the checksum
|
||||
// al &= 0x007F;//limit it
|
||||
// TransmitCommChar(hComm, al);//send it
|
||||
// //---------------------------
|
||||
// // prepare for "wait" state
|
||||
// //---------------------------
|
||||
// txIdleCount = TXMAXIDLE;//set the idle counter
|
||||
// txState = TX_WAIT_STATE;//move to the "wait" state
|
||||
// goto sendDone;
|
||||
//
|
||||
// //--------------------------------------------------------------
|
||||
// // Transmitter "wait" state
|
||||
// // Waits for reply from other end
|
||||
// //--------------------------------------------------------------
|
||||
//txWaitState:
|
||||
// flags = rxFlags;//get flags, also clear them
|
||||
// rxFlags = 0;
|
||||
// if(flags == 0)//flags clear?
|
||||
// goto txWaitMore;//yes, keep waiting
|
||||
//
|
||||
// if((flags & RX_ACK_BIT) == 0)//ACK?
|
||||
// goto txWaitNak;//no, process NAK
|
||||
// //---------------------------
|
||||
// // ACK, buffer received OK
|
||||
// //---------------------------
|
||||
// COM_ACCEPT_OUT(&txBuf);//yes, good transmission. Discard packet.
|
||||
// txState = TX_IDLE_STATE;//move to the "idle" state
|
||||
// goto txIdleState;//start another buffer
|
||||
// //---------------------------
|
||||
// // NAK!
|
||||
// //---------------------------
|
||||
//txWaitNak:
|
||||
// Error |= TX_NAK;//set error flag
|
||||
// COM_RESTORE_OUT(&txBuf);//restore output pointers
|
||||
//
|
||||
// txErrorCount--;//check the error count
|
||||
// if(txErrorCount == 0)
|
||||
// goto txWaitGiveUp;//if too many errors, give up
|
||||
// goto txRestartState;//no, resend it
|
||||
// //---------------------------
|
||||
// // Keep waiting
|
||||
// //---------------------------
|
||||
//txWaitMore:
|
||||
// txIdleCount--;//have we waited too long?
|
||||
// if(txIdleCount == 0)
|
||||
// goto txWaitDone;//yes, attempt to restart
|
||||
//
|
||||
// TransmitCommChar(hComm, (BYTE)IDLE_CHAR);//no, send idle character
|
||||
// goto sendDone;
|
||||
// //---------------------------
|
||||
// // Attempt restart
|
||||
// //---------------------------
|
||||
//txWaitDone:
|
||||
// Error |= TX_RESTART;//set error flag
|
||||
// COM_RESTORE_OUT(&txBuf);//restore output pointers
|
||||
//
|
||||
// txResetCount--;//too many restarts?
|
||||
// if(txResetCount == 0)
|
||||
// goto txWaitGiveUp;//yes, abandon buffer
|
||||
//
|
||||
// TransmitCommChar(hComm, (BYTE)RESTART_CHAR);//no, send restart character
|
||||
//
|
||||
// txIdleCount = TXMAXIDLE;//reset the idle counter
|
||||
// txState = TX_RESTART_STATE;//move to the "idle" state
|
||||
// goto sendDone;
|
||||
// //---------------------------
|
||||
// // Give up
|
||||
// //---------------------------
|
||||
//txWaitGiveUp:
|
||||
// Error |= TX_ABANDON;//set error flag
|
||||
// COM_EAT_PACKET(&txBuf);//discard the packet
|
||||
// txState = TX_IDLE_STATE;//move to the "idle" state
|
||||
// goto txIdleState;//start another packet
|
||||
//sendDone:
|
||||
// return;
|
||||
// }
|
||||
|
||||
//Win32 Serial support: ADB 06/23/07
|
||||
//RX Thread Proc
|
||||
DWORD WINAPI RxThreadProc(LPVOID lpParameter)
|
||||
{
|
||||
//DEBUG_STREAM<<"RX Thread Running!\n"<<std::flush;
|
||||
PCSerialPacket* pcPack = (PCSerialPacket*)lpParameter;
|
||||
//DEBUG_STREAM<<"RX Max: "<<(unsigned int)pcPack->rxMaximum<<"\n";
|
||||
//initialize com port event
|
||||
OVERLAPPED o;
|
||||
o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
o.Internal = 0;
|
||||
o.InternalHigh = 0;
|
||||
o.Offset = 0;
|
||||
o.OffsetHigh = 0;
|
||||
|
||||
HANDLE events[] = {pcPack->hRxAbortEvent, o.hEvent};
|
||||
|
||||
while(true)
|
||||
{
|
||||
DWORD dwEvent;
|
||||
//DEBUG_STREAM<<"Waiting for Data...\n"<<std::flush;
|
||||
WaitCommEvent(pcPack->hComm, &dwEvent, &o);
|
||||
if(WaitForMultipleObjects(2, &events[0], FALSE, INFINITE) == WAIT_OBJECT_0)//indicates that the abort event was triggered
|
||||
if(pcPack->bThreadAbort)//if we really are supposed to abort
|
||||
break;//then abort
|
||||
|
||||
//perform read
|
||||
BYTE buffer[COMBUFSIZE];
|
||||
memset(&buffer, 0, COMBUFSIZE);
|
||||
DWORD bytesRead = 0;
|
||||
//DEBUG_STREAM << "Reading Data\n" << std::flush;
|
||||
ReadFile(pcPack->hComm, &buffer[0], COMBUFSIZE, NULL, &o);
|
||||
GetOverlappedResult(pcPack->hComm, &o, &bytesRead, TRUE);
|
||||
|
||||
//process data
|
||||
//DEBUG_STREAM<<"Received "<<bytesRead<<" bytes! {"<<std::flush;
|
||||
for(DWORD b = 0; b < bytesRead; b++)
|
||||
{
|
||||
//if (buffer[b] == 135)
|
||||
//DEBUG_STREAM << "Received AnalogReply: " << GetTickCount() << std::endl << std::flush;
|
||||
//DEBUG_STREAM<<"0x"<<std::hex<<(unsigned int)(BYTE)buffer[b]<<std::dec<<std::flush;
|
||||
//if(b < bytesRead - 1)
|
||||
// DEBUG_STREAM<<", ";
|
||||
//--------------------------------------------------------------
|
||||
// Process universal special characters: ACK, NAK, IDLE
|
||||
//--------------------------------------------------------------
|
||||
if(((unsigned int)buffer[b] & 0x0080) == 0)//MSB set?
|
||||
goto rcNotSpecial;//no, can't be special character
|
||||
//------------------------------
|
||||
// IDLE
|
||||
//------------------------------
|
||||
|
||||
if((unsigned int)buffer[b] != IDLE_CHAR)//IDLE character?
|
||||
goto rcNotIdle;//no
|
||||
goto recvDone;//yes, ignore it
|
||||
rcNotIdle:
|
||||
//------------------------------
|
||||
// ACK
|
||||
//------------------------------
|
||||
if((unsigned int)buffer[b] != ACK_CHAR)//ACK character?
|
||||
goto rcNotAck;//no
|
||||
pcPack->rxFlags |= RX_ACK_BIT;//yes, flag for transmitter
|
||||
goto recvDone;
|
||||
rcNotAck:
|
||||
//------------------------------
|
||||
// NAK
|
||||
//------------------------------
|
||||
if((unsigned int)buffer[b] != NAK_CHAR)//NAK character?
|
||||
goto rcNotNak;//no
|
||||
pcPack->rxFlags |= RX_NAK_BIT;//yes, flag for transmitter
|
||||
goto recvDone;
|
||||
rcNotNak:
|
||||
rcNotSpecial:
|
||||
//--------------------------------------------------------------
|
||||
// Process state-dependent characters
|
||||
//--------------------------------------------------------------
|
||||
if(pcPack->rxState != 0)//test the state
|
||||
goto rxActive;//non-zero, so active
|
||||
//--------------------------------------------------------------
|
||||
// Receiver "idle" state
|
||||
// Wait for command character
|
||||
//--------------------------------------------------------------
|
||||
if(((unsigned int)buffer[b] & 0x0080) != 0)//is it a control character?
|
||||
goto rxIdleSpecial;//yes, process it
|
||||
|
||||
pcPack->Error |= RX_SEQ_ERR;//Not expecting data, so error.
|
||||
goto recvDone;
|
||||
rxIdleSpecial:
|
||||
if((unsigned int)buffer[b] == RESTART_CHAR)//restart?
|
||||
goto recvDone;//yes, discard it
|
||||
|
||||
unsigned int bx = pcPack->COM_SPACE_IN(&pcPack->rxBuf);//get remaining space
|
||||
if(bx != 0)//zero?
|
||||
goto rxIdleSpace;//no, continue
|
||||
DEBUG_STREAM<<"RX Buffer Full!"<<std::flush;
|
||||
DISABLE_AND_DIE("RX Buffer Full!");
|
||||
pcPack->Error |= RX_COM_ERR;//error. Set flag.
|
||||
goto recvDone;
|
||||
rxIdleSpace:
|
||||
unsigned int ah = (unsigned int)buffer[b];//move to ah for testing
|
||||
ah &= 0x007F;//remove MSB
|
||||
if(ah < pcPack->rxMaximum)//legitimate command?
|
||||
goto rxIdleOk;//yes, continue
|
||||
|
||||
DEBUG_STREAM<<"RX Unknown Command!"<<std::flush;
|
||||
DISABLE_AND_DIE("RX Unknown Command!");
|
||||
pcPack->Error |= RX_COM_ERR;//no.
|
||||
goto recvDone;
|
||||
rxIdleOk:
|
||||
pcPack->COM_PUT_AL(&pcPack->rxBuf, buffer[b]);//save command character in buffer
|
||||
pcPack->rxChecksum = buffer[b];//start a new receive checksum
|
||||
|
||||
pcPack->rxCount = pcPack->rxLengthPtr[ah] + 1;//save the length
|
||||
|
||||
pcPack->rxState = RX_ACTIVE_STATE;//change to "active" state
|
||||
goto recvDone;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Receiver "active" state
|
||||
// Place N characters into buffer, test checksum, and reply
|
||||
//--------------------------------------------------------------
|
||||
rxActive:
|
||||
if(((unsigned int)buffer[b] & 0x0080) == 0)//control character?
|
||||
goto rxActiveData;//no, therefore data
|
||||
|
||||
pcPack->Error |= RX_SEQ_ERR;//yes, error. Set error flag
|
||||
pcPack->COM_RESTORE_IN(&pcPack->rxBuf);//Discard received data
|
||||
//------------------------------
|
||||
// Process control char
|
||||
//------------------------------
|
||||
if((unsigned int)buffer[b] == RESTART_CHAR)//restart character?
|
||||
goto rxActiveAbandon;//yes, abandon received data
|
||||
|
||||
pcPack->txReply = NAK_CHAR;//error, tell transmitter to send NAK
|
||||
goto rxActiveReply;
|
||||
//------------------------------
|
||||
// Process data
|
||||
//------------------------------
|
||||
rxActiveData:
|
||||
pcPack->rxCount--;//check the receive count
|
||||
if(pcPack->rxCount <= 0)
|
||||
goto rxActiveCheck;//if end of message, process checksum
|
||||
//------------------------------
|
||||
// Enough space in buffer?
|
||||
//------------------------------
|
||||
bx = pcPack->COM_SPACE_IN(&pcPack->rxBuf);//get remaining space
|
||||
|
||||
if(bx != 0)//zero?
|
||||
goto rxActiveSpace;//no, continue
|
||||
|
||||
DEBUG_STREAM<<"RX Buffer Full @ 2!"<<std::flush;
|
||||
DISABLE_AND_DIE("RX Buffer Full @ 2!");
|
||||
pcPack->Error |= RX_COM_ERR;//error. Set flag.
|
||||
pcPack->COM_RESTORE_IN(&pcPack->rxBuf);//Discard received data
|
||||
goto rxActiveAbandon;//give up on packet
|
||||
|
||||
rxActiveSpace:
|
||||
//------------------------------
|
||||
// Save data in buffer
|
||||
//------------------------------
|
||||
pcPack->rxChecksum += buffer[b];//update the checksum
|
||||
pcPack->COM_PUT_AL(&pcPack->rxBuf, buffer[b]);//save the character
|
||||
goto recvDone;
|
||||
//------------------------------
|
||||
// Test checksum
|
||||
//------------------------------
|
||||
rxActiveCheck:
|
||||
unsigned int bl = pcPack->rxChecksum;//get the checksum
|
||||
bl &= 0x007F;//remove MSB
|
||||
if(bl == buffer[b])//checksum OK?
|
||||
goto rxActiveOk;//yes!
|
||||
//------------------------------
|
||||
// Buffer error
|
||||
//------------------------------
|
||||
pcPack->Error |= RX_BAD_CHECKSUM;//error. Set flag.
|
||||
pcPack->COM_RESTORE_IN(&pcPack->rxBuf);//Discard received data
|
||||
pcPack->txReply = NAK_CHAR;//tell transmitter to send NAK
|
||||
TransmitCommChar(pcPack->hComm, (char)NAK_CHAR);
|
||||
goto rxActiveReply;
|
||||
//------------------------------
|
||||
// Buffer OK
|
||||
//------------------------------
|
||||
rxActiveOk:
|
||||
pcPack->COM_ACCEPT_IN(&pcPack->rxBuf);//accept the received data
|
||||
pcPack->txReply = ACK_CHAR;//tell transmitter to send ACK
|
||||
TransmitCommChar(pcPack->hComm, (char)ACK_CHAR);
|
||||
rxActiveReply:
|
||||
//call StartSending ;restart transmitter if needed
|
||||
//------------------------------
|
||||
// Return to inactive state
|
||||
//------------------------------
|
||||
rxActiveAbandon:
|
||||
pcPack->rxState = RX_IDLE_STATE;
|
||||
recvDone:
|
||||
;
|
||||
}
|
||||
//DEBUG_STREAM<<"}\n"<<std::flush;
|
||||
}
|
||||
|
||||
CloseHandle(o.hEvent);
|
||||
DEBUG_STREAM<<"Exiting RX Thread!\n"<<std::flush;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user