linapple-pie/src/SerialComms.cpp

1198 lines
37 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-2007, 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: Super Serial Card emulation
*
* Author: Various
*/
// TO DO:
// . Enable & test Tx IRQ
// . DIP switch read values
//
// Refs:
// (1) "Super Serial Card (SSC) Memory Locations for Programmers" - Aaron Heiss
// (2) SSC recv IRQ example: http://www.wright.edu/~john.matthews/ssc.html#lst - John B. Matthews, 5/13/87
// (3) WaitCommEvent, etc: http://mail.python.org/pipermail/python-list/2002-November/131437.html
// (4) SY6551 info: http://www.axess.com/twilight/sock/rs232pak.html
//
/* Adaptation for SDL and POSIX (l) by beom beotiger, Nov-Dec 2007 */
// for read() and write()
#include <unistd.h>
#include "stdafx.h"
//#pragma hdrstop
//#include "resource.h"
//#include "wwrapper.h"
#include <assert.h>
// for terminal structure and funcs
#include <termios.h>
#include <fcntl.h>
char SSC_rom[] =
"\x20\x9B\xC9\xA9\x16\x48\xA9\x00\x9D\xB8\x04\x9D\xB8\x03\x9D\x38"
"\x04\x9D\xB8\x05\x9D\x38\x06\x9D\xB8\x06\xB9\x82\xC0\x85\x2B\x4A"
"\x4A\x90\x04\x68\x29\xFE\x48\xB8\xB9\x81\xC0\x4A\xB0\x07\x4A\xB0"
"\x0E\xA9\x01\xD0\x3D\x4A\xA9\x03\xB0\x02\xA9\x80\x9D\xB8\x04\x2C"
"\x58\xFF\xA5\x2B\x29\x20\x49\x20\x9D\xB8\x03\x70\x0A\x20\x9B\xC8"
"\xAE\xF8\x07\x9D\xB8\x05\x60\xA5\x2B\x4A\x4A\x29\x03\xA8\xF0\x04"
"\x68\x29\x7F\x48\xB9\xA6\xC9\x9D\x38\x06\xA4\x26\x68\x29\x95\x48"
"\xA9\x09\x9D\x38\x05\x68\x9D\x38\x07\xA5\x2B\x48\x29\xA0\x50\x02"
"\x29\x80\x20\xA1\xCD\x20\x81\xCD\x68\x29\x0C\x50\x02\xA9\x00\x0A"
"\x0A\x0A\x09\x0B\x99\x8A\xC0\xB9\x88\xC0\x60\x20\x9B\xC9\x20\xAA"
"\xC8\x29\x7F\xAC\xF8\x07\xBE\xB8\x05\x60\x20\xFF\xCA\xB0\x05\x20"
"\x2C\xCC\x90\xF6\x60\x20\x1E\xCA\x68\xA8\x68\xAA\xA5\x27\x60\xF0"
"\x29\xBD\xB8\x06\x10\x05\x5E\xB8\x06\xD0\x24\x20\x3E\xCC\x90\x1A"
"\xBD\xB8\x03\x29\xC0\xF0\x0E\xA5\x27\xC9\xE0\x90\x08\xBD\xB8\x04"
"\x09\x40\x9D\xB8\x04\x28\xF0\xD0\xD0\xCB\x20\xFF\xCA\x90\xDC\x20"
"\x11\xCC\x28\x08\xF0\xDA\x20\xD1\xC9\x4C\xD0\xC8\x20\x1A\xCB\xB0"
"\xB7\xA5\x27\x48\xBD\x38\x07\x29\xC0\xD0\x16\xA5\x24\xF0\x42\xC9"
"\x08\xF0\x04\xC9\x10\xD0\x0A\x09\xF0\x3D\xB8\x06\x18\x65\x24\x85"
"\x24\xBD\xB8\x06\xC5\x24\xF0\x29\xA9\xA0\x90\x08\xBD\x38\x07\x0A"
"\x10\x1F\xA9\x88\x85\x27\x2C\x58\xFF\x08\x70\x0C\xEA\x2C\x58\xFF"
"\x50\xB8\xAE\xF8\x07\x4C\xEF\xC9\x20\xB5\xC9\x20\x6B\xCB\x4C\x68"
"\xC9\x68\xB8\x08\x85\x27\x48\x20\x68\xCB\x20\xB5\xC9\x68\x49\x8D"
"\x0A\xD0\x05\x9D\xB8\x06\x85\x24\xBD\xB8\x04\x10\x0D\xBD\x38\x06"
"\xF0\x08\x18\xFD\xB8\x06\xA9\x8D\x90\xDA\x28\x70\xA4\xBD\x38\x07"
"\x30\x16\xBC\xB8\x06\x0A\x30\x0E\x98\xA0\x00\x38\xFD\x38\x06\xC9"
"\xF8\x90\x03\x69\x27\xA8\x84\x24\x4C\xB8\xC8\x8E\xF8\x07\x84\x26"
"\xA9\x00\x9D\xB8\x05\x60\x29\x48\x50\x84\x85\x27\x20\x9B\xC9\x20"
"\x63\xCB\x4C\xA3\xC8\xA5\x27\x49\x08\x0A\xF0\x04\x49\xEE\xD0\x09"
"\xDE\xB8\x06\x10\x03\x9D\xB8\x06\x60\xC9\xC0\xB0\xFB\xFE\xB8\x06"
"\x60\xBD\x38\x07\x29\x08\xF0\x16\xBD\xB8\x04\xA4\x27\xC0\x94\xD0"
"\x04\x09\x80\xD0\x06\xC0\x92\xD0\x05\x29\x7F\x9D\xB8\x04\x60\x8A"
"\x0A\x0A\x0A\x0A\x85\x26\xA9\x00\x9D\xB8\x05\x70\x0F\xA0\x00\xB1"
"\x3C\x85\x27\x20\x02\xCC\x20\xBA\xFC\x90\xF2\x60\x20\xD2\xCA\x90"
"\xFB\xB9\x88\xC0\xA0\x00\x91\x3C\x20\xBA\xFC\x90\xEF\x60\xBD\xB8"
"\x04\x10\x31\xA9\x02\x48\xA9\x7F\x20\xE2\xCD\xA4\x24\xB1\x28\x85"
"\x27\xA9\x07\x25\x4F\xD0\x10\xA4\x24\xA9\xDF\xD1\x28\xD0\x02\xA5"
"\x27\x91\x28\xE6\x4F\xE6\x4F\xBD\xB8\x04\x30\x09\x20\x11\xCC\x68"
"\xA9\x8D\x85\x27\x60\x20\xFF\xCA\x90\x0C\x20\x11\xCC\x20\xD1\xC9"
"\x20\xA3\xCC\x4C\x2B\xCA\x20\x3E\xCC\x90\xC6\x70\xBE\xBD\x38\x07"
"\x0A\x10\x22\x68\xA8\xA5\x27\xC0\x01\xF0\x20\xB0\x34\xC9\x9B\xD0"
"\x06\xC8\x98\x48\x4C\x2B\xCA\xC9\xC1\x90\x08\xC9\xDB\xB0\x04\x09"
"\x20\x85\x27\x98\x48\x20\x68\xCB\x4C\x2B\xCA\xC9\x9B\xF0\xE2\xC9"
"\xB0\x90\x0A\xC9\xBB\xB0\x06\xA8\xB9\x09\xCA\x85\x27\xA0\x00\xF0"
"\xE2\xC9\x9B\xD0\xDE\xA0\x00\xF0\xC9\x9B\x9C\x9F\xDB\xDC\xDF\xFB"
"\xFC\xFD\xFE\xFF\xA2\xCA\xCA\xD0\xFD\x38\xE9\x01\xD0\xF6\xAE\xF8"
"\x07\x60\xA4\x26\xB9\x89\xC0\x48\x29\x20\x4A\x4A\x85\x35\x68\x29"
"\x0F\xC9\x08\x90\x04\x29\x07\xB0\x02\xA5\x35\x05\x35\xF0\x05\x09"
"\x20\x9D\xB8\x05\x60\xA4\x26\xB9\x89\xC0\x29\x70\xC9\x10\x60\x20"
"\xD2\xCA\x90\x15\xB9\x88\xC0\x09\x80\xC9\x8A\xD0\x09\xA8\xBD\x38"
"\x07\x29\x20\xD0\x03\x98\x38\x60\x18\x60\xA4\x26\xB9\x81\xC0\x4A"
"\xB0\x36\xBD\xB8\x04\x29\x07\xF0\x05\x20\xFC\xCD\x38\x60\xA5\x27"
"\x29\x7F\xDD\x38\x05\xD0\x05\xFE\xB8\x04\x38\x60\xBD\x38\x07\x29"
"\x08\xF0\x15\x20\xFF\xCA\x90\x10\xC9\x93\xF0\x0E\x48\xBD\x38\x07"
"\x4A\x4A\x68\x90\x04\x9D\xB8\x06\x18\x60\x20\xAA\xC8\xC9\x91\xD0"
"\xF9\x18\x60\x20\x1A\xCB\xB0\xF1\x20\x9E\xCC\xA4\x26\xB9\x81\xC0"
"\x4A\x90\x4E\x4A\x90\x4B\xA5\x27\x48\xBD\x38\x04\xC9\x67\x90\x10"
"\xC9\x6C\xB0\x22\xC9\x6B\x68\x48\x49\x9B\x29\x7F\xD0\x18\xB0\x19"
"\xBD\xB8\x04\x29\x1F\x09\x80\x85\x27\x20\x02\xCC\x20\xAA\xC8\x49"
"\x86\xD0\xED\x9D\x38\x04\xDE\x38\x04\x68\x85\x27\x49\x8D\x0A\xD0"
"\x0A\xBD\xB8\x03\x29\x30\xF0\x03\x9D\x38\x04\x20\x02\xCC\x4C\xEA"
"\xCB\x20\x02\xCC\x0A\xA8\xBD\xB8\x03\xC0\x18\xF0\x0C\x4A\x4A\xC0"
"\x14\xF0\x06\x4A\x4A\xC0\x1A\xD0\x25\x29\x03\xF0\x0D\xA8\xB9\xFE"
"\xCB\xA8\xA9\x20\x20\xC4\xCA\x88\xD0\xF8\xA5\x27\x0A\xC9\x1A\xD0"
"\x0D\xBD\x38\x07\x6A\x90\x07\xA9\x8A\x85\x27\x4C\x6B\xCB\x60\x01"
"\x08\x40\x20\xF5\xCA\xD0\xFB\x98\x09\x89\xA8\xA5\x27\x99\xFF\xBF"
"\x60\x48\xA4\x24\xA5\x27\x91\x28\x68\xC9\x95\xD0\x0C\xA5\x27\xC9"
"\x20\xB0\x06\x20\xDF\xCC\x59\xDB\xCC\x85\x27\x60\x18\xBD\x38\x07"
"\x29\x04\xF0\x09\xAD\x00\xC0\x10\x04\x8D\x10\xC0\x38\x60\xE6\x4E"
"\xD0\x02\xE6\x4F\x20\x2C\xCC\xB8\x90\xF3\x20\x11\xCC\x29\x7F\xDD"
"\x38\x05\xD0\x3D\xA4\x26\xB9\x81\xC0\x4A\xB0\x35\xA0\x0A\xB9\x93"
"\xCC\x85\x27\x98\x48\x20\xA3\xCC\x68\xA8\x88\x10\xF1\xA9\x01\x20"
"\x7B\xCE\x20\x34\xCC\x10\xFB\xC9\x88\xF0\xE1\x85\x27\x20\xA3\xCC"
"\x20\x1A\xCB\xBD\xB8\x04\x29\x07\xD0\xE8\xA9\x8D\x85\x27\x2C\x58"
"\xFF\x38\x60\xBA\xC3\xD3\xD3\xA0\xC5\xCC\xD0\xD0\xC1\x8D\xBD\x38"
"\x07\x10\x13\xBD\x38\x07\x29\x02\xF0\x0D\xBD\xB8\x04\x29\x38\xF0"
"\x06\x8A\x48\xA9\xAF\x48\x60\x20\xDF\xCC\x09\x80\xC9\xE0\x90\x06"
"\x59\xD3\xCC\x4C\xF6\xFD\xC9\xC1\x90\xF9\xC9\xDB\xB0\xF5\x59\xD7"
"\xCC\x90\xF0\x20\x00\xE0\x20\x00\x00\x00\xC0\x00\x00\xE0\xC0\xBD"
"\xB8\x03\x2A\x2A\x2A\x29\x03\xA8\xA5\x27\x60\x42\x67\xC0\x54\x47"
"\xA6\x43\x87\xA6\x51\x47\xB8\x52\xC7\xAC\x5A\xE7\xF3\x49\x90\xD3"
"\x4B\x90\xDF\x45\x43\x80\x46\xE3\x04\x4C\xE3\x01\x58\xE3\x08\x54"
"\x83\x40\x53\x43\x40\x4D\xE3\x20\x00\x42\xF6\x7C\x50\xF6\x9A\x44"
"\xF6\x9B\x46\xF6\x46\x4C\xF6\x40\x43\xF6\x3A\x54\xD6\x34\x4E\x90"
"\xE8\x53\x56\x60\x00\xA9\x3F\xA0\x07\xD0\x10\xA9\xCF\xA0\x05\xD0"
"\x0A\xA9\xF3\xA0\x03\xD0\x04\xA9\xFC\xA0\x01\x3D\xB8\x03\x85\x2A"
"\xBD\x38\x04\x29\x03\x18\x6A\x2A\x88\xD0\xFC\x05\x2A\x9D\xB8\x03"
"\x60\x29\x07\x0A\x0A\x0A\x85\x2A\x0A\xC5\x26\xF0\x0F\xBD\xB8\x04"
"\x29\xC7\x05\x2A\x9D\xB8\x04\xA9\x00\x9D\x38\x06\x60\x29\x0F\xD0"
"\x07\xB9\x81\xC0\x4A\x4A\x4A\x4A\x09\x10\x85\x2A\xA9\xE0\x85\x2B"
"\xB9\x8B\xC0\x25\x2B\x05\x2A\x99\x8B\xC0\x60\x88\x0A\x0A\x0A\x0A"
"\x0A\x85\x2A\xA9\x1F\xD0\xE7\x1E\xB8\x04\x38\xB0\x10\x99\x89\xC0"
"\x20\x93\xFE\x20\x89\xFE\xAE\xF8\x07\x1E\xB8\x04\x18\x7E\xB8\x04"
"\x60\xB9\x8A\xC0\x48\x09\x0C\x99\x8A\xC0\xA9\xE9\x20\xC4\xCA\x68"
"\x99\x8A\xC0\x60\xA9\x28\x9D\x38\x06\xA9\x80\x1D\x38\x07\xD0\x05"
"\xA9\xFE\x3D\x38\x07\x9D\x38\x07\x60\xC9\x28\x90\x0E\x9D\x38\x06"
"\xA9\x3F\xD0\xEE\x1E\x38\x05\x38\x7E\x38\x05\x60\xA8\xA5\x27\x29"
"\x7F\xC9\x20\xD0\x09\xC0\x03\xF0\x01\x60\xA9\x04\xD0\x6D\xC9\x0D"
"\xD0\x12\x20\x79\xCE\xC0\x07\xF0\x01\x60\xA9\xCD\x48\xBD\x38\x04"
"\x48\xA4\x26\x60\x85\x35\xA9\xCE\x48\xB9\x30\xCE\x48\xA5\x35\x60"
"\xA7\x37\x61\x89\x8A\xA7\x89\x89\xDD\x38\x05\xD0\x06\xDE\xB8\x04"
"\x4C\x02\xCC\xC9\x30\x90\x0D\xC9\x3A\xB0\x09\x29\x0F\x9D\x38\x04"
"\xA9\x02\xD0\x27\xC9\x20\xB0\x06\x9D\x38\x05\x4C\x79\xCE\xA0\x00"
"\xF0\x4D\x49\x30\xC9\x0A\xB0\x0D\xA0\x0A\x7D\x38\x04\x88\xD0\xFA"
"\x9D\x38\x04\xF0\x15\xA0\x2E\xD0\x36\xA9\x00\x85\x2A\xAE\xF8\x07"
"\xBD\xB8\x04\x29\xF8\x05\x2A\x9D\xB8\x04\x60\xA8\xBD\x38\x04\xC0"
"\x44\xF0\x09\xC0\x45\xD0\x11\x1D\x38\x07\xD0\x05\x49\xFF\x3D\x38"
"\x07\x9D\x38\x07\xA9\x06\xD0\xD3\xA9\x20\x9D\xB8\x05\xD0\xF5\xB9"
"\xEB\xCC\xF0\xF4\xC5\x35\xF0\x05\xC8\xC8\xC8\xD0\xF2\xC8\xB9\xEB"
"\xCC\x85\x2A\x29\x20\xD0\x07\xBD\x38\x07\x29\x10\xD0\xEB\xBD\x38"
"\x07\x4A\x4A\x24\x2A\xB0\x04\x10\xE0\x30\x02\x50\xDC\xA5\x2A\x48"
"\x29\x07\x20\x7B\xCE\xC8\x68\x29\x10\xD0\x07\xB9\xEB\xCC\x9D\x38"
"\x04\x60\xA9\xCD\x48\xB9\xEB\xCC\x48\xA4\x26\xBD\x38\x04\x60\xC2"
"\x2C\x58\xFF\x70\x0C\x38\x90\x18\xB8\x50\x06\x01\x31\x8E\x94\x97"
"\x9A\x85\x27\x86\x35\x8A\x48\x98\x48\x08\x78\x8D\xFF\xCF\x20\x58"
"\xFF\xBA\xBD\x00\x01\x8D\xF8\x07\xAA\x0A\x0A\x0A\x0A\x85\x26\xA8"
"\x28\x50\x29\x1E\x38\x05\x5E\x38\x05\xB9\x8A\xC0\x29\x1F\xD0\x05"
"\xA9\xEF\x20\x05\xC8\xE4\x37\xD0\x0B\xA9\x07\xC5\x36\xF0\x05\x85"
"\x36\x18\x90\x08\xE4\x39\xD0\xF9\xA9\x05\x85\x38\xBD\x38\x07\x29"
"\x02\x08\x90\x03\x4C\xBF\xC8\xBD\xB8\x04\x48\x0A\x10\x0E\xA6\x35"
"\xA5\x27\x09\x20\x9D\x00\x02\x85\x27\xAE\xF8\x07\x68\x29\xBF\x9D"
"\xB8\x04\x28\xF0\x06\x20\x63\xCB\x4C\xB5\xC8\x4C\xFC\xC8\x20\x00"
"\xC8\xA2\x00\x60\x4C\x9B\xC8\x4C\xAA\xC9\x4A\x20\x9B\xC9\xB0\x08"
"\x20\xF5\xCA\xF0\x06\x18\x90\x03\x20\xD2\xCA\xBD\xB8\x05\xAA\x60"
"\xA2\x03\xB5\x36\x48\xCA\x10\xFA\xAE\xF8\x07\xBD\x38\x06\x85\x36"
"\xBD\xB8\x04\x29\x38\x4A\x4A\x4A\x09\xC0\x85\x37\x8A\x48\xA5\x27"
"\x48\x09\x80\x20\xED\xFD\x68\x85\x27\x68\x8D\xF8\x07\xAA\x0A\x0A"
"\x0A\x0A\x85\x26\x8D\xFF\xCF\xA5\x36\x9D\x38\x06\xA2\x00\x68\x95"
"\x36\xE8\xE0\x04\x90\xF8\xAE\xF8\x07\x60\xC1\xD0\xD0\xCC\xC5\x08"
;
pthread_mutex_t m_CriticalSection = PTHREAD_MUTEX_INITIALIZER;
//#define SUPPORT_MODEM
// Default: 19200-8-N-1
// Maybe a better default is: 9600-7-N-1 (for HyperTrm)
SSC_DIPSW CSuperSerialCard::m_DIPSWDefault =
{
// DIPSW1:
B19200, // CBR_# (win32) -> B# (*nix?)
FWMODE_CIC,
// DIPSW2:
ONESTOPBIT,
8, // ByteSize
NOPARITY,
true, // LF
false, // INT
};
//===========================================================================
CSuperSerialCard::CSuperSerialCard()
{
m_dwSerialPort = 0;
GetDIPSW();
m_vRecvBytes = 0;
m_hCommHandle = -1;
m_dwCommInactivity = 0;
m_bTxIrqEnabled = false;
m_bRxIrqEnabled = false;
m_bWrittenTx = false;
m_vbCommIRQ = false;
m_hCommThread = NULL;
for (UINT i=0; i<COMMEVT_MAX; i++)
m_hCommEvent[i] = NULL;
memset(&m_o, 0, sizeof(m_o));
}
//===========================================================================
// TODO: Serial Comms - UI Property Sheet Page:
// . Ability to config the 2x DIPSWs - only takes affect after next Apple2 reset
// . 'Default' button that resets DIPSWs to DIPSWDefaults
void CSuperSerialCard::GetDIPSW()
{
// TODO: Read settings from Registry
// In the meantime, use the defaults:
SetDIPSWDefaults();
//
m_uBaudRate = m_DIPSWCurrent.uBaudRate;
m_uStopBits = m_DIPSWCurrent.uStopBits;
m_uByteSize = m_DIPSWCurrent.uByteSize;
m_uParity = m_DIPSWCurrent.uParity;
//
m_uControlByte = GenerateControl();
m_uCommandByte = 0x00;
}
void CSuperSerialCard::SetDIPSWDefaults()
{
// Default DIPSW settings (comms mode)
// DIPSW1:
m_DIPSWCurrent.uBaudRate = m_DIPSWDefault.uBaudRate;
m_DIPSWCurrent.eFirmwareMode = m_DIPSWDefault.eFirmwareMode;
// DIPSW2:
m_DIPSWCurrent.uStopBits = m_DIPSWDefault.uStopBits;
m_DIPSWCurrent.uByteSize = m_DIPSWDefault.uByteSize;
m_DIPSWCurrent.uParity = m_DIPSWDefault.uParity;
m_DIPSWCurrent.bLinefeed = m_DIPSWDefault.bLinefeed;
m_DIPSWCurrent.bInterrupts = m_DIPSWDefault.bInterrupts;
}
BYTE CSuperSerialCard::GenerateControl()
{
const UINT CLK=1; // Internal
UINT bmByteSize = (8 - m_uByteSize); // [8,7,6,5] -> [0,1,2,3]
_ASSERT(bmByteSize <= 3);
UINT StopBit;
if ( ((m_uByteSize == 8) && (m_uParity != NOPARITY)) ||
( m_uStopBits != ONESTOPBIT ) )
StopBit = 1;
else
StopBit = 0;
return (StopBit<<7) | (bmByteSize<<5) | (CLK<<4) | BaudRateToIndex(m_uBaudRate);
}
UINT CSuperSerialCard::BaudRateToIndex(UINT uBaudRate)
{
switch (uBaudRate)
{ // changed: CBR_# to B# (for *nix?) --bb
case B110: return 0x05;
case B300: return 0x06;
case B600: return 0x07;
case B1200: return 0x08;
case B2400: return 0x0A;
case B4800: return 0x0C;
case B9600: return 0x0E;
case B19200: return 0x0F;
}
_ASSERT(0);
return BaudRateToIndex(B9600);
}
//===========================================================================
void CSuperSerialCard::UpdateCommState()
{
if (m_hCommHandle == -1)
return;
struct termios dcb;
int l_databits = CS8;
tcgetattr(m_hCommHandle, &dcb); // get current attributes for m_hCommHandle in dcb
// set input/output speed to m_uBaudRate
cfsetispeed(&dcb, m_uBaudRate);
cfsetospeed(&dcb, m_uBaudRate);
/*
* Enable the receiver and set localmode
*/
dcb.c_cflag |= (CLOCAL | CREAD);
switch(m_uParity) {
case NOPARITY: /* NONE */
dcb.c_cflag &= ~PARENB;
// dcb.c_cflag &= ~CSTOPB;
break;
case EVENPARITY: /* EVEN */
dcb.c_cflag |= PARENB;
dcb.c_cflag &= ~PARODD;
// dcb.c_cflag &= ~CSTOPB;
break;
case ODDPARITY: /* ODD */
dcb.c_cflag |= PARENB;
dcb.c_cflag |= PARODD;
// sp->params->c_cflag &= ~CSTOPB;
break;
case MARKPARITY: /* MARKPARITY */
dcb.c_cflag |= PARENB | CMSPAR | PARODD;
break;
case SPACEPARITY: /* SPACEPARITY */
dcb.c_cflag |= PARENB | CMSPAR;
dcb.c_cflag &= ~PARODD;
break;
}
switch(m_uByteSize) { // data bits
case 5: l_databits = CS5; break;
case 6: l_databits = CS6; break;
case 7: l_databits = CS7; break;
case 8: l_databits = CS8; break;
}
dcb.c_cflag &= ~CSIZE;
dcb.c_cflag |= l_databits;
// dcb.c_cflag |= m_uBaudRate; // set here instead of by cfsetispeed and cfsetospeed?
switch(m_uStopBits) {
case ONE5STOPBITS:
case ONESTOPBIT: dcb.c_cflag &= ~CSTOPB; // 1 stopbit
break;
case TWOSTOPBITS: dcb.c_cflag |= CSTOPB; // 1.5 and 2 stopbits.
break;
}
dcb.c_cflag &= ~CRTSCTS; /* Disable hardware flow control */
/* Enable data to be processed as raw input */
dcb.c_lflag &= ~(ICANON | ECHO | ISIG);
/* Set the new options for the port */
tcsetattr(m_hCommHandle, TCSANOW, &dcb);
// This code in Win32??
/* DCB dcb;
ZeroMemory(&dcb,sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
GetCommState(m_hCommHandle,&dcb);
dcb.BaudRate = m_uBaudRate;
dcb.ByteSize = m_uByteSize;
dcb.Parity = m_uParity;
dcb.StopBits = m_uStopBits;
SetCommState(m_hCommHandle,&dcb);*/
}
//===========================================================================
BOOL CSuperSerialCard::CheckComm()
{
m_dwCommInactivity = 0;
if ((m_hCommHandle == -1) && m_dwSerialPort)
{
TCHAR portname[12]; // we have /dev/ttyS0..X instead of COM1..COMX+1?
if(m_dwSerialPort < 0 || m_dwSerialPort > 99) m_dwSerialPort = 1;//buffer overflow check
sprintf(portname, TEXT("/dev/ttyS%u"), (unsigned int)(m_dwSerialPort - 1));
/* m_hCommHandle = CreateFile(portname,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
(LPSECURITY_ATTRIBUTES)NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, // required for WaitCommEvent()
NULL);*/
m_hCommHandle = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
if (m_hCommHandle != -1)
{
UpdateCommState();
/* COMMTIMEOUTS ct;
ZeroMemory(&ct,sizeof(COMMTIMEOUTS));
ct.ReadIntervalTimeout = MAXDWORD;
SetCommTimeouts(m_hCommHandle,&ct);*/
CommThInit();
}
else
{
;//DWORD uError = 1;//GetLastError();
}
}
return (m_hCommHandle != -1);
}
//===========================================================================
void CSuperSerialCard::CloseComm()
{
CommThUninit(); // Kill CommThread before closing COM handle
if (m_hCommHandle != -1)
close(m_hCommHandle); // close device (port?)
m_hCommHandle = -1;
m_dwCommInactivity = 0;
}
//===========================================================================
BYTE /*__stdcall*/ CSuperSerialCard::SSC_IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft)
{
UINT uSlot = ((uAddr & 0xff) >> 4) - 8;
CSuperSerialCard* pSSC = (CSuperSerialCard*) MemGetSlotParameters(uSlot);
switch (uAddr & 0xf)
{
case 0x0: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x1: return pSSC->CommDipSw(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x2: return pSSC->CommDipSw(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x3: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x4: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x5: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x6: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x7: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x8: return pSSC->CommReceive(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x9: return pSSC->CommStatus(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xA: return pSSC->CommCommand(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xB: return pSSC->CommControl(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xC: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xD: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xE: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xF: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
}
return 0;
}
BYTE /*__stdcall*/ CSuperSerialCard::SSC_IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft)
{
UINT uSlot = ((uAddr & 0xff) >> 4) - 8;
CSuperSerialCard* pSSC = (CSuperSerialCard*) MemGetSlotParameters(uSlot);
switch (uAddr & 0xf)
{
case 0x0: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x1: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x2: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x3: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x4: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x5: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x6: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x7: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x8: return pSSC->CommTransmit(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0x9: return pSSC->CommStatus(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xA: return pSSC->CommCommand(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xB: return pSSC->CommControl(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xC: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xD: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xE: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
case 0xF: return IO_Null(PC, uAddr, bWrite, uValue, nCyclesLeft);
}
return 0;
}
//===========================================================================
// EG. 0x09 = Enable IRQ, No parity [Ref.2]
BYTE /*__stdcall*/ CSuperSerialCard::CommCommand(WORD, WORD, BYTE write, BYTE value, ULONG)
{
if (!CheckComm())
return 0;
if (write && (value != m_uCommandByte))
{
m_uCommandByte = value;
// UPDATE THE PARITY
if (m_uCommandByte & 0x20)
{
switch (m_uCommandByte & 0xC0)
{
case 0x00 : m_uParity = ODDPARITY; break;
case 0x40 : m_uParity = EVENPARITY; break;
case 0x80 : m_uParity = MARKPARITY; break;
case 0xC0 : m_uParity = SPACEPARITY; break;
}
}
else
{
m_uParity = NOPARITY;
}
if (m_uCommandByte & 0x10) // Receiver mode echo [0=no echo, 1=echo]
{
}
switch (m_uCommandByte & 0x0C) // transmitter interrupt control
{
// Note: the RTS signal must be set 'low' in order to receive any
// incoming data from the serial device
case 0<<2: // set RTS high and transmit no interrupts
m_bTxIrqEnabled = false;
break;
case 1<<2: // set RTS low and transmit interrupts
m_bTxIrqEnabled = true;
break;
case 2<<2: // set RTS low and transmit no interrupts
m_bTxIrqEnabled = false;
break;
case 3<<2: // set RTS low and transmit break signals instead of interrupts
m_bTxIrqEnabled = false;
break;
}
// interrupt request disable [0=enable receiver interrupts]
m_bRxIrqEnabled = ((m_uCommandByte & 0x02) == 0);
if (m_uCommandByte & 0x01) // Data Terminal Ready (DTR) setting [0=set DTR high (indicates 'not ready')]
{
// Note that, although the DTR is generally not used in the SSC (it may actually not
// be connected!), it must be set to 'low' in order for the 6551 to function correctly.
}
UpdateCommState();
}
return m_uCommandByte;
}
//===========================================================================
BYTE /*__stdcall*/ CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value, ULONG)
{
if (!CheckComm())
return 0;
if (write && (value != m_uControlByte))
{
m_uControlByte = value;
// UPDATE THE BAUD RATE
switch (m_uControlByte & 0x0F)
{
// Note that 1 MHz Apples (everything other than the Apple IIgs and //c
// Plus running in "fast" mode) cannot handle 19.2 kbps, and even 9600
// bps on these machines requires either some highly optimised code or
// a decent buffer in the device being accessed. The faster Apples
// have no difficulty with this speed, however.
case 0x00: // fall through [16x external clock]
case 0x01: // fall through [50 bps]
case 0x02: // fall through [75 bps]
case 0x03: // fall through [109.92 bps]
case 0x04: // fall through [134.58 bps]
case 0x05: m_uBaudRate = B110; break; // [150 bps]
case 0x06: m_uBaudRate = B300; break;
case 0x07: m_uBaudRate = B600; break;
case 0x08: m_uBaudRate = B1200; break;
case 0x09: // fall through [1800 bps]
case 0x0A: m_uBaudRate = B2400; break;
case 0x0B: // fall through [3600 bps]
case 0x0C: m_uBaudRate = B4800; break;
case 0x0D: // fall through [7200 bps]
case 0x0E: m_uBaudRate = B9600; break;
case 0x0F: m_uBaudRate = B19200; break;
}
if (m_uControlByte & 0x10)
{
// receiver clock source [0= external, 1= internal]
}
// UPDATE THE BYTE SIZE
switch (m_uControlByte & 0x60)
{
case 0x00: m_uByteSize = 8; break;
case 0x20: m_uByteSize = 7; break;
case 0x40: m_uByteSize = 6; break;
case 0x60: m_uByteSize = 5; break;
}
// UPDATE THE NUMBER OF STOP BITS
if (m_uControlByte & 0x80)
{
if ((m_uByteSize == 8) && (m_uParity != NOPARITY))
m_uStopBits = ONESTOPBIT;
else if ((m_uByteSize == 5) && (m_uParity == NOPARITY))
m_uStopBits = ONE5STOPBITS;
else
m_uStopBits = TWOSTOPBITS;
}
else
{
m_uStopBits = ONESTOPBIT;
}
UpdateCommState();
}
return m_uControlByte;
}
//===========================================================================
BYTE /*__stdcall*/ CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
{
if (!CheckComm())
return 0;
BYTE result = 0;
if (m_vRecvBytes)
{
// Don't need critical section in here as CommThread is waiting for ACK
result = m_RecvBuffer[0];
--m_vRecvBytes;
if (m_vbCommIRQ && !m_vRecvBytes)
{
// Read last byte, so get CommThread to call WaitCommEvent() again
fprintf(stderr, "CommRecv: SetEvent - ACK\n");
// SetEvent(m_hCommEvent[COMMEVT_ACK]);
}
}
return result;
}
//===========================================================================
BYTE /*__stdcall*/ CSuperSerialCard::CommTransmit(WORD, WORD, BYTE, BYTE value, ULONG)
{
if (!CheckComm())
return 0;
DWORD uBytesWritten;
uBytesWritten = write(m_hCommHandle, &value, 1);
// WriteFile(m_hCommHandle, &value, 1, &uBytesWritten, &m_o);
m_bWrittenTx = true; // Transmit done
// TO DO:
// 1) Use CommThread determine when transmit is complete
// 2) OR do this:
//if (m_bTxIrqEnabled)
// CpuIrqAssert(IS_SSC);
return 0;
}
//===========================================================================
// 6551 ACIA Status Register ($C089+s0)
// ------------------------------------
// Bit Value Meaning
// 0 1 Parity error
// 1 1 Framing error
// 2 1 Overrun error
// 3 1 Receive register full
// 4 1 Transmit register empty
// 5 0 Data Carrier Detect (DCD) true [0=DCD low (detected), 1=DCD high (not detected)]
// 6 0 Data Set Ready (DSR) true [0=DSR low (ready), 1=DSR high (not ready)]
// 7 1 Interrupt (IRQ) true (cleared by reading status reg [Ref.4])
enum { ST_PARITY_ERR = 1<<0,
ST_FRAMING_ERR = 1<<1,
ST_OVERRUN_ERR = 1<<2,
ST_RX_FULL = 1<<3,
ST_TX_EMPTY = 1<<4,
ST_DCD = 1<<5,
ST_DSR = 1<<6,
ST_IRQ = 1<<7
};
BYTE /*__stdcall*/ CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG)
{
if (!CheckComm())
return ST_DSR | ST_DCD | ST_TX_EMPTY;
#ifdef SUPPORT_MODEM
DWORD modemstatus = 0;
GetCommModemStatus(m_hCommHandle,&modemstatus); // Returns 0x30 = MS_DSR_ON|MS_CTS_ON
#endif
//
// TO DO - ST_TX_EMPTY:
// . IRQs enabled : set after WaitCommEvent has signaled that TX has completed
// . IRQs disabled : always set it [Currently done]
//
// So that /m_vRecvBytes/ doesn't change midway (from 0 to 1):
// . bIRQ=false, but uStatus.ST_RX_FULL=1
// EnterCriticalSection(&m_CriticalSection);
pthread_mutex_lock( &m_CriticalSection );
bool bIRQ = false;
if (m_bTxIrqEnabled && m_bWrittenTx)
{
bIRQ = true;
}
if (m_bRxIrqEnabled && m_vRecvBytes)
{
bIRQ = true;
}
m_bWrittenTx = false; // Read status reg always clears IRQ
//
BYTE uStatus = ST_TX_EMPTY
| (m_vRecvBytes ? ST_RX_FULL : 0x00)
#ifdef SUPPORT_MODEM
| ((modemstatus & MS_RLSD_ON) ? 0x00 : ST_DCD) // Need 0x00 to allow ZLink to start up
| ((modemstatus & MS_DSR_ON) ? 0x00 : ST_DSR)
#endif
| (bIRQ ? ST_IRQ : 0x00);
// LeaveCriticalSection(&m_CriticalSection);
pthread_mutex_unlock( &m_CriticalSection);
CpuIrqDeassert(IS_SSC);
return uStatus;
}
//===========================================================================
BYTE /*__stdcall*/ CSuperSerialCard::CommDipSw(WORD, WORD addr, BYTE, BYTE, ULONG)
{
BYTE sw = 0;
switch (addr & 0xf)
{
case 1: // DIPSW1
sw = (BaudRateToIndex(m_DIPSWCurrent.uBaudRate)<<4) | m_DIPSWCurrent.eFirmwareMode;
break;
case 2: // DIPSW2
// Comms mode - SSC manual, pg23/24
BYTE INT = m_DIPSWCurrent.uStopBits == TWOSTOPBITS ? 1 : 0; // SW2-1 (Stop bits: 1-ON(0); 2-OFF(1))
BYTE DSR = 0; // Always zero
BYTE DCD = m_DIPSWCurrent.uByteSize == 7 ? 1 : 0; // SW2-2 (Data bits: 8-ON(0); 7-OFF(1))
BYTE TDR = 0; // Always zero
// SW2-3 (Parity: odd-ON(0); even-OFF(1))
// SW2-4 (Parity: none-ON(0); SW2-3-OFF(1))
BYTE RDR,OVR;
switch (m_DIPSWCurrent.uParity)
{
case ODDPARITY:
RDR = 0; OVR = 1;
break;
case EVENPARITY:
RDR = 1; OVR = 1;
break;
default:
_ASSERT(0);
case NOPARITY:
RDR = 0; OVR = 0;
break;
}
BYTE FE = m_DIPSWCurrent.bLinefeed ? 1 : 0; // SW2-5 (LF: yes-ON(0); no-OFF(1))
BYTE PE = m_DIPSWCurrent.bInterrupts ? 1 : 0; // SW2-6 (Interrupts: yes-ON(0); no-OFF(1))
sw = (INT<<7) | (DSR<<6) | (DCD<<5) | (TDR<<4) | (RDR<<3) | (OVR<<2) | (FE<<1) | (PE<<0);
break;
}
return sw;
}
//===========================================================================
void CSuperSerialCard::CommInitialize(LPBYTE pCxRomPeripheral, UINT uSlot)
{
const UINT SSC_FW_SIZE = 2*1024;
const UINT SSC_SLOT_FW_SIZE = 256;
const UINT SSC_SLOT_FW_OFFSET = 7*256;
/* HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_SSC_FW), "FIRMWARE");
if(hResInfo == NULL)
return;
DWORD dwResSize = SizeofResource(NULL, hResInfo);
if(dwResSize != SSC_FW_SIZE)
return;
HGLOBAL hResData = LoadResource(NULL, hResInfo);
if(hResData == NULL)
return;*/
// #define IDR_SSC_FW "SSC.rom"
// char BUFFER[SSC_FW_SIZE];
// FILE * hdfile = NULL;
// hdfile = fopen(IDR_SSC_FW, "rb");
// if(hdfile == NULL) return; // no file?
// UINT nbytes = fread(BUFFER, 1, SSC_FW_SIZE, hdfile);
// fclose(hdfile);
// if(nbytes != SSC_FW_SIZE) return; // have not read enough?
//
BYTE* pData = (BYTE*) SSC_rom; // NB. Don't need to unlock resource
// if(pData == NULL)
// return;
memcpy(pCxRomPeripheral + uSlot*256, pData+SSC_SLOT_FW_OFFSET, SSC_SLOT_FW_SIZE);
// Expansion ROM
if (m_pExpansionRom == NULL)
{
m_pExpansionRom = new BYTE [SSC_FW_SIZE];
if (m_pExpansionRom)
memcpy(m_pExpansionRom, pData, SSC_FW_SIZE);
}
//
RegisterIoHandler(uSlot, &CSuperSerialCard::SSC_IORead, &CSuperSerialCard::SSC_IOWrite, NULL, NULL, this, m_pExpansionRom);
}
//===========================================================================
void CSuperSerialCard::CommReset()
{
CloseComm();
GetDIPSW();
m_vRecvBytes = 0;
//
m_bTxIrqEnabled = false;
m_bRxIrqEnabled = false;
m_bWrittenTx = false;
m_vbCommIRQ = false;
}
//===========================================================================
void CSuperSerialCard::CommDestroy()
{
CommReset();
delete [] m_pExpansionRom;
m_pExpansionRom = NULL;
}
//===========================================================================
void CSuperSerialCard::CommSetSerialPort(/*HWND window,*/ DWORD newserialport)
{
if (m_hCommHandle == -1)
{
m_dwSerialPort = newserialport;
}
else
{
/* MessageBox(window,
TEXT("You cannot change the serial port while it is ")
TEXT("in use."),
TEXT("Configuration"),
MB_ICONEXCLAMATION | MB_SETFOREGROUND);*/
fprintf(stderr, "You cannot change the serial port while it is in use!\n");
}
}
//===========================================================================
void CSuperSerialCard::CommUpdate(DWORD totalcycles)
{
if (m_hCommHandle == -1)
return;
if ((m_dwCommInactivity += totalcycles) > 1000000)
{
static DWORD lastcheck = 0;
if ((m_dwCommInactivity > 2000000) || (m_dwCommInactivity-lastcheck > 99950))
{
#ifdef SUPPORT_MODEM
DWORD modemstatus = 0;
GetCommModemStatus(m_hCommHandle,&modemstatus);
if ((modemstatus & MS_RLSD_ON) || DiskIsSpinning())
m_dwCommInactivity = 0;
#else
if (DiskIsSpinning())
m_dwCommInactivity = 0;
#endif
}
//if (m_dwCommInactivity > 2000000)
// CloseComm();
}
}
//===========================================================================
void CSuperSerialCard::CheckCommEvent(DWORD dwEvtMask)
{
/* if (dwEvtMask & EV_RXCHAR)*/
{
pthread_mutex_lock(&m_CriticalSection);
// ReadFile(m_hCommHandle, m_RecvBuffer, 1, (DWORD*)&m_vRecvBytes, &m_o);
m_vRecvBytes = read(m_hCommHandle, m_RecvBuffer, 1);
pthread_mutex_unlock(&m_CriticalSection);
if (m_bRxIrqEnabled && m_vRecvBytes)
{
m_vbCommIRQ = true;
CpuIrqAssert(IS_SSC);
}
}
//else if (dwEvtMask & EV_TXEMPTY)
//{
// if (m_bTxIrqEnabled)
// {
// m_vbCommIRQ = true;
// CpuIrqAssert(IS_SSC);
// }
//}
}
DWORD CSuperSerialCard::CommThread(LPVOID lpParameter)
{
/* CSuperSerialCard* pSSC = (CSuperSerialCard*) lpParameter;
char szDbg[100];
// BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_TXEMPTY | EV_RXCHAR);
BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_RXCHAR); // Just RX
if (!bRes)
return -1;
//
const UINT nNumEvents = 2;
#if 1
HANDLE hCommEvent_Wait[nNumEvents] = {pSSC->m_hCommEvent[COMMEVT_WAIT], pSSC->m_hCommEvent[COMMEVT_TERM]};
HANDLE hCommEvent_Ack[nNumEvents] = {pSSC->m_hCommEvent[COMMEVT_ACK], pSSC->m_hCommEvent[COMMEVT_TERM]};
#else
HANDLE hCommEvent_Wait[nNumEvents];
HANDLE hCommEvent_Ack[nNumEvents];
hCommEvent_Wait[0] = m_hCommEvent[COMMEVT_WAIT];
hCommEvent_Wait[1] = m_hCommEvent[COMMEVT_TERM];
hCommEvent_Ack[0] = m_hCommEvent[COMMEVT_ACK];
hCommEvent_Ack[1] = m_hCommEvent[COMMEVT_TERM];
#endif
while(1)
{
DWORD dwEvtMask = 0;
DWORD dwWaitResult;
bRes = WaitCommEvent(pSSC->m_hCommHandle, &dwEvtMask, &pSSC->m_o); // Will return immediately (probably with ERROR_IO_PENDING)
_ASSERT(!bRes);
if (!bRes)
{
DWORD dwRet = GetLastError();
// Got this error once: ERROR_OPERATION_ABORTED
_ASSERT(dwRet == ERROR_IO_PENDING);
if (dwRet != ERROR_IO_PENDING)
return -1;
//
// Wait for comm event
//
while(1)
{
OutputDebugString("CommThread: Wait1\n");
dwWaitResult = WaitForMultipleObjects(
nNumEvents, // number of handles in array
hCommEvent_Wait, // array of event handles
FALSE, // wait until any one is signaled
INFINITE);
// On very 1st wait *only*: get a false signal (when not running via debugger)
if ((dwWaitResult == WAIT_OBJECT_0) && (dwEvtMask == 0))
continue;
if ((dwWaitResult >= WAIT_OBJECT_0) && (dwWaitResult <= WAIT_OBJECT_0+nNumEvents-1))
break;
}
dwWaitResult -= WAIT_OBJECT_0; // Determine event # that signaled
sprintf(szDbg, "CommThread: GotEvent1: %d\n", dwWaitResult); OutputDebugString(szDbg);
if (dwWaitResult == (nNumEvents-1))
break; // Termination event
}
// Comm event
pSSC->CheckCommEvent(dwEvtMask);
if (pSSC->m_vbCommIRQ)
{
//
// Wait for ack
//
while(1)
{
OutputDebugString("CommThread: Wait2\n");
dwWaitResult = WaitForMultipleObjects(
nNumEvents, // number of handles in array
hCommEvent_Ack, // array of event handles
FALSE, // wait until any one is signaled
INFINITE);
if ((dwWaitResult >= WAIT_OBJECT_0) && (dwWaitResult <= WAIT_OBJECT_0+nNumEvents-1))
break;
}
dwWaitResult -= WAIT_OBJECT_0; // Determine event # that signaled
sprintf(szDbg, "CommThread: GotEvent2: %d\n", dwWaitResult); OutputDebugString(szDbg);
if (dwWaitResult == (nNumEvents-1))
break; // Termination event
pSSC->m_vbCommIRQ = false;
}
}*/
return 0;
}
bool CSuperSerialCard::CommThInit()
{
/* _ASSERT(m_hCommThread == NULL);
_ASSERT(m_hCommHandle);
if ((m_hCommEvent[0] == NULL) && (m_hCommEvent[1] == NULL) && (m_hCommEvent[2] == NULL))
{
// Create an event object for use by WaitCommEvent
m_o.hEvent = CreateEvent(
NULL, // default security attributes
FALSE, // auto reset event (bManualReset)
FALSE, // not signaled (bInitialState)
NULL // no name
);
// Initialize the rest of the OVERLAPPED structure to zero
m_o.Internal = 0;
m_o.InternalHigh = 0;
m_o.Offset = 0;
m_o.OffsetHigh = 0;
//
m_hCommEvent[COMMEVT_WAIT] = m_o.hEvent;
m_hCommEvent[COMMEVT_ACK] = CreateEvent(NULL, // lpEventAttributes
FALSE, // bManualReset (FALSE = auto-reset)
FALSE, // bInitialState (FALSE = non-signaled)
NULL); // lpName
m_hCommEvent[COMMEVT_TERM] = CreateEvent(NULL, // lpEventAttributes
FALSE, // bManualReset (FALSE = auto-reset)
FALSE, // bInitialState (FALSE = non-signaled)
NULL); // lpName
if ((m_hCommEvent[0] == NULL) || (m_hCommEvent[1] == NULL) || (m_hCommEvent[2] == NULL))
{
if(g_fh) fprintf(g_fh, "Comm: CreateEvent failed\n");
return false;
}
}
//
if (m_hCommThread == NULL)
{
DWORD dwThreadId;
m_hCommThread = CreateThread(NULL, // lpThreadAttributes
0, // dwStackSize
(LPTHREAD_START_ROUTINE) &CSuperSerialCard::CommThread,
this, // lpParameter
0, // dwCreationFlags : 0 = Run immediately
&dwThreadId); // lpThreadId
InitializeCriticalSection(&m_CriticalSection);
}*/
return true;
}
void CSuperSerialCard::CommThUninit()
{
/* if (m_hCommThread)
{
SetEvent(m_hCommEvent[COMMEVT_TERM]); // Signal to thread that it should exit
do
{
DWORD dwExitCode;
if(GetExitCodeThread(m_hCommThread, &dwExitCode))
{
if(dwExitCode == STILL_ACTIVE)
Sleep(10);
else
break;
}
}
while(1);
CloseHandle(m_hCommThread);
m_hCommThread = NULL;
DeleteCriticalSection(&m_CriticalSection);
}
//
for (UINT i=0; i<COMMEVT_MAX; i++)
{
if(m_hCommEvent[i])
{
CloseHandle(m_hCommEvent[i]);
m_hCommEvent[i] = NULL;
}
}*/
}
//===========================================================================
DWORD CSuperSerialCard::CommGetSnapshot(SS_IO_Comms* pSS)
{
pSS->baudrate = m_uBaudRate;
pSS->bytesize = m_uByteSize;
pSS->commandbyte = m_uCommandByte;
pSS->comminactivity = m_dwCommInactivity;
pSS->controlbyte = m_uControlByte;
pSS->parity = m_uParity;
memcpy(pSS->recvbuffer, m_RecvBuffer, uRecvBufferSize);
pSS->recvbytes = m_vRecvBytes;
pSS->stopbits = m_uStopBits;
return 0;
}
DWORD CSuperSerialCard::CommSetSnapshot(SS_IO_Comms* pSS)
{
m_uBaudRate = pSS->baudrate;
m_uByteSize = pSS->bytesize;
m_uCommandByte = pSS->commandbyte;
m_dwCommInactivity = pSS->comminactivity;
m_uControlByte = pSS->controlbyte;
m_uParity = pSS->parity;
memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize);
m_vRecvBytes = pSS->recvbytes;
m_uStopBits = pSS->stopbits;
return 0;
}