| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487 |
- /*
- ** Command & Conquer Red Alert(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program 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 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : Command & Conquer/ WW Library *
- * *
- * File Name : WINCOMM.H *
- * *
- * Programmer : Steve Tall *
- * *
- * Start Date : 1/10/96 *
- * *
- * Last Update : January 10th 1996 [ST] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Overview: *
- * *
- * Functions for WinModemClass & WinNullModemClass *
- * *
- * These classes was created to replace the greenleaf comms functions used in C&C DOS with *
- * WIN32 API calls. *
- * *
- *---------------------------------------------------------------------------------------------*
- * *
- * Functions: *
- * *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- //#include "function.h"
- #include "wincomm.h"
- #include "timer.h"
- #include "keyboard.h"
- #include "misc.h"
- #include <io.h>
- #include <sys\types.h>
- #include <sys\stat.h>
- #include <fcntl.h>
- /*
- ** Define this to log modem activity to disk.
- */
- //#define LOG_MODEM
- /*
- ** Object represents a serial port
- */
- WinModemClass *SerialPort = NULL;
- /***********************************************************************************************
- * WMC::WinModemClass -- WinModemClass constructor *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:14PM ST : Created *
- *=============================================================================================*/
- WinModemClass::WinModemClass(void)
- {
- /*
- ** Allocate memory for our internal circular serial input buffer
- */
- SerialBuffer = new unsigned char [SIZE_OF_WINDOWS_SERIAL_BUFFER];
- /*
- ** Initialise the serial buffer pointers
- */
- SerialBufferReadPtr = 0;
- SerialBufferWritePtr = 0;
- /*
- ** Clear the waiting flags
- */
- WaitingForSerialCharRead = FALSE;
- WaitingForSerialCharWrite = FALSE;
- /*
- ** No default abort or echo function
- */
- AbortFunction = NULL;
- EchoFunction = NULL;
- /*
- ** Clear the running error count
- */
- FramingErrors=0;
- IOErrors=0;
- BufferOverruns=0;
- InBufferOverflows=0;
- ParityErrors=0;
- OutBufferOverflows=0;
- /*
- ** We havnt opened a port yet so...
- */
- PortHandle = 0;
- }
- /***********************************************************************************************
- * WMC::~WinModemClass -- destructor for WinModemClass *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:15PM ST : Created *
- *=============================================================================================*/
- WinModemClass::~WinModemClass(void)
- {
- /*
- ** Close the port
- */
- if (PortHandle){
- Serial_Port_Close();
- }
- /*
- ** Free the serial buffer
- */
- if (SerialBuffer){
- delete [] SerialBuffer;
- }
- }
- /***********************************************************************************************
- * Get_Registry_Sub_Key -- search a registry key for a sub-key *
- * *
- * *
- * *
- * INPUT: handle of key to search *
- * text to search for *
- * true if old key should be closed when new key opened *
- * *
- * OUTPUT: handle to the key we found or 0 *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/12/96 2:11PM ST : Created *
- *=============================================================================================*/
- HKEY Get_Registry_Sub_Key (HKEY base_key, char *search_key, BOOL close)
- {
- char class_string[1024];
- DWORD string_size = 1024;
- DWORD num_sub_keys;
- DWORD longest_sub_key_name;
- DWORD longest_class_string;
- DWORD num_value_entries;
- DWORD longest_value_name_length;
- DWORD longest_value_data_length;
- DWORD security_descriptor_length;
- FILETIME last_write_time;
- HKEY result_key;
- DWORD sub_key_buffer_size;
- char *sub_key_buffer;
- char *sub_key_class;
- if (RegQueryInfoKey (base_key,
- &class_string[0],
- &string_size,
- NULL,
- &num_sub_keys,
- &longest_sub_key_name,
- &longest_class_string,
- &num_value_entries,
- &longest_value_name_length,
- &longest_value_data_length,
- &security_descriptor_length,
- &last_write_time) != ERROR_SUCCESS) return (0);
- sub_key_buffer_size = longest_sub_key_name+16;
- sub_key_buffer = new char [sub_key_buffer_size];
- sub_key_class = new char [longest_class_string+1];
- for (int key_num=0 ; key_num<num_sub_keys ; key_num++){
- *sub_key_buffer = 0;
- longest_sub_key_name = sub_key_buffer_size;
- RegEnumKeyEx(base_key,
- key_num,
- sub_key_buffer,
- &longest_sub_key_name,
- NULL,
- sub_key_class,
- &longest_class_string,
- &last_write_time);
- if (!stricmp(search_key, sub_key_buffer)){
- if (RegOpenKeyEx( base_key,
- sub_key_buffer,
- NULL,
- KEY_READ,
- &result_key) == ERROR_SUCCESS){
- if (close){
- RegCloseKey(base_key);
- }
- delete [] sub_key_buffer;
- delete [] sub_key_class;
- return (result_key);
- }
- }
- }
- if (close){
- RegCloseKey(base_key);
- }
- delete [] sub_key_buffer;
- delete [] sub_key_class;
- return (0);
- }
- /***********************************************************************************************
- * Get_Modem_Name_From_Registry -- retrieve the name of the installed modem from the registry *
- * *
- * *
- * *
- * INPUT: buffer to put the name in *
- * length of buffer *
- * *
- * OUTPUT: TRUE if modem was found in the registry *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/12/96 2:13PM ST : Created *
- *=============================================================================================*/
- BOOL Get_Modem_Name_From_Registry(char *buffer, int buffer_len)
- {
- HKEY key;
- char modem_name[256];
- DWORD modem_name_size = 256;
- key = Get_Registry_Sub_Key (HKEY_LOCAL_MACHINE, "Enum", FALSE);
- if (!key) return (FALSE);
- key = Get_Registry_Sub_Key (key, "Root", TRUE);
- if (!key) return (FALSE);
- key = Get_Registry_Sub_Key (key, "Modem", TRUE);
- if (!key) return (FALSE);
- key = Get_Registry_Sub_Key (key, "0000", TRUE);
- if (!key) return (FALSE);
- if (RegQueryValueEx(key, "FriendlyName", NULL, NULL, (unsigned char*)&modem_name[0], &modem_name_size) != ERROR_SUCCESS){
- RegCloseKey(key);
- return (FALSE);
- }
- RegCloseKey(key);
- memcpy (buffer, modem_name, min(buffer_len, modem_name_size));
- return (TRUE);
- }
- #ifdef cuts
- /***********************************************************************************************
- * WMC::Serial_Port_Open -- opens a com port for asyncronous read/write and gets a handle to it*
- * *
- * *
- * *
- * INPUT: Com port - 0=com1, 1=com2 etc. *
- * baud rate - bits per second *
- * parity - true or false *
- * word length - 5 to 8 bits *
- * stop bits - 0=1 stop bit, 1=1.5 & 2=2 *
- * *
- * OUTPUT: Handle to port *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:17PM ST : Created *
- *=============================================================================================*/
- //VOID FAR PASCAL lineCallbackFunc(DWORD hDevice, DWORD dwMsg,
- // DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2,
- // DWORD dwParam3)
- VOID FAR PASCAL lineCallbackFunc(DWORD ,DWORD ,DWORD ,DWORD ,DWORD ,DWORD);
- extern HINSTANCE ProgramInstance;
- HANDLE WinModemClass::Serial_Port_Open (int com, int baud, int parity, int wordlen, int stopbits)
- {
- HANDLE com_handle; //temporary storage for the port handle
- DCB device_control; //device control block
- COMMTIMEOUTS timeouts; //timeout values
- char modem_name[256]; //name of modem
- char device_name[266]={"\\\\.\\"}; //device name to open
- DWORD config_size = 2048;
- char config[2048];
- COMMCONFIG *modem_config = (COMMCONFIG*)&config[0];
- MODEMDEVCAPS *modem_caps;
- int temp;
- BOOL found_modem;
- /*
- ** Map for com port values to device names
- */
- static char com_ids[8][5]={
- "COM1",
- "COM2",
- "COM3",
- "COM4",
- "COM5",
- "COM6",
- "COM7",
- "COM8"
- };
- HLINEAPP app_line_handle;
- DWORD num_devices;
- lineInitialise (&app_line_handle, ProgramInstance, &lineCallbackFunc, NULL, &num_devices);
- found_modem = TRUE;
- if (!Get_Modem_Name_From_Registry(modem_name, 256)){
- strcpy(modem_name, com_ids[com]);
- found_modem = FALSE;
- }
- strcat(device_name, modem_name);
- PortHandle = 0;
- /*
- ** Open the com port for asyncronous reads/writes
- */
- com_handle = CreateFile (device_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
- if (com_handle == INVALID_HANDLE_VALUE) return (com_handle);
- PortHandle = com_handle;
- /*
- ** Set the size of the windows communication buffers
- */
- SetupComm(com_handle, 2048, 2048);
- /*
- ** Create an event object for asyncronous reads
- */
- ReadOverlap.Internal = 0;
- ReadOverlap.InternalHigh = 0;
- ReadOverlap.Offset = 0;
- ReadOverlap.OffsetHigh = 0;
- ReadOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
- /*
- ** Create an event object for asyncronous writes
- */
- WriteOverlap.Internal = 0;
- WriteOverlap.InternalHigh = 0;
- WriteOverlap.Offset = 0;
- WriteOverlap.OffsetHigh = 0;
- WriteOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
- if (!found_modem){
- /*
- ** Get the current state of the com port as a basis for our device control block
- */
- GetCommState (com_handle , &device_control);
- /*
- ** Communications settings
- */
- device_control.BaudRate = baud;
- device_control.fParity = parity;
- device_control.ByteSize = wordlen;
- device_control.StopBits = stopbits-1;
- /*
- ** Misc settings for flow control etc.
- */
- device_control.fBinary = TRUE; // Binary mode data transfer
- device_control.fOutxCtsFlow = TRUE; // CTS flow control
- device_control.fRtsControl = RTS_CONTROL_HANDSHAKE; // RTS flow control
- device_control.fErrorChar = FALSE; // Dont put an error char into our input stream
- device_control.fOutxDsrFlow = FALSE; // No DSR flow control
- device_control.fDtrControl = DTR_CONTROL_ENABLE; // Enable control of DTR line
- device_control.fOutX = FALSE; // No XON/XOF flow control
- device_control.fInX = FALSE; // No XON/XOF flow control
- device_control.fAbortOnError = FALSE; // Device continues to send after an error
- /*
- ** Pass the device settings to windows
- */
- if (SetCommState (com_handle , &device_control) != TRUE){
- Serial_Port_Close();
- return (INVALID_HANDLE_VALUE);
- }
- }else{
- /*
- ** If we are talking to a modem device then turn off compression and error correction
- */
- GetCommConfig(PortHandle ,modem_config, &config_size);
- if (modem_config->dwProviderSubType == PST_MODEM){
- temp = modem_config->dwProviderOffset;
- temp += (int)modem_config;
- modem_caps = (MODEMDEVCAPS*)temp;
- modem_caps->dwModemOptions &= ~( MDM_COMPRESSION |
- MDM_ERROR_CONTROL |
- MDM_FLOWCONTROL_HARD);
- SetCommConfig(PortHandle, modem_config ,(unsigned)config_size);
- }
- }
- /*
- ** Set the device timeouts
- */
- timeouts.ReadIntervalTimeout = 10000; //10 seconds between incoming packets
- timeouts.ReadTotalTimeoutMultiplier = 0; //disable total timeouts
- timeouts.ReadTotalTimeoutConstant = 0; //disable total timeouts
- timeouts.WriteTotalTimeoutMultiplier= 0; //disable total timeouts
- timeouts.WriteTotalTimeoutConstant = 0; //disable total timeouts
- if (SetCommTimeouts(com_handle, &timeouts) !=TRUE){
- Serial_Port_Close();
- return (INVALID_HANDLE_VALUE);
- }
- return (com_handle);
- }
- #endif
- /***********************************************************************************************
- * WMC::Serial_Port_Open -- opens a com port for asyncronous read/write and gets a handle to it*
- * *
- * *
- * *
- * INPUT: Com port - 0=com1, 1=com2 etc. *
- * baud rate - bits per second *
- * parity - true or false *
- * word length - 5 to 8 bits *
- * stop bits - 0=1 stop bit, 1=1.5 & 2=2 *
- * flow control- 0 = none, 1 = hardware *
- * *
- * OUTPUT: Handle to port *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:17PM ST : Created *
- *=============================================================================================*/
- HANDLE WinModemClass::Serial_Port_Open (char *device_name, int baud, int parity, int wordlen, int stopbits, int flowcontrol)
- {
- HANDLE com_handle; //temporary storage for the port handle
- DCB device_control; //device control block
- COMMTIMEOUTS timeouts; //timeout values
- #if (0)
- /*
- ** Map for com port values to device names
- */
- static char com_ids[8][5]={
- "COM1",
- "COM2",
- "COM3",
- "COM4",
- "COM5",
- "COM6",
- "COM7",
- "COM8"
- };
- #endif //(0)
- int errorval;
- char errortxt[128];
- char devname[266]={"\\\\.\\"}; //device name to open
- strcat (devname, device_name);
- PortHandle = 0;
- /*
- ** Open the com port for asyncronous reads/writes
- */
- //com_handle = CreateFile (&com_ids[com][0], GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
- com_handle = CreateFile (devname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
- if (com_handle == INVALID_HANDLE_VALUE) return (com_handle);
- PortHandle = com_handle;
- /*
- ** Set the size of the windows communication buffers
- */
- SetupComm(com_handle, SIZE_OF_WINDOWS_SERIAL_BUFFER, SIZE_OF_WINDOWS_SERIAL_BUFFER);
- /*
- ** Reset any read or write operation and purge the buffers
- */
- PurgeComm (PortHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
- /*
- ** Create an event object for asyncronous reads
- */
- ReadOverlap.Internal = 0;
- ReadOverlap.InternalHigh = 0;
- ReadOverlap.Offset = 0;
- ReadOverlap.OffsetHigh = 0;
- ReadOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
- /*
- ** Create an event object for asyncronous writes
- */
- WriteOverlap.Internal = 0;
- WriteOverlap.InternalHigh = 0;
- WriteOverlap.Offset = 0;
- WriteOverlap.OffsetHigh = 0;
- WriteOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
- /*
- ** Get the current state of the com port as a basis for our device control block
- */
- if (GetCommState (com_handle , &device_control)){
- /*
- ** Communications settings
- */
- device_control.BaudRate = baud;
- device_control.fParity = parity;
- device_control.ByteSize = (char)wordlen;
- device_control.StopBits = (char)(stopbits-1);
- /*
- ** Misc settings for flow control etc.
- */
- device_control.fBinary = TRUE; // Binary mode data transfer
- device_control.fOutxCtsFlow = TRUE; // CTS flow control
- device_control.fRtsControl = RTS_CONTROL_HANDSHAKE; // RTS flow control
- device_control.fErrorChar = FALSE; // Dont put an error char into our input stream
- device_control.fOutxDsrFlow = FALSE; // No DSR flow control
- device_control.fDtrControl = DTR_CONTROL_ENABLE; // Enable control of DTR line
- device_control.fOutX = FALSE; // No XON/XOF flow control
- device_control.fInX = FALSE; // No XON/XOF flow control
- device_control.fAbortOnError = FALSE; // Device continues to send after an error
- /*
- ** Disable hardware flow control if required
- */
- if (!flowcontrol){
- device_control.fOutxCtsFlow = FALSE; // CTS flow control
- device_control.fRtsControl = RTS_CONTROL_DISABLE; // RTS flow control
- }
- /*
- ** Pass the device settings to windows
- */
- if ( !SetCommState (com_handle , &device_control)){
- errorval = GetLastError();
- sprintf (errortxt, "RA95 -- SetCommState returned error code %d.\n", errorval);
- OutputDebugString (errortxt);
- //Serial_Port_Close();
- //return (INVALID_HANDLE_VALUE);
- }
- }else{
- errorval = GetLastError();
- sprintf (errortxt, "RA95 -- GetCommState returned error code %d.\n", errorval);
- OutputDebugString (errortxt);
- }
- /*
- ** Set the device timeouts
- */
- timeouts.ReadIntervalTimeout = 1000; //1 second between incoming bytes will time-out the read
- timeouts.ReadTotalTimeoutMultiplier = 0; //disable per byte timeouts
- timeouts.ReadTotalTimeoutConstant = 3000; //Read operations time out after 3 secs if no data received
- timeouts.WriteTotalTimeoutMultiplier= 500; //Allow 1/2 ms between each char write
- timeouts.WriteTotalTimeoutConstant = 1000; //Write operations time out after 1 sec + 1/2 sec per char if data wasnt sent
- if ( !SetCommTimeouts(com_handle, &timeouts) ){
- errorval = GetLastError();
- sprintf (errortxt, "RA95 -- SetCommTimeouts returned error code %d.\n", errorval);
- OutputDebugString (errortxt);
- //Serial_Port_Close();
- //return (INVALID_HANDLE_VALUE);
- }
- return (com_handle);
- }
- /***********************************************************************************************
- * WMC::Set_Modem_Dial_Type -- sets dial type to WC_TOUCH_TONE or WC_PULSE *
- * *
- * *
- * *
- * INPUT: WC_TOUCH_TONE or WC_PULSE *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:22PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Set_Modem_Dial_Type(WinCommDialMethodType method)
- {
- DialingMethod = method;
- }
- /***********************************************************************************************
- * WMC::Get_Modem_Status -- gets the status of the modem control lines *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Modem status. Any of the following bits CTS_SET, DSR_SET, RI_SET or CD_SET *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:24PM ST : Created *
- *=============================================================================================*/
- unsigned WinModemClass::Get_Modem_Status(void)
- {
- DWORD modem_stat = 0;
- unsigned long return_stat = 0;
- /*
- ** Get the modem status
- */
- GetCommModemStatus(PortHandle, &modem_stat);
- /*
- ** Translate the windows status flags to greenleaf flags
- */
- if (MS_CTS_ON & modem_stat) return_stat |= CTS_SET;
- if (MS_DSR_ON & modem_stat) return_stat |= DSR_SET;
- if (MS_RING_ON & modem_stat) return_stat |= RI_SET;
- if (MS_RLSD_ON & modem_stat) return_stat |= CD_SET;
- return (return_stat);
- }
- /***********************************************************************************************
- * WMC::Set_Serial_DTR -- set the state of the modems DTR control line *
- * *
- * *
- * *
- * INPUT: state - true or false *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:25PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Set_Serial_DTR(BOOL state)
- {
- if (state){
- EscapeCommFunction(PortHandle, SETDTR);
- }else{
- EscapeCommFunction(PortHandle, CLRDTR);
- }
- }
- /***********************************************************************************************
- * WMC::Serial_Port_Close -- close the port and free the port handle *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:26PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Serial_Port_Close (void)
- {
- if (PortHandle){
- CloseHandle(PortHandle);
- PortHandle = 0;
- }
- }
- /***********************************************************************************************
- * WMC::Read_Serial_Chars -- copys chars from the windows serial buffer to the class buffer *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: TRUE if any chars read *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:26PM ST : Created *
- *=============================================================================================*/
- void Smart_Printf( char *format, ... );
- BOOL WinModemClass::Read_Serial_Chars (void)
- {
- DWORD bytes_read; //amount of data read this time
- BOOL read_result; //result of ReadFile
- BOOL overlap_result; //result of GetOverlappedResult
- DWORD total_bytes_read=0; //total amount of data read
- int bytes_to_read;
- int i;
- /*
- ** Are we were still waiting for the last read operation to finish?
- */
- if (WaitingForSerialCharRead){
- /*
- ** Check the result of the last read operation
- */
- bytes_read = 0;
- overlap_result = GetOverlappedResult(PortHandle, &ReadOverlap, &bytes_read, FALSE);
- /*
- ** If we got a good result from GetOverlappedResult and data was read then move it
- ** to our circular buffer
- */
- if (overlap_result){
- WaitingForSerialCharRead = FALSE; //Flag that we are no longer waiting for a read
- if (bytes_read){
- for (i=0 ; i<bytes_read ; i++){
- *(SerialBuffer + SerialBufferWritePtr++) = TempSerialBuffer[i];
- SerialBufferWritePtr &= SIZE_OF_WINDOWS_SERIAL_BUFFER - 1;
- }
- total_bytes_read += bytes_read;
- }
- }else{
- /*
- ** No chars were read since last time so just return
- */
- if (GetLastError() == ERROR_IO_INCOMPLETE){
- return (FALSE);
- }
- }
- }
- /*
- **
- ** There is no outstanding read to wait for so try a new read
- **
- */
- /*
- ** Clear the event object
- */
- ResetEvent(ReadOverlap.hEvent);
- /*
- **
- ** Clear any communications errors and get the number of bytes in the in buffer
- **
- */
- DWORD error;
- COMSTAT status;
- bytes_to_read = 1;
- if (ClearCommError(PortHandle, &error, &status)){
- InQueue = status.cbInQue;
- OutQueue = status.cbOutQue;
- if (error){
- if (CE_FRAME & error) FramingErrors++;
- if (CE_IOE & error) IOErrors++;
- if (CE_OVERRUN & error) BufferOverruns++;
- if (CE_RXOVER & error) InBufferOverflows++;
- if (CE_RXPARITY & error)ParityErrors++;
- if (CE_TXFULL & error) OutBufferOverflows++;
- bytes_to_read = 0;
- }else{
- bytes_to_read = min(status.cbInQue, SIZE_OF_WINDOWS_SERIAL_BUFFER);
- }
- }
- if (!bytes_to_read) bytes_to_read++;
- /*
- **
- ** Start reading bytes
- **
- */
- do{
- /*
- ** Try a read operation
- */
- bytes_read = 0;
- read_result = ReadFile(PortHandle ,TempSerialBuffer ,bytes_to_read ,&bytes_read, &ReadOverlap);
- if (!read_result){
- /*
- ** Read failed
- */
- if (GetLastError() == ERROR_IO_PENDING){
- /*
- ** But it threaded in the background OK so flag that we must wait for it to finish
- */
- WaitingForSerialCharRead = TRUE;
- }
- }else{
- /*
- ** Read was successful - copy to our circular buffer and try reading again
- */
- if (bytes_read){
- for (i=0 ; i<bytes_read ; i++){
- *(SerialBuffer + SerialBufferWritePtr++) = TempSerialBuffer[i];
- SerialBufferWritePtr &= SIZE_OF_WINDOWS_SERIAL_BUFFER - 1;
- }
- total_bytes_read += bytes_read;
- }
- bytes_to_read = 1;
- }
- } while (read_result == TRUE);
- return ((BOOL)total_bytes_read);
- }
- /***********************************************************************************************
- * WMC::Read_From_Serial_Port -- retrieves chars from the internal class circular buffer which *
- * is filled from the windows serial buffer *
- * *
- * *
- * INPUT: buffer to copy to *
- * size of buffer *
- * *
- * OUTPUT: number of chars copied *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:27PM ST : Created *
- *=============================================================================================*/
- int WinModemClass::Read_From_Serial_Port (unsigned char *dest_ptr, int buffer_len)
- {
- int bytes_read;
- int bytes_to_copy = 0;
- unsigned char *original_dest = dest_ptr;
- /*
- ** Get any outstanding data from the windows serial buffer into our class' circular buffer
- */
- bytes_read = Read_Serial_Chars();
- if (bytes_read){
- /*
- ** Calculate how many bytes should be copied to the user buffer
- */
- bytes_to_copy = SerialBufferWritePtr - SerialBufferReadPtr;
- if (bytes_to_copy <0 ) bytes_to_copy += SIZE_OF_WINDOWS_SERIAL_BUFFER;
- if (bytes_to_copy>buffer_len) bytes_to_copy = buffer_len;
- /*
- ** Loop to copy the data from the internal class buffer to the users buffer
- */
- for (int i=0 ; i<bytes_to_copy ; i++){
- /*
- ** Call the users echo function if required
- */
- if (EchoFunction && *(SerialBuffer + SerialBufferReadPtr) !=13 ){
- EchoFunction(*(SerialBuffer + SerialBufferReadPtr));
- }
- *dest_ptr++ = *(SerialBuffer + SerialBufferReadPtr++);
- SerialBufferReadPtr &= SIZE_OF_WINDOWS_SERIAL_BUFFER-1;
- }
- }
- #ifdef LOG_MODEM
- if (bytes_read){
- char *outstr = new char[bytes_read+1];
- memcpy (outstr, original_dest, bytes_read);
- outstr[bytes_read] = 0;
- OutputDebugString (outstr);
- int handle;
- handle = open("COMMLOG.TXT",O_WRONLY | O_CREAT | O_APPEND | O_TEXT);
- if (handle != -1){
- write(handle, original_dest, bytes_read);
- close(handle);
- }
- }
- #endif //LOG_MODEM
- return(bytes_to_copy);
- }
- /***********************************************************************************************
- * WMC::Wait_For_Serial_Write -- waits for output buffer to empty *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:29PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Wait_For_Serial_Write()
- {
- DWORD bytes_written;
- BOOL overlap_result;
- BOOL wait_send;
- CountDownTimerClass timer;
- if (WaitingForSerialCharWrite){
- timer.Set(60*5);
- /*
- ** Wait until the overlapped port write is finished
- */
- do{
- wait_send = FALSE;
- overlap_result = GetOverlappedResult(PortHandle, &WriteOverlap, &bytes_written, FALSE);
- if (!overlap_result){
- if (GetLastError() == ERROR_IO_INCOMPLETE){
- wait_send = TRUE;
- }
- }
- }while(wait_send && timer.Time());
- WaitingForSerialCharWrite = FALSE;
- }
- ResetEvent(WriteOverlap.hEvent);
- }
- /***********************************************************************************************
- * WMC::Write_To_Serial_Port -- writes data to the serial port *
- * *
- * *
- * *
- * INPUT: ptr to data *
- * bytes to write *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:29PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Write_To_Serial_Port (unsigned char *buffer, int length)
- {
- DWORD bytes_written;
- BOOL write_result;
- #ifdef LOG_MODEM
- if (length){
- char *outstr = new char[length+1];
- memcpy (outstr, buffer, length);
- outstr[length] = 0;
- OutputDebugString (outstr);
- int handle;
- handle = open("COMMLOG.TXT",O_WRONLY | O_CREAT | O_APPEND | O_TEXT);
- if (handle != -1){
- write(handle, buffer, length);
- close(handle);
- }
- }
- #endif //LOG_MODEM
- /*
- ** Wait for the end of the last write operation
- */
- Wait_For_Serial_Write();
- /*
- ** Write the data to the port
- */
- write_result = WriteFile (PortHandle, buffer, length, &bytes_written, &WriteOverlap);
- if (!write_result){
- if (GetLastError() == ERROR_IO_PENDING){
- WaitingForSerialCharWrite = TRUE;
- }
- }
- }
- /***********************************************************************************************
- * WMC::Get_Modem_Result -- gets the result code from the modem after issuing an 'AT' command *
- * *
- * *
- * *
- * INPUT: delay for result time-out *
- * ptr to buffer to receive modem result *
- * length of buffer *
- * *
- * OUTPUT: un-elapsed delay *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:30PM ST : Created *
- *=============================================================================================*/
- extern void CCDebugString (char*);
- int WinModemClass::Get_Modem_Result(int delay, char *buffer, int buffer_len)
- {
- CountDownTimerClass timer;
- int dest_ptr;
- char *cr_ptr;
- char *lf_ptr;
- int copy_bytes;
- //OutputDebugString ("Wincomm - In Get_Modem_Result\n");
- char abuffer [128];
- sprintf (abuffer, "Wincomm - delay = %d, buffer = %p, buffer_len = %d.\n", delay, buffer, buffer_len);
- //OutputDebugString (abuffer);
- //OutputDebugString ("Wincomm - About to clear input buffer.\n");
- memset(buffer, 0 ,buffer_len);
- dest_ptr = 0;
- /*
- ** Loop to parse data from the modem and discard any echoed 'AT' commands or spurious LF
- ** and CR characters.
- **
- */
- //OutputDebugString ("Wincomm - Entering do loop.\n");
- do{
- cr_ptr = NULL; //Set the result pointer to NULL
- //OutputDebugString ("Wincomm - About to set timer.\n");
- timer.Set(delay/16); //Set and start the timer
- /*
- ** Keep reading from the serial port until...
- ** 1. we time out
- ** 2. the user abort by pressing ESC
- ** 3. the supplied buffer fills up
- ** 4. there is an app switch
- ** or 5. we get a CR character from the modem
- */
- //OutputDebugString ("Wincomm - About to enter inner do loop.\n");
- do{
- if (AbortFunction){// &&
- //_Kbd->Check()) {
- //OutputDebugString ("Wincomm - About to call abort function.\n");
- int abort = AbortFunction();
- sprintf (abuffer ,"Wincomm - About function returned %d.\n", abort);
- //OutputDebugString (abuffer);
- if (abort != COMMSUCCESS) return (abort);
- }
- /*
- ** If we had lost focus then abort
- */
- if (AllSurfaces.SurfacesRestored){
- //OutputDebugString ("Wincomm - Aborting due to loss of focus.\n");
- return (0);
- }
- //OutputDebugString ("Wincomm - About to call Read_From_Serial_Port.\n");
- dest_ptr += Read_From_Serial_Port((unsigned char*)(buffer + dest_ptr), (int)buffer_len-dest_ptr);
- sprintf (abuffer, "Wincomm - End of inner do loop. Time is %d.\n", timer.Time());
- //OutputDebugString (abuffer);
- } while (timer.Time() &&
- dest_ptr < buffer_len &&
- !strchr (buffer, 13) );
- //OutputDebugString ("Wincomm - Exited inner do loop.\n");
- /*
- ** We need to discard this result if it is just an echo of the 'AT' command we sent
- */
- cr_ptr = strstr(buffer,"AT");
- if (cr_ptr){
- if (*buffer == 'A' && *(buffer+1) == 'T' && strchr(buffer,13)){
- //OutputDebugString ("Wincomm - Discarding command echo.\n");
- cr_ptr = strchr(buffer,13);
- }
- }
- /*
- ** If it wasnt an AT echo then strip off any leading CR/LF characters
- */
- if (!cr_ptr && (*buffer==13 || *buffer==10)){
- cr_ptr = strchr(buffer,13);
- lf_ptr = strchr(buffer,10);
- if (!cr_ptr || (lf_ptr && lf_ptr < cr_ptr)){
- //OutputDebugString ("Wincomm - Stripping CR/LF.\n");
- cr_ptr = strchr(buffer,10);
- }
- }
- /*
- ** Copy the good stuff at the end of the buffer over the 'AT' or CR/LF chars
- */
- if (cr_ptr){
- //OutputDebugString ("Wincomm - Copying over start of buffer.\n");
- while(*cr_ptr == 13 || *cr_ptr == 10){
- cr_ptr++;
- }
- if (cr_ptr != buffer){
- copy_bytes = (int)cr_ptr - (int)buffer;
- memcpy(buffer, cr_ptr, buffer_len - copy_bytes);
- dest_ptr -= copy_bytes;
- }
- }
- //OutputDebugString ("Wincomm - End of outer do loop.\n");
- }while(cr_ptr);
- /*
- ** Terminate the string at the first CR character as this is what Greenleaf does
- */
- if (strchr(buffer, 13)){
- //OutputDebugString ("Truncating result string.\n");
- *(strchr(buffer, 13)) = 0;
- }
- //sprintf (abuffer, "Wincomm - returning remaining delay of %d.\n", timer.Time());
- //OutputDebugString (abuffer);
- return (timer.Time());
- }
- /***********************************************************************************************
- * WMC::Dial_Modem -- issue an 'ATD' command to the modem *
- * *
- * *
- * *
- * INPUT: string - number to dial *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: Use Set_Modem_Dial_Type to choose pulse or tone dialling *
- * *
- * HISTORY: *
- * 1/10/96 2:32PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Dial_Modem(char *dial_number)
- {
- char dial_string[80];
- /*
- ** Create the dial command to send to the modem
- */
- strcpy (dial_string, "ATD");
- if (DialingMethod == WC_TOUCH_TONE){
- strcat(dial_string, "T");
- }else{
- strcat(dial_string, "P");
- }
- /*
- ** Stick a carriage return on the end
- */
- strcat (dial_string, dial_number);
- strcat (dial_string, "\r");
- /*
- ** Write the dial command to the serial port and wait for the write to complete
- */
- Write_To_Serial_Port ((unsigned char*)dial_string, strlen(dial_string));
- Wait_For_Serial_Write();
- }
- /***********************************************************************************************
- * WMC::Send_Command_To_Modem -- send an 'AT' command to the modem and await a response *
- * *
- * *
- * *
- * INPUT: command string *
- * terminator byte (usually "\r") *
- * ptr to buffer to receive modem result code *
- * length of buffer *
- * timeout delay for waiting for result *
- * number of times to retry the command *
- * *
- * OUTPUT: result code *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:33PM ST : Created *
- *=============================================================================================*/
- int WinModemClass::Send_Command_To_Modem(char *command, char terminator, char *buffer, int buflen, int delay, int retries)
- {
- int times;
- unsigned char tmp_string[80];
- char tmp_buff[80];
- char term_string[2];
- int time;
- /*
- ** Build the terminator string
- */
- term_string[0] = terminator;
- term_string[1] = 0;
- /*
- ** Create the command from the supplied command and terminator
- */
- strcpy((char*)tmp_string, command);
- strcat((char*)tmp_string, term_string);
- /*
- ** Flush out any pending characters from the port
- */
- unsigned char nothing_buff[80];
- Read_From_Serial_Port(nothing_buff,80);
- Sleep (100);
- Read_From_Serial_Port(nothing_buff,80);
- for (times = 0 ; times<retries; times++){
- /*
- ** Write the command to the serial port
- */
- //Smart_Printf("%s",tmp_string);
- Write_To_Serial_Port (tmp_string, strlen((char*)tmp_string));
- Wait_For_Serial_Write();
- //Delay(120);
- /*
- ** Wait for the result of the command from the modem
- */
- memset(tmp_buff, 0, 80);
- time = Get_Modem_Result(delay, tmp_buff, 80);
- //Smart_Printf("%s%s",tmp_buff,"\r");
- /*
- ** If it is a pretty standard result then just return
- */
- if (!strcmp(tmp_buff,"0")) return (MODEM_CMD_0);
- if (strstr(tmp_buff,"OK")) return (MODEM_CMD_OK);
- if (strstr(tmp_buff,"ERROR")) return (MODEM_CMD_ERROR);
- /*
- ** If the result was a 3 digit number then copy it to the users buffer and return OK
- */
- if (strlen(tmp_buff)==3){
- if ( (tmp_buff[0] >= '0' && tmp_buff[0] <='9') &&
- (tmp_buff[1] >= '0' && tmp_buff[1] <='9') &&
- (tmp_buff[2] >= '0' && tmp_buff[2] <='9')) {
- strncpy(buffer, tmp_buff, MIN(buflen, 80));
- return (MODEM_CMD_OK);
- }
- }
- /*
- ** It was a non-standard(ish) result so copy it to the users buffer
- */
- strncpy(buffer, tmp_buff, MIN(buflen, 80));
- /*
- ** Spurious write for no apparent reason. Well it was there in the DOS version so...
- */
- Sleep (100);
- Write_To_Serial_Port((unsigned char*)"\r",1);
- Wait_For_Serial_Write();
- Sleep (100);
- }
- return (ASTIMEOUT);
- }
- /***********************************************************************************************
- * WMC::Set_Echo_Function -- set up the echo function pointer *
- * *
- * *
- * *
- * INPUT: ptr to echo function *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:35PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Set_Echo_Function( void ( *func )( char c) )
- {
- EchoFunction = func;
- }
- /***********************************************************************************************
- * WMC::Set_Abort_Function -- set up the abort function pointer *
- * *
- * *
- * *
- * INPUT: ptr to abort function *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 1/10/96 2:35PM ST : Created *
- *=============================================================================================*/
- void WinModemClass::Set_Abort_Function(int (*func)(void))
- {
- AbortFunction = func;
- }
- /***********************************************************************************************
- * WMC::Get_Port_Handle -- returns a handle to the communications port *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Com port handle *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 5/23/96 1:25PM ST : Created *
- *=============================================================================================*/
- HANDLE WinModemClass::Get_Port_Handle(void)
- {
- return (PortHandle);
- }
|