emu48-mirror/sources/Emu48/SERIAL.C

262 lines
6.6 KiB
C
Raw Normal View History

2024-03-19 22:24:30 +01:00
/*
* Serial.c
*
* This file is part of Emu48
*
* Copyright (C) 1998 Christoph Gie<EFBFBD>elink
*
*/
#include "pch.h"
#include "Emu48.h"
2024-03-19 22:25:45 +01:00
#include "io.h" // 24.10.99 cg, renamed from Serial.h
2024-03-19 22:24:30 +01:00
#define INTERRUPT ((void)(Chipset.SoftInt=TRUE,bInterrupt=TRUE))
2024-03-19 22:25:45 +01:00
// 25.10.99 cg, new, state of USRQ
#define NINT2ERBZ ((Chipset.IORam[IOC] & ERBZ) != 0 && (Chipset.IORam[RCS] & RBZ) != 0)
#define NINT2ERBF ((Chipset.IORam[IOC] & ERBF) != 0 && (Chipset.IORam[RCS] & RBF) != 0)
#define NINT2ETBE ((Chipset.IORam[IOC] & ETBE) != 0 && (Chipset.IORam[TCS] & TBF) == 0)
#define NINT2USRQ (NINT2ERBZ || NINT2ERBF || NINT2ETBE)
2024-03-19 22:24:30 +01:00
static OVERLAPPED os = { 0 };
static HANDLE hComm = NULL;
static HANDLE hCThread = NULL;
static DWORD lSerialThreadId = 0;
static BOOL bReading = TRUE;
static WORD wPort = PORT_CLOSE;
2024-03-19 22:25:45 +01:00
static BYTE cBuffer[128];
static WORD nRp;
static DWORD dwBytesRead = 0L;
// static CRITICAL_SECTION csRecv; // 24.10.99 cg, moved to main function
2024-03-19 22:24:30 +01:00
static DWORD WINAPI SerialThread(LPVOID pParam)
{
DWORD dwEvent;
SetCommMask(hComm,EV_RXCHAR); // event on RX
while (bReading)
{
_ASSERT(hComm != NULL);
WaitCommEvent(hComm,&dwEvent,NULL); // wait for serial event
if (dwEvent & EV_RXCHAR) // signal char received
{
CommReceive(); // get data
// interrupt request and emulation thread down
if (Chipset.SoftInt && Chipset.Shutdn)
2024-03-19 22:25:45 +01:00
{
Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode
SetEvent(hEventShutdn); // wake up emulation thread
}
2024-03-19 22:24:30 +01:00
}
}
lSerialThreadId = 0; // signal serial thread is down
return 0;
UNREFERENCED_PARAMETER(pParam);
}
WORD CommConnect(VOID)
{
return wPort;
}
VOID CommOpen(LPSTR strWirePort,LPSTR strIrPort)
{
COMMTIMEOUTS CommTimeouts = { MAXDWORD, 0L, 0L, 0L, 0L };
LPSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort;
2024-03-19 22:25:45 +01:00
_ASSERT(Chipset.IORam[IOC] & SON); // UART on
2024-03-19 22:24:30 +01:00
if (hComm != NULL) // port already open
CloseHandle(hComm);
2024-03-19 22:25:45 +01:00
if (strcmp(strPort, NO_SERIAL)) // port defined
2024-03-19 22:24:30 +01:00
{
hComm = CreateFile(strPort,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if(hComm != INVALID_HANDLE_VALUE)
{
2024-03-19 22:25:45 +01:00
// InitializeCriticalSection(&csRecv);
2024-03-19 22:24:30 +01:00
wPort = (Chipset.IORam[IR_CTRL] & EIRU) ? PORT_IR : PORT_WIRE;
SetCommTimeouts(hComm,&CommTimeouts);
CommSetBaud();
// set event RXD handler
bReading = TRUE;
hCThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&SerialThread,NULL,0,&lSerialThreadId);
_ASSERT(lSerialThreadId);
}
else
hComm = NULL;
}
#if defined DEBUG_SERIAL
{
char buffer[256];
wsprintf(buffer,"COM port %s.\n",hComm ? "opened": "open error");
OutputDebugString(buffer);
}
#endif
2024-03-19 22:25:45 +01:00
return;
2024-03-19 22:24:30 +01:00
}
VOID CommClose(VOID)
{
if (hComm != NULL) // port open
{
bReading = FALSE; // kill read thread
SetCommMask(hComm,0L); // clear all events and force WaitCommEvent to return
while (lSerialThreadId != 0) Sleep(0); // wait for termination
CloseHandle(hComm); // close port
hComm = NULL;
#if defined DEBUG_SERIAL
OutputDebugString("COM port closed.\n");
#endif
2024-03-19 22:25:45 +01:00
// DeleteCriticalSection(&csRecv);
2024-03-19 22:24:30 +01:00
wPort = PORT_CLOSE;
}
2024-03-19 22:25:45 +01:00
return;
2024-03-19 22:24:30 +01:00
}
VOID CommSetBaud(VOID)
{
if (hComm != NULL)
{
const DWORD dwBaudrates[] = { 1200, 1920, 2400, 3840, 4800, 7680, 9600, 15360 };
DCB dcb;
FillMemory(&dcb,sizeof(dcb),0);
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = dwBaudrates[Chipset.IORam[BAUD] & 0x7];
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fOutX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE; // may changed in further implementations
dcb.ByteSize = 8;
dcb.Parity = NOPARITY; // no parity check, emulated by software
dcb.StopBits = ONESTOPBIT;
#if defined DEBUG_SERIAL
{
char buffer[256];
wsprintf(buffer,"CommsetBaud: %ld\n",dcb.BaudRate);
OutputDebugString(buffer);
}
#endif
SetCommState(hComm,&dcb);
}
2024-03-19 22:25:45 +01:00
return;
}
VOID UpdateUSRQ(VOID) // 25.10.99 cg, new, USRQ handling
{
IOBit(SRQ1,USRQ,NINT2USRQ); // update USRQ bit
return;
2024-03-19 22:24:30 +01:00
}
VOID CommTransmit(VOID)
{
DWORD dwWritten;
BYTE tbr = (Chipset.IORam[TBR_MSB] << 4) | Chipset.IORam[TBR_LSB];
#if defined DEBUG_SERIAL
{
char buffer[256];
if (isprint(tbr))
wsprintf(buffer,"-> '%c'\n",tbr);
else
wsprintf(buffer,"-> %02X\n",tbr);
OutputDebugString(buffer);
}
#endif
2024-03-19 22:25:45 +01:00
// 23.10.99 cg, bugfix, add serial loopback support
if (Chipset.IORam[TCS] & LPB) // is loopback bit set
{
cBuffer[nRp+dwBytesRead] = tbr; // save character in receive buffer
++dwBytesRead;
CommReceive(); // receive byte available
}
// 23.10.99 cg, end of implementation
if (hComm != NULL) // com port open
2024-03-19 22:24:30 +01:00
WriteFile(hComm,(LPCVOID) &tbr,1,&dwWritten,&os);
Chipset.IORam[TCS] &= (~TBF); // clear transmit buffer
2024-03-19 22:25:45 +01:00
UpdateUSRQ(); // 25.10.99 cg, bugfix, update USRQ bit
if (Chipset.IORam[IOC] & ETBE) // interrupt on transmit buffer empty
2024-03-19 22:24:30 +01:00
INTERRUPT;
2024-03-19 22:25:45 +01:00
return;
2024-03-19 22:24:30 +01:00
}
VOID CommReceive(VOID)
{
2024-03-19 22:25:45 +01:00
if (!(Chipset.IORam[IOC] & SON)) // UART off
2024-03-19 22:24:30 +01:00
{
dwBytesRead = 0L; // no bytes received
return;
}
2024-03-19 22:25:45 +01:00
EnterCriticalSection(&csRecvLock);
2024-03-19 22:24:30 +01:00
do
{
if (Chipset.IORam[RCS] & RBF) // receive buffer full
break;
2024-03-19 22:25:45 +01:00
// 23.10.99 cg, bugfix, reject reading if com port is closed and not whole operation
if (hComm && dwBytesRead == 0L) // com port open and buffer empty
2024-03-19 22:24:30 +01:00
{
if(ReadFile(hComm,&cBuffer,sizeof(cBuffer),&dwBytesRead,&os) == FALSE)
dwBytesRead = 0L;
else // bytes received
nRp = 0; // reset read pointer
}
if(dwBytesRead == 0L) // receive buffer empty
break;
#if defined DEBUG_SERIAL
{
char buffer[256];
if (isprint(cBuffer[nRp]))
wsprintf(buffer,"<- '%c'\n",cBuffer[nRp]);
else
wsprintf(buffer,"<- %02X\n",cBuffer[nRp]);
OutputDebugString(buffer);
}
#endif
Chipset.IORam[RBR_MSB] = (cBuffer[nRp] >> 4);
Chipset.IORam[RBR_LSB] = (cBuffer[nRp] & 0x0f);
++nRp;
--dwBytesRead;
Chipset.IORam[RCS] |= RBF; // receive buffer full
2024-03-19 22:25:45 +01:00
UpdateUSRQ(); // 25.10.99 cg, bugfix, update USRQ bit
if (Chipset.IORam[IOC] & ERBF) // interrupt on recv buffer full
2024-03-19 22:24:30 +01:00
INTERRUPT;
}
while(0);
2024-03-19 22:25:45 +01:00
LeaveCriticalSection(&csRecvLock);
return;
2024-03-19 22:24:30 +01:00
}