AppleWin/AppleWin/source/SerialComms.cpp

302 lines
8.8 KiB
C++

/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
AppleWin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
AppleWin is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Description: Enhanced //e & //c serial port emulation
*
* Author: Various
*/
#include "StdAfx.h"
#pragma hdrstop
static DWORD baudrate = CBR_19200;
static BYTE bytesize = 8;
static BYTE commandbyte = 0x00;
static HANDLE commhandle = INVALID_HANDLE_VALUE;
static DWORD comminactivity = 0;
static BYTE controlbyte = 0x1F;
static BYTE parity = NOPARITY;
static BYTE recvbuffer[9];
static DWORD recvbytes = 0;
DWORD serialport = 0;
static BYTE stopbits = ONESTOPBIT;
static void UpdateCommState ();
//===========================================================================
static BOOL CheckComm () {
comminactivity = 0;
if ((commhandle == INVALID_HANDLE_VALUE) && serialport) {
TCHAR portname[8];
wsprintf(portname,
TEXT("COM%u"),
serialport);
commhandle = CreateFile(portname,
GENERIC_READ | GENERIC_WRITE,
0,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
0,
NULL);
if (commhandle != INVALID_HANDLE_VALUE) {
UpdateCommState();
COMMTIMEOUTS ct;
ZeroMemory(&ct,sizeof(COMMTIMEOUTS));
ct.ReadIntervalTimeout = MAXDWORD;
SetCommTimeouts(commhandle,&ct);
}
}
return (commhandle != INVALID_HANDLE_VALUE);
}
//===========================================================================
static void CheckReceive () {
if (recvbytes || (commhandle == INVALID_HANDLE_VALUE))
return;
ReadFile(commhandle,recvbuffer,8,&recvbytes,NULL);
}
//===========================================================================
static void CloseComm () {
if (commhandle != INVALID_HANDLE_VALUE)
CloseHandle(commhandle);
commhandle = INVALID_HANDLE_VALUE;
comminactivity = 0;
}
//===========================================================================
static void UpdateCommState () {
if (commhandle == INVALID_HANDLE_VALUE)
return;
DCB dcb;
ZeroMemory(&dcb,sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
GetCommState(commhandle,&dcb);
dcb.BaudRate = baudrate;
dcb.ByteSize = bytesize;
dcb.Parity = parity;
dcb.StopBits = stopbits;
SetCommState(commhandle,&dcb);
}
//===========================================================================
BYTE __stdcall CommCommand (WORD, BYTE, BYTE write, BYTE value, ULONG) {
if (!CheckComm())
return 0;
if (write && (value != commandbyte)) {
commandbyte = value;
// UPDATE THE PARITY
if (commandbyte & 0x20)
switch (commandbyte & 0xC0) {
case 0x00 : parity = ODDPARITY; break;
case 0x40 : parity = EVENPARITY; break;
case 0x80 : parity = MARKPARITY; break;
case 0xC0 : parity = SPACEPARITY; break;
}
else
parity = NOPARITY;
UpdateCommState();
}
return commandbyte;
}
//===========================================================================
BYTE __stdcall CommControl (WORD, BYTE, BYTE write, BYTE value, ULONG) {
if (!CheckComm())
return 0;
if (write && (value != controlbyte)) {
controlbyte = value;
// UPDATE THE BAUD RATE
switch (controlbyte & 0x0F) {
case 0x00: // fall through
case 0x01: // fall through
case 0x02: // fall through
case 0x03: // fall through
case 0x04: // fall through
case 0x05: baudrate = CBR_110; break;
case 0x06: baudrate = CBR_300; break;
case 0x07: baudrate = CBR_600; break;
case 0x08: baudrate = CBR_1200; break;
case 0x09: // fall through
case 0x0A: baudrate = CBR_2400; break;
case 0x0B: // fall through
case 0x0C: baudrate = CBR_4800; break;
case 0x0D: // fall through
case 0x0E: baudrate = CBR_9600; break;
case 0x0F: baudrate = CBR_19200; break;
}
// UPDATE THE BYTE SIZE
switch (controlbyte & 0x60) {
case 0x00: bytesize = 8; break;
case 0x20: bytesize = 7; break;
case 0x40: bytesize = 6; break;
case 0x60: bytesize = 5; break;
}
// UPDATE THE NUMBER OF STOP BITS
if (controlbyte & 0x80) {
if ((bytesize == 8) && (parity == NOPARITY))
stopbits = ONESTOPBIT;
else if ((bytesize == 5) && (parity == NOPARITY))
stopbits = ONE5STOPBITS;
else
stopbits = TWOSTOPBITS;
}
else
stopbits = ONESTOPBIT;
UpdateCommState();
}
return controlbyte;
}
//===========================================================================
void CommDestroy () {
if ((baudrate != CBR_19200) ||
(bytesize != 8) ||
(parity != NOPARITY) ||
(stopbits != ONESTOPBIT)) {
CommReset();
CheckComm();
}
CloseComm();
}
//===========================================================================
BYTE __stdcall CommDipSw (WORD, BYTE, BYTE, BYTE, ULONG) {
// note: determine what values a real SSC returns
return 0;
}
//===========================================================================
void CommSetSerialPort (HWND window, DWORD newserialport) {
if (commhandle == INVALID_HANDLE_VALUE)
serialport = newserialport;
else
MessageBox(window,
TEXT("You cannot change the serial port while it is ")
TEXT("in use."),
TEXT("Configuration"),
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
}
//===========================================================================
void CommUpdate (DWORD totalcycles) {
if (commhandle == INVALID_HANDLE_VALUE)
return;
if ((comminactivity += totalcycles) > 1000000) {
static DWORD lastcheck = 0;
if ((comminactivity > 2000000) || (comminactivity-lastcheck > 99950)) {
DWORD modemstatus = 0;
GetCommModemStatus(commhandle,&modemstatus);
if ((modemstatus & MS_RLSD_ON) || DiskIsSpinning())
comminactivity = 0;
}
if (comminactivity > 2000000)
CloseComm();
}
}
//===========================================================================
BYTE __stdcall CommReceive (WORD, BYTE, BYTE, BYTE, ULONG) {
if (!CheckComm())
return 0;
if (!recvbytes)
CheckReceive();
BYTE result = 0;
if (recvbytes) {
result = recvbuffer[0];
if (--recvbytes)
MoveMemory(recvbuffer,recvbuffer+1,recvbytes);
}
return result;
}
//===========================================================================
void CommReset () {
CloseComm();
baudrate = CBR_19200;
bytesize = 8;
commandbyte = 0x00;
controlbyte = 0x1F;
parity = NOPARITY;
recvbytes = 0;
stopbits = ONESTOPBIT;
}
//===========================================================================
BYTE __stdcall CommStatus (WORD, BYTE, BYTE, BYTE, ULONG) {
if (!CheckComm())
return 0x70;
if (!recvbytes)
CheckReceive();
DWORD modemstatus = 0;
GetCommModemStatus(commhandle,&modemstatus);
return 0x10 | (recvbytes ? 0x08 : 0x00)
| ((modemstatus & MS_RLSD_ON) ? 0x00 : 0x20)
| ((modemstatus & MS_DSR_ON) ? 0x00 : 0x40);
}
//===========================================================================
BYTE __stdcall CommTransmit (WORD, BYTE, BYTE, BYTE value, ULONG) {
if (!CheckComm())
return 0;
DWORD byteswritten;
WriteFile(commhandle,&value,1,&byteswritten,NULL);
return 0;
}
//===========================================================================
DWORD CommGetSnapshot(SS_IO_Comms* pSS)
{
pSS->baudrate = baudrate;
pSS->bytesize = bytesize;
pSS->commandbyte = commandbyte;
pSS->comminactivity = comminactivity;
pSS->controlbyte = controlbyte;
pSS->parity = parity;
memcpy(pSS->recvbuffer, recvbuffer, 9);
pSS->recvbytes = recvbytes;
pSS->stopbits = stopbits;
return 0;
}
DWORD CommSetSnapshot(SS_IO_Comms* pSS)
{
baudrate = pSS->baudrate;
bytesize = pSS->bytesize;
commandbyte = pSS->commandbyte;
comminactivity = pSS->comminactivity;
controlbyte = pSS->controlbyte;
parity = pSS->parity;
memcpy(recvbuffer, pSS->recvbuffer, 9);
recvbytes = pSS->recvbytes;
stopbits = pSS->stopbits;
return 0;
}