WINCOMM.CPP 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer/ WW Library *
  23. * *
  24. * File Name : WINCOMM.H *
  25. * *
  26. * Programmer : Steve Tall *
  27. * *
  28. * Start Date : 1/10/96 *
  29. * *
  30. * Last Update : January 10th 1996 [ST] *
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Overview: *
  34. * *
  35. * Functions for WinModemClass & WinNullModemClass *
  36. * *
  37. * These classes was created to replace the greenleaf comms functions used in C&C DOS with *
  38. * WIN32 API calls. *
  39. * *
  40. *---------------------------------------------------------------------------------------------*
  41. * *
  42. * Functions: *
  43. * *
  44. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  45. //#include "function.h"
  46. #include "wincomm.h"
  47. #include "timer.h"
  48. #include "keyboard.h"
  49. #include "misc.h"
  50. #include <io.h>
  51. #include <sys\types.h>
  52. #include <sys\stat.h>
  53. #include <fcntl.h>
  54. /*
  55. ** Define this to log modem activity to disk.
  56. */
  57. //#define LOG_MODEM
  58. /*
  59. ** Object represents a serial port
  60. */
  61. WinModemClass *SerialPort = NULL;
  62. /***********************************************************************************************
  63. * WMC::WinModemClass -- WinModemClass constructor *
  64. * *
  65. * *
  66. * *
  67. * INPUT: Nothing *
  68. * *
  69. * OUTPUT: Nothing *
  70. * *
  71. * WARNINGS: None *
  72. * *
  73. * HISTORY: *
  74. * 1/10/96 2:14PM ST : Created *
  75. *=============================================================================================*/
  76. WinModemClass::WinModemClass(void)
  77. {
  78. /*
  79. ** Allocate memory for our internal circular serial input buffer
  80. */
  81. SerialBuffer = new unsigned char [SIZE_OF_WINDOWS_SERIAL_BUFFER];
  82. /*
  83. ** Initialise the serial buffer pointers
  84. */
  85. SerialBufferReadPtr = 0;
  86. SerialBufferWritePtr = 0;
  87. /*
  88. ** Clear the waiting flags
  89. */
  90. WaitingForSerialCharRead = FALSE;
  91. WaitingForSerialCharWrite = FALSE;
  92. /*
  93. ** No default abort or echo function
  94. */
  95. AbortFunction = NULL;
  96. EchoFunction = NULL;
  97. /*
  98. ** Clear the running error count
  99. */
  100. FramingErrors=0;
  101. IOErrors=0;
  102. BufferOverruns=0;
  103. InBufferOverflows=0;
  104. ParityErrors=0;
  105. OutBufferOverflows=0;
  106. /*
  107. ** We havnt opened a port yet so...
  108. */
  109. PortHandle = 0;
  110. }
  111. /***********************************************************************************************
  112. * WMC::~WinModemClass -- destructor for WinModemClass *
  113. * *
  114. * *
  115. * *
  116. * INPUT: Nothing *
  117. * *
  118. * OUTPUT: Nothing *
  119. * *
  120. * WARNINGS: None *
  121. * *
  122. * HISTORY: *
  123. * 1/10/96 2:15PM ST : Created *
  124. *=============================================================================================*/
  125. WinModemClass::~WinModemClass(void)
  126. {
  127. /*
  128. ** Close the port
  129. */
  130. if (PortHandle){
  131. Serial_Port_Close();
  132. }
  133. /*
  134. ** Free the serial buffer
  135. */
  136. if (SerialBuffer){
  137. delete [] SerialBuffer;
  138. }
  139. }
  140. /***********************************************************************************************
  141. * Get_Registry_Sub_Key -- search a registry key for a sub-key *
  142. * *
  143. * *
  144. * *
  145. * INPUT: handle of key to search *
  146. * text to search for *
  147. * true if old key should be closed when new key opened *
  148. * *
  149. * OUTPUT: handle to the key we found or 0 *
  150. * *
  151. * WARNINGS: None *
  152. * *
  153. * HISTORY: *
  154. * 1/12/96 2:11PM ST : Created *
  155. *=============================================================================================*/
  156. HKEY Get_Registry_Sub_Key (HKEY base_key, char *search_key, BOOL close)
  157. {
  158. char class_string[1024];
  159. DWORD string_size = 1024;
  160. DWORD num_sub_keys;
  161. DWORD longest_sub_key_name;
  162. DWORD longest_class_string;
  163. DWORD num_value_entries;
  164. DWORD longest_value_name_length;
  165. DWORD longest_value_data_length;
  166. DWORD security_descriptor_length;
  167. FILETIME last_write_time;
  168. HKEY result_key;
  169. DWORD sub_key_buffer_size;
  170. char *sub_key_buffer;
  171. char *sub_key_class;
  172. if (RegQueryInfoKey (base_key,
  173. &class_string[0],
  174. &string_size,
  175. NULL,
  176. &num_sub_keys,
  177. &longest_sub_key_name,
  178. &longest_class_string,
  179. &num_value_entries,
  180. &longest_value_name_length,
  181. &longest_value_data_length,
  182. &security_descriptor_length,
  183. &last_write_time) != ERROR_SUCCESS) return (0);
  184. sub_key_buffer_size = longest_sub_key_name+16;
  185. sub_key_buffer = new char [sub_key_buffer_size];
  186. sub_key_class = new char [longest_class_string+1];
  187. for (int key_num=0 ; key_num<num_sub_keys ; key_num++){
  188. *sub_key_buffer = 0;
  189. longest_sub_key_name = sub_key_buffer_size;
  190. RegEnumKeyEx(base_key,
  191. key_num,
  192. sub_key_buffer,
  193. &longest_sub_key_name,
  194. NULL,
  195. sub_key_class,
  196. &longest_class_string,
  197. &last_write_time);
  198. if (!stricmp(search_key, sub_key_buffer)){
  199. if (RegOpenKeyEx( base_key,
  200. sub_key_buffer,
  201. NULL,
  202. KEY_READ,
  203. &result_key) == ERROR_SUCCESS){
  204. if (close){
  205. RegCloseKey(base_key);
  206. }
  207. delete [] sub_key_buffer;
  208. delete [] sub_key_class;
  209. return (result_key);
  210. }
  211. }
  212. }
  213. if (close){
  214. RegCloseKey(base_key);
  215. }
  216. delete [] sub_key_buffer;
  217. delete [] sub_key_class;
  218. return (0);
  219. }
  220. /***********************************************************************************************
  221. * Get_Modem_Name_From_Registry -- retrieve the name of the installed modem from the registry *
  222. * *
  223. * *
  224. * *
  225. * INPUT: buffer to put the name in *
  226. * length of buffer *
  227. * *
  228. * OUTPUT: TRUE if modem was found in the registry *
  229. * *
  230. * WARNINGS: None *
  231. * *
  232. * HISTORY: *
  233. * 1/12/96 2:13PM ST : Created *
  234. *=============================================================================================*/
  235. BOOL Get_Modem_Name_From_Registry(char *buffer, int buffer_len)
  236. {
  237. HKEY key;
  238. char modem_name[256];
  239. DWORD modem_name_size = 256;
  240. key = Get_Registry_Sub_Key (HKEY_LOCAL_MACHINE, "Enum", FALSE);
  241. if (!key) return (FALSE);
  242. key = Get_Registry_Sub_Key (key, "Root", TRUE);
  243. if (!key) return (FALSE);
  244. key = Get_Registry_Sub_Key (key, "Modem", TRUE);
  245. if (!key) return (FALSE);
  246. key = Get_Registry_Sub_Key (key, "0000", TRUE);
  247. if (!key) return (FALSE);
  248. if (RegQueryValueEx(key, "FriendlyName", NULL, NULL, (unsigned char*)&modem_name[0], &modem_name_size) != ERROR_SUCCESS){
  249. RegCloseKey(key);
  250. return (FALSE);
  251. }
  252. RegCloseKey(key);
  253. memcpy (buffer, modem_name, min(buffer_len, modem_name_size));
  254. return (TRUE);
  255. }
  256. #ifdef cuts
  257. /***********************************************************************************************
  258. * WMC::Serial_Port_Open -- opens a com port for asyncronous read/write and gets a handle to it*
  259. * *
  260. * *
  261. * *
  262. * INPUT: Com port - 0=com1, 1=com2 etc. *
  263. * baud rate - bits per second *
  264. * parity - true or false *
  265. * word length - 5 to 8 bits *
  266. * stop bits - 0=1 stop bit, 1=1.5 & 2=2 *
  267. * *
  268. * OUTPUT: Handle to port *
  269. * *
  270. * WARNINGS: None *
  271. * *
  272. * HISTORY: *
  273. * 1/10/96 2:17PM ST : Created *
  274. *=============================================================================================*/
  275. //VOID FAR PASCAL lineCallbackFunc(DWORD hDevice, DWORD dwMsg,
  276. // DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2,
  277. // DWORD dwParam3)
  278. VOID FAR PASCAL lineCallbackFunc(DWORD ,DWORD ,DWORD ,DWORD ,DWORD ,DWORD);
  279. extern HINSTANCE ProgramInstance;
  280. HANDLE WinModemClass::Serial_Port_Open (int com, int baud, int parity, int wordlen, int stopbits)
  281. {
  282. HANDLE com_handle; //temporary storage for the port handle
  283. DCB device_control; //device control block
  284. COMMTIMEOUTS timeouts; //timeout values
  285. char modem_name[256]; //name of modem
  286. char device_name[266]={"\\\\.\\"}; //device name to open
  287. DWORD config_size = 2048;
  288. char config[2048];
  289. COMMCONFIG *modem_config = (COMMCONFIG*)&config[0];
  290. MODEMDEVCAPS *modem_caps;
  291. int temp;
  292. BOOL found_modem;
  293. /*
  294. ** Map for com port values to device names
  295. */
  296. static char com_ids[8][5]={
  297. "COM1",
  298. "COM2",
  299. "COM3",
  300. "COM4",
  301. "COM5",
  302. "COM6",
  303. "COM7",
  304. "COM8"
  305. };
  306. HLINEAPP app_line_handle;
  307. DWORD num_devices;
  308. lineInitialise (&app_line_handle, ProgramInstance, &lineCallbackFunc, NULL, &num_devices);
  309. found_modem = TRUE;
  310. if (!Get_Modem_Name_From_Registry(modem_name, 256)){
  311. strcpy(modem_name, com_ids[com]);
  312. found_modem = FALSE;
  313. }
  314. strcat(device_name, modem_name);
  315. PortHandle = 0;
  316. /*
  317. ** Open the com port for asyncronous reads/writes
  318. */
  319. com_handle = CreateFile (device_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  320. if (com_handle == INVALID_HANDLE_VALUE) return (com_handle);
  321. PortHandle = com_handle;
  322. /*
  323. ** Set the size of the windows communication buffers
  324. */
  325. SetupComm(com_handle, 2048, 2048);
  326. /*
  327. ** Create an event object for asyncronous reads
  328. */
  329. ReadOverlap.Internal = 0;
  330. ReadOverlap.InternalHigh = 0;
  331. ReadOverlap.Offset = 0;
  332. ReadOverlap.OffsetHigh = 0;
  333. ReadOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
  334. /*
  335. ** Create an event object for asyncronous writes
  336. */
  337. WriteOverlap.Internal = 0;
  338. WriteOverlap.InternalHigh = 0;
  339. WriteOverlap.Offset = 0;
  340. WriteOverlap.OffsetHigh = 0;
  341. WriteOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
  342. if (!found_modem){
  343. /*
  344. ** Get the current state of the com port as a basis for our device control block
  345. */
  346. GetCommState (com_handle , &device_control);
  347. /*
  348. ** Communications settings
  349. */
  350. device_control.BaudRate = baud;
  351. device_control.fParity = parity;
  352. device_control.ByteSize = wordlen;
  353. device_control.StopBits = stopbits-1;
  354. /*
  355. ** Misc settings for flow control etc.
  356. */
  357. device_control.fBinary = TRUE; // Binary mode data transfer
  358. device_control.fOutxCtsFlow = TRUE; // CTS flow control
  359. device_control.fRtsControl = RTS_CONTROL_HANDSHAKE; // RTS flow control
  360. device_control.fErrorChar = FALSE; // Dont put an error char into our input stream
  361. device_control.fOutxDsrFlow = FALSE; // No DSR flow control
  362. device_control.fDtrControl = DTR_CONTROL_ENABLE; // Enable control of DTR line
  363. device_control.fOutX = FALSE; // No XON/XOF flow control
  364. device_control.fInX = FALSE; // No XON/XOF flow control
  365. device_control.fAbortOnError = FALSE; // Device continues to send after an error
  366. /*
  367. ** Pass the device settings to windows
  368. */
  369. if (SetCommState (com_handle , &device_control) != TRUE){
  370. Serial_Port_Close();
  371. return (INVALID_HANDLE_VALUE);
  372. }
  373. }else{
  374. /*
  375. ** If we are talking to a modem device then turn off compression and error correction
  376. */
  377. GetCommConfig(PortHandle ,modem_config, &config_size);
  378. if (modem_config->dwProviderSubType == PST_MODEM){
  379. temp = modem_config->dwProviderOffset;
  380. temp += (int)modem_config;
  381. modem_caps = (MODEMDEVCAPS*)temp;
  382. modem_caps->dwModemOptions &= ~( MDM_COMPRESSION |
  383. MDM_ERROR_CONTROL |
  384. MDM_FLOWCONTROL_HARD);
  385. SetCommConfig(PortHandle, modem_config ,(unsigned)config_size);
  386. }
  387. }
  388. /*
  389. ** Set the device timeouts
  390. */
  391. timeouts.ReadIntervalTimeout = 10000; //10 seconds between incoming packets
  392. timeouts.ReadTotalTimeoutMultiplier = 0; //disable total timeouts
  393. timeouts.ReadTotalTimeoutConstant = 0; //disable total timeouts
  394. timeouts.WriteTotalTimeoutMultiplier= 0; //disable total timeouts
  395. timeouts.WriteTotalTimeoutConstant = 0; //disable total timeouts
  396. if (SetCommTimeouts(com_handle, &timeouts) !=TRUE){
  397. Serial_Port_Close();
  398. return (INVALID_HANDLE_VALUE);
  399. }
  400. return (com_handle);
  401. }
  402. #endif
  403. /***********************************************************************************************
  404. * WMC::Serial_Port_Open -- opens a com port for asyncronous read/write and gets a handle to it*
  405. * *
  406. * *
  407. * *
  408. * INPUT: Com port - 0=com1, 1=com2 etc. *
  409. * baud rate - bits per second *
  410. * parity - true or false *
  411. * word length - 5 to 8 bits *
  412. * stop bits - 0=1 stop bit, 1=1.5 & 2=2 *
  413. * flow control- 0 = none, 1 = hardware *
  414. * *
  415. * OUTPUT: Handle to port *
  416. * *
  417. * WARNINGS: None *
  418. * *
  419. * HISTORY: *
  420. * 1/10/96 2:17PM ST : Created *
  421. *=============================================================================================*/
  422. HANDLE WinModemClass::Serial_Port_Open (char *device_name, int baud, int parity, int wordlen, int stopbits, int flowcontrol)
  423. {
  424. HANDLE com_handle; //temporary storage for the port handle
  425. DCB device_control; //device control block
  426. COMMTIMEOUTS timeouts; //timeout values
  427. #if (0)
  428. /*
  429. ** Map for com port values to device names
  430. */
  431. static char com_ids[8][5]={
  432. "COM1",
  433. "COM2",
  434. "COM3",
  435. "COM4",
  436. "COM5",
  437. "COM6",
  438. "COM7",
  439. "COM8"
  440. };
  441. #endif //(0)
  442. int errorval;
  443. char errortxt[128];
  444. char devname[266]={"\\\\.\\"}; //device name to open
  445. strcat (devname, device_name);
  446. PortHandle = 0;
  447. /*
  448. ** Open the com port for asyncronous reads/writes
  449. */
  450. //com_handle = CreateFile (&com_ids[com][0], GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  451. com_handle = CreateFile (devname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  452. if (com_handle == INVALID_HANDLE_VALUE) return (com_handle);
  453. PortHandle = com_handle;
  454. /*
  455. ** Set the size of the windows communication buffers
  456. */
  457. SetupComm(com_handle, SIZE_OF_WINDOWS_SERIAL_BUFFER, SIZE_OF_WINDOWS_SERIAL_BUFFER);
  458. /*
  459. ** Reset any read or write operation and purge the buffers
  460. */
  461. PurgeComm (PortHandle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
  462. /*
  463. ** Create an event object for asyncronous reads
  464. */
  465. ReadOverlap.Internal = 0;
  466. ReadOverlap.InternalHigh = 0;
  467. ReadOverlap.Offset = 0;
  468. ReadOverlap.OffsetHigh = 0;
  469. ReadOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
  470. /*
  471. ** Create an event object for asyncronous writes
  472. */
  473. WriteOverlap.Internal = 0;
  474. WriteOverlap.InternalHigh = 0;
  475. WriteOverlap.Offset = 0;
  476. WriteOverlap.OffsetHigh = 0;
  477. WriteOverlap.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
  478. /*
  479. ** Get the current state of the com port as a basis for our device control block
  480. */
  481. if (GetCommState (com_handle , &device_control)){
  482. /*
  483. ** Communications settings
  484. */
  485. device_control.BaudRate = baud;
  486. device_control.fParity = parity;
  487. device_control.ByteSize = (char)wordlen;
  488. device_control.StopBits = (char)(stopbits-1);
  489. /*
  490. ** Misc settings for flow control etc.
  491. */
  492. device_control.fBinary = TRUE; // Binary mode data transfer
  493. device_control.fOutxCtsFlow = TRUE; // CTS flow control
  494. device_control.fRtsControl = RTS_CONTROL_HANDSHAKE; // RTS flow control
  495. device_control.fErrorChar = FALSE; // Dont put an error char into our input stream
  496. device_control.fOutxDsrFlow = FALSE; // No DSR flow control
  497. device_control.fDtrControl = DTR_CONTROL_ENABLE; // Enable control of DTR line
  498. device_control.fOutX = FALSE; // No XON/XOF flow control
  499. device_control.fInX = FALSE; // No XON/XOF flow control
  500. device_control.fAbortOnError = FALSE; // Device continues to send after an error
  501. /*
  502. ** Disable hardware flow control if required
  503. */
  504. if (!flowcontrol){
  505. device_control.fOutxCtsFlow = FALSE; // CTS flow control
  506. device_control.fRtsControl = RTS_CONTROL_DISABLE; // RTS flow control
  507. }
  508. /*
  509. ** Pass the device settings to windows
  510. */
  511. if ( !SetCommState (com_handle , &device_control)){
  512. errorval = GetLastError();
  513. sprintf (errortxt, "RA95 -- SetCommState returned error code %d.\n", errorval);
  514. OutputDebugString (errortxt);
  515. //Serial_Port_Close();
  516. //return (INVALID_HANDLE_VALUE);
  517. }
  518. }else{
  519. errorval = GetLastError();
  520. sprintf (errortxt, "RA95 -- GetCommState returned error code %d.\n", errorval);
  521. OutputDebugString (errortxt);
  522. }
  523. /*
  524. ** Set the device timeouts
  525. */
  526. timeouts.ReadIntervalTimeout = 1000; //1 second between incoming bytes will time-out the read
  527. timeouts.ReadTotalTimeoutMultiplier = 0; //disable per byte timeouts
  528. timeouts.ReadTotalTimeoutConstant = 3000; //Read operations time out after 3 secs if no data received
  529. timeouts.WriteTotalTimeoutMultiplier= 500; //Allow 1/2 ms between each char write
  530. timeouts.WriteTotalTimeoutConstant = 1000; //Write operations time out after 1 sec + 1/2 sec per char if data wasnt sent
  531. if ( !SetCommTimeouts(com_handle, &timeouts) ){
  532. errorval = GetLastError();
  533. sprintf (errortxt, "RA95 -- SetCommTimeouts returned error code %d.\n", errorval);
  534. OutputDebugString (errortxt);
  535. //Serial_Port_Close();
  536. //return (INVALID_HANDLE_VALUE);
  537. }
  538. return (com_handle);
  539. }
  540. /***********************************************************************************************
  541. * WMC::Set_Modem_Dial_Type -- sets dial type to WC_TOUCH_TONE or WC_PULSE *
  542. * *
  543. * *
  544. * *
  545. * INPUT: WC_TOUCH_TONE or WC_PULSE *
  546. * *
  547. * OUTPUT: Nothing *
  548. * *
  549. * WARNINGS: None *
  550. * *
  551. * HISTORY: *
  552. * 1/10/96 2:22PM ST : Created *
  553. *=============================================================================================*/
  554. void WinModemClass::Set_Modem_Dial_Type(WinCommDialMethodType method)
  555. {
  556. DialingMethod = method;
  557. }
  558. /***********************************************************************************************
  559. * WMC::Get_Modem_Status -- gets the status of the modem control lines *
  560. * *
  561. * *
  562. * *
  563. * INPUT: Nothing *
  564. * *
  565. * OUTPUT: Modem status. Any of the following bits CTS_SET, DSR_SET, RI_SET or CD_SET *
  566. * *
  567. * WARNINGS: None *
  568. * *
  569. * HISTORY: *
  570. * 1/10/96 2:24PM ST : Created *
  571. *=============================================================================================*/
  572. unsigned WinModemClass::Get_Modem_Status(void)
  573. {
  574. DWORD modem_stat = 0;
  575. unsigned long return_stat = 0;
  576. /*
  577. ** Get the modem status
  578. */
  579. GetCommModemStatus(PortHandle, &modem_stat);
  580. /*
  581. ** Translate the windows status flags to greenleaf flags
  582. */
  583. if (MS_CTS_ON & modem_stat) return_stat |= CTS_SET;
  584. if (MS_DSR_ON & modem_stat) return_stat |= DSR_SET;
  585. if (MS_RING_ON & modem_stat) return_stat |= RI_SET;
  586. if (MS_RLSD_ON & modem_stat) return_stat |= CD_SET;
  587. return (return_stat);
  588. }
  589. /***********************************************************************************************
  590. * WMC::Set_Serial_DTR -- set the state of the modems DTR control line *
  591. * *
  592. * *
  593. * *
  594. * INPUT: state - true or false *
  595. * *
  596. * OUTPUT: Nothing *
  597. * *
  598. * WARNINGS: None *
  599. * *
  600. * HISTORY: *
  601. * 1/10/96 2:25PM ST : Created *
  602. *=============================================================================================*/
  603. void WinModemClass::Set_Serial_DTR(BOOL state)
  604. {
  605. if (state){
  606. EscapeCommFunction(PortHandle, SETDTR);
  607. }else{
  608. EscapeCommFunction(PortHandle, CLRDTR);
  609. }
  610. }
  611. /***********************************************************************************************
  612. * WMC::Serial_Port_Close -- close the port and free the port handle *
  613. * *
  614. * *
  615. * *
  616. * INPUT: Nothing *
  617. * *
  618. * OUTPUT: Nothing *
  619. * *
  620. * WARNINGS: None *
  621. * *
  622. * HISTORY: *
  623. * 1/10/96 2:26PM ST : Created *
  624. *=============================================================================================*/
  625. void WinModemClass::Serial_Port_Close (void)
  626. {
  627. if (PortHandle){
  628. CloseHandle(PortHandle);
  629. PortHandle = 0;
  630. }
  631. }
  632. /***********************************************************************************************
  633. * WMC::Read_Serial_Chars -- copys chars from the windows serial buffer to the class buffer *
  634. * *
  635. * *
  636. * *
  637. * INPUT: Nothing *
  638. * *
  639. * OUTPUT: TRUE if any chars read *
  640. * *
  641. * WARNINGS: None *
  642. * *
  643. * HISTORY: *
  644. * 1/10/96 2:26PM ST : Created *
  645. *=============================================================================================*/
  646. void Smart_Printf( char *format, ... );
  647. BOOL WinModemClass::Read_Serial_Chars (void)
  648. {
  649. DWORD bytes_read; //amount of data read this time
  650. BOOL read_result; //result of ReadFile
  651. BOOL overlap_result; //result of GetOverlappedResult
  652. DWORD total_bytes_read=0; //total amount of data read
  653. int bytes_to_read;
  654. int i;
  655. /*
  656. ** Are we were still waiting for the last read operation to finish?
  657. */
  658. if (WaitingForSerialCharRead){
  659. /*
  660. ** Check the result of the last read operation
  661. */
  662. bytes_read = 0;
  663. overlap_result = GetOverlappedResult(PortHandle, &ReadOverlap, &bytes_read, FALSE);
  664. /*
  665. ** If we got a good result from GetOverlappedResult and data was read then move it
  666. ** to our circular buffer
  667. */
  668. if (overlap_result){
  669. WaitingForSerialCharRead = FALSE; //Flag that we are no longer waiting for a read
  670. if (bytes_read){
  671. for (i=0 ; i<bytes_read ; i++){
  672. *(SerialBuffer + SerialBufferWritePtr++) = TempSerialBuffer[i];
  673. SerialBufferWritePtr &= SIZE_OF_WINDOWS_SERIAL_BUFFER - 1;
  674. }
  675. total_bytes_read += bytes_read;
  676. }
  677. }else{
  678. /*
  679. ** No chars were read since last time so just return
  680. */
  681. if (GetLastError() == ERROR_IO_INCOMPLETE){
  682. return (FALSE);
  683. }
  684. }
  685. }
  686. /*
  687. **
  688. ** There is no outstanding read to wait for so try a new read
  689. **
  690. */
  691. /*
  692. ** Clear the event object
  693. */
  694. ResetEvent(ReadOverlap.hEvent);
  695. /*
  696. **
  697. ** Clear any communications errors and get the number of bytes in the in buffer
  698. **
  699. */
  700. DWORD error;
  701. COMSTAT status;
  702. bytes_to_read = 1;
  703. if (ClearCommError(PortHandle, &error, &status)){
  704. InQueue = status.cbInQue;
  705. OutQueue = status.cbOutQue;
  706. if (error){
  707. if (CE_FRAME & error) FramingErrors++;
  708. if (CE_IOE & error) IOErrors++;
  709. if (CE_OVERRUN & error) BufferOverruns++;
  710. if (CE_RXOVER & error) InBufferOverflows++;
  711. if (CE_RXPARITY & error)ParityErrors++;
  712. if (CE_TXFULL & error) OutBufferOverflows++;
  713. bytes_to_read = 0;
  714. }else{
  715. bytes_to_read = min(status.cbInQue, SIZE_OF_WINDOWS_SERIAL_BUFFER);
  716. }
  717. }
  718. if (!bytes_to_read) bytes_to_read++;
  719. /*
  720. **
  721. ** Start reading bytes
  722. **
  723. */
  724. do{
  725. /*
  726. ** Try a read operation
  727. */
  728. bytes_read = 0;
  729. read_result = ReadFile(PortHandle ,TempSerialBuffer ,bytes_to_read ,&bytes_read, &ReadOverlap);
  730. if (!read_result){
  731. /*
  732. ** Read failed
  733. */
  734. if (GetLastError() == ERROR_IO_PENDING){
  735. /*
  736. ** But it threaded in the background OK so flag that we must wait for it to finish
  737. */
  738. WaitingForSerialCharRead = TRUE;
  739. }
  740. }else{
  741. /*
  742. ** Read was successful - copy to our circular buffer and try reading again
  743. */
  744. if (bytes_read){
  745. for (i=0 ; i<bytes_read ; i++){
  746. *(SerialBuffer + SerialBufferWritePtr++) = TempSerialBuffer[i];
  747. SerialBufferWritePtr &= SIZE_OF_WINDOWS_SERIAL_BUFFER - 1;
  748. }
  749. total_bytes_read += bytes_read;
  750. }
  751. bytes_to_read = 1;
  752. }
  753. } while (read_result == TRUE);
  754. return ((BOOL)total_bytes_read);
  755. }
  756. /***********************************************************************************************
  757. * WMC::Read_From_Serial_Port -- retrieves chars from the internal class circular buffer which *
  758. * is filled from the windows serial buffer *
  759. * *
  760. * *
  761. * INPUT: buffer to copy to *
  762. * size of buffer *
  763. * *
  764. * OUTPUT: number of chars copied *
  765. * *
  766. * WARNINGS: None *
  767. * *
  768. * HISTORY: *
  769. * 1/10/96 2:27PM ST : Created *
  770. *=============================================================================================*/
  771. int WinModemClass::Read_From_Serial_Port (unsigned char *dest_ptr, int buffer_len)
  772. {
  773. int bytes_read;
  774. int bytes_to_copy = 0;
  775. unsigned char *original_dest = dest_ptr;
  776. /*
  777. ** Get any outstanding data from the windows serial buffer into our class' circular buffer
  778. */
  779. bytes_read = Read_Serial_Chars();
  780. if (bytes_read){
  781. /*
  782. ** Calculate how many bytes should be copied to the user buffer
  783. */
  784. bytes_to_copy = SerialBufferWritePtr - SerialBufferReadPtr;
  785. if (bytes_to_copy <0 ) bytes_to_copy += SIZE_OF_WINDOWS_SERIAL_BUFFER;
  786. if (bytes_to_copy>buffer_len) bytes_to_copy = buffer_len;
  787. /*
  788. ** Loop to copy the data from the internal class buffer to the users buffer
  789. */
  790. for (int i=0 ; i<bytes_to_copy ; i++){
  791. /*
  792. ** Call the users echo function if required
  793. */
  794. if (EchoFunction && *(SerialBuffer + SerialBufferReadPtr) !=13 ){
  795. EchoFunction(*(SerialBuffer + SerialBufferReadPtr));
  796. }
  797. *dest_ptr++ = *(SerialBuffer + SerialBufferReadPtr++);
  798. SerialBufferReadPtr &= SIZE_OF_WINDOWS_SERIAL_BUFFER-1;
  799. }
  800. }
  801. #ifdef LOG_MODEM
  802. if (bytes_read){
  803. char *outstr = new char[bytes_read+1];
  804. memcpy (outstr, original_dest, bytes_read);
  805. outstr[bytes_read] = 0;
  806. OutputDebugString (outstr);
  807. int handle;
  808. handle = open("COMMLOG.TXT",O_WRONLY | O_CREAT | O_APPEND | O_TEXT);
  809. if (handle != -1){
  810. write(handle, original_dest, bytes_read);
  811. close(handle);
  812. }
  813. }
  814. #endif //LOG_MODEM
  815. return(bytes_to_copy);
  816. }
  817. /***********************************************************************************************
  818. * WMC::Wait_For_Serial_Write -- waits for output buffer to empty *
  819. * *
  820. * *
  821. * *
  822. * INPUT: Nothing *
  823. * *
  824. * OUTPUT: Nothing *
  825. * *
  826. * WARNINGS: None *
  827. * *
  828. * HISTORY: *
  829. * 1/10/96 2:29PM ST : Created *
  830. *=============================================================================================*/
  831. void WinModemClass::Wait_For_Serial_Write()
  832. {
  833. DWORD bytes_written;
  834. BOOL overlap_result;
  835. BOOL wait_send;
  836. CountDownTimerClass timer;
  837. if (WaitingForSerialCharWrite){
  838. timer.Set(60*5);
  839. /*
  840. ** Wait until the overlapped port write is finished
  841. */
  842. do{
  843. wait_send = FALSE;
  844. overlap_result = GetOverlappedResult(PortHandle, &WriteOverlap, &bytes_written, FALSE);
  845. if (!overlap_result){
  846. if (GetLastError() == ERROR_IO_INCOMPLETE){
  847. wait_send = TRUE;
  848. }
  849. }
  850. }while(wait_send && timer.Time());
  851. WaitingForSerialCharWrite = FALSE;
  852. }
  853. ResetEvent(WriteOverlap.hEvent);
  854. }
  855. /***********************************************************************************************
  856. * WMC::Write_To_Serial_Port -- writes data to the serial port *
  857. * *
  858. * *
  859. * *
  860. * INPUT: ptr to data *
  861. * bytes to write *
  862. * *
  863. * OUTPUT: Nothing *
  864. * *
  865. * WARNINGS: None *
  866. * *
  867. * HISTORY: *
  868. * 1/10/96 2:29PM ST : Created *
  869. *=============================================================================================*/
  870. void WinModemClass::Write_To_Serial_Port (unsigned char *buffer, int length)
  871. {
  872. DWORD bytes_written;
  873. BOOL write_result;
  874. #ifdef LOG_MODEM
  875. if (length){
  876. char *outstr = new char[length+1];
  877. memcpy (outstr, buffer, length);
  878. outstr[length] = 0;
  879. OutputDebugString (outstr);
  880. int handle;
  881. handle = open("COMMLOG.TXT",O_WRONLY | O_CREAT | O_APPEND | O_TEXT);
  882. if (handle != -1){
  883. write(handle, buffer, length);
  884. close(handle);
  885. }
  886. }
  887. #endif //LOG_MODEM
  888. /*
  889. ** Wait for the end of the last write operation
  890. */
  891. Wait_For_Serial_Write();
  892. /*
  893. ** Write the data to the port
  894. */
  895. write_result = WriteFile (PortHandle, buffer, length, &bytes_written, &WriteOverlap);
  896. if (!write_result){
  897. if (GetLastError() == ERROR_IO_PENDING){
  898. WaitingForSerialCharWrite = TRUE;
  899. }
  900. }
  901. }
  902. /***********************************************************************************************
  903. * WMC::Get_Modem_Result -- gets the result code from the modem after issuing an 'AT' command *
  904. * *
  905. * *
  906. * *
  907. * INPUT: delay for result time-out *
  908. * ptr to buffer to receive modem result *
  909. * length of buffer *
  910. * *
  911. * OUTPUT: un-elapsed delay *
  912. * *
  913. * WARNINGS: None *
  914. * *
  915. * HISTORY: *
  916. * 1/10/96 2:30PM ST : Created *
  917. *=============================================================================================*/
  918. extern void CCDebugString (char*);
  919. int WinModemClass::Get_Modem_Result(int delay, char *buffer, int buffer_len)
  920. {
  921. CountDownTimerClass timer;
  922. int dest_ptr;
  923. char *cr_ptr;
  924. char *lf_ptr;
  925. int copy_bytes;
  926. //OutputDebugString ("Wincomm - In Get_Modem_Result\n");
  927. char abuffer [128];
  928. sprintf (abuffer, "Wincomm - delay = %d, buffer = %p, buffer_len = %d.\n", delay, buffer, buffer_len);
  929. //OutputDebugString (abuffer);
  930. //OutputDebugString ("Wincomm - About to clear input buffer.\n");
  931. memset(buffer, 0 ,buffer_len);
  932. dest_ptr = 0;
  933. /*
  934. ** Loop to parse data from the modem and discard any echoed 'AT' commands or spurious LF
  935. ** and CR characters.
  936. **
  937. */
  938. //OutputDebugString ("Wincomm - Entering do loop.\n");
  939. do{
  940. cr_ptr = NULL; //Set the result pointer to NULL
  941. //OutputDebugString ("Wincomm - About to set timer.\n");
  942. timer.Set(delay/16); //Set and start the timer
  943. /*
  944. ** Keep reading from the serial port until...
  945. ** 1. we time out
  946. ** 2. the user abort by pressing ESC
  947. ** 3. the supplied buffer fills up
  948. ** 4. there is an app switch
  949. ** or 5. we get a CR character from the modem
  950. */
  951. //OutputDebugString ("Wincomm - About to enter inner do loop.\n");
  952. do{
  953. if (AbortFunction){// &&
  954. //_Kbd->Check()) {
  955. //OutputDebugString ("Wincomm - About to call abort function.\n");
  956. int abort = AbortFunction();
  957. sprintf (abuffer ,"Wincomm - About function returned %d.\n", abort);
  958. //OutputDebugString (abuffer);
  959. if (abort != COMMSUCCESS) return (abort);
  960. }
  961. /*
  962. ** If we had lost focus then abort
  963. */
  964. if (AllSurfaces.SurfacesRestored){
  965. //OutputDebugString ("Wincomm - Aborting due to loss of focus.\n");
  966. return (0);
  967. }
  968. //OutputDebugString ("Wincomm - About to call Read_From_Serial_Port.\n");
  969. dest_ptr += Read_From_Serial_Port((unsigned char*)(buffer + dest_ptr), (int)buffer_len-dest_ptr);
  970. sprintf (abuffer, "Wincomm - End of inner do loop. Time is %d.\n", timer.Time());
  971. //OutputDebugString (abuffer);
  972. } while (timer.Time() &&
  973. dest_ptr < buffer_len &&
  974. !strchr (buffer, 13) );
  975. //OutputDebugString ("Wincomm - Exited inner do loop.\n");
  976. /*
  977. ** We need to discard this result if it is just an echo of the 'AT' command we sent
  978. */
  979. cr_ptr = strstr(buffer,"AT");
  980. if (cr_ptr){
  981. if (*buffer == 'A' && *(buffer+1) == 'T' && strchr(buffer,13)){
  982. //OutputDebugString ("Wincomm - Discarding command echo.\n");
  983. cr_ptr = strchr(buffer,13);
  984. }
  985. }
  986. /*
  987. ** If it wasnt an AT echo then strip off any leading CR/LF characters
  988. */
  989. if (!cr_ptr && (*buffer==13 || *buffer==10)){
  990. cr_ptr = strchr(buffer,13);
  991. lf_ptr = strchr(buffer,10);
  992. if (!cr_ptr || (lf_ptr && lf_ptr < cr_ptr)){
  993. //OutputDebugString ("Wincomm - Stripping CR/LF.\n");
  994. cr_ptr = strchr(buffer,10);
  995. }
  996. }
  997. /*
  998. ** Copy the good stuff at the end of the buffer over the 'AT' or CR/LF chars
  999. */
  1000. if (cr_ptr){
  1001. //OutputDebugString ("Wincomm - Copying over start of buffer.\n");
  1002. while(*cr_ptr == 13 || *cr_ptr == 10){
  1003. cr_ptr++;
  1004. }
  1005. if (cr_ptr != buffer){
  1006. copy_bytes = (int)cr_ptr - (int)buffer;
  1007. memcpy(buffer, cr_ptr, buffer_len - copy_bytes);
  1008. dest_ptr -= copy_bytes;
  1009. }
  1010. }
  1011. //OutputDebugString ("Wincomm - End of outer do loop.\n");
  1012. }while(cr_ptr);
  1013. /*
  1014. ** Terminate the string at the first CR character as this is what Greenleaf does
  1015. */
  1016. if (strchr(buffer, 13)){
  1017. //OutputDebugString ("Truncating result string.\n");
  1018. *(strchr(buffer, 13)) = 0;
  1019. }
  1020. //sprintf (abuffer, "Wincomm - returning remaining delay of %d.\n", timer.Time());
  1021. //OutputDebugString (abuffer);
  1022. return (timer.Time());
  1023. }
  1024. /***********************************************************************************************
  1025. * WMC::Dial_Modem -- issue an 'ATD' command to the modem *
  1026. * *
  1027. * *
  1028. * *
  1029. * INPUT: string - number to dial *
  1030. * *
  1031. * OUTPUT: Nothing *
  1032. * *
  1033. * WARNINGS: Use Set_Modem_Dial_Type to choose pulse or tone dialling *
  1034. * *
  1035. * HISTORY: *
  1036. * 1/10/96 2:32PM ST : Created *
  1037. *=============================================================================================*/
  1038. void WinModemClass::Dial_Modem(char *dial_number)
  1039. {
  1040. char dial_string[80];
  1041. /*
  1042. ** Create the dial command to send to the modem
  1043. */
  1044. strcpy (dial_string, "ATD");
  1045. if (DialingMethod == WC_TOUCH_TONE){
  1046. strcat(dial_string, "T");
  1047. }else{
  1048. strcat(dial_string, "P");
  1049. }
  1050. /*
  1051. ** Stick a carriage return on the end
  1052. */
  1053. strcat (dial_string, dial_number);
  1054. strcat (dial_string, "\r");
  1055. /*
  1056. ** Write the dial command to the serial port and wait for the write to complete
  1057. */
  1058. Write_To_Serial_Port ((unsigned char*)dial_string, strlen(dial_string));
  1059. Wait_For_Serial_Write();
  1060. }
  1061. /***********************************************************************************************
  1062. * WMC::Send_Command_To_Modem -- send an 'AT' command to the modem and await a response *
  1063. * *
  1064. * *
  1065. * *
  1066. * INPUT: command string *
  1067. * terminator byte (usually "\r") *
  1068. * ptr to buffer to receive modem result code *
  1069. * length of buffer *
  1070. * timeout delay for waiting for result *
  1071. * number of times to retry the command *
  1072. * *
  1073. * OUTPUT: result code *
  1074. * *
  1075. * WARNINGS: None *
  1076. * *
  1077. * HISTORY: *
  1078. * 1/10/96 2:33PM ST : Created *
  1079. *=============================================================================================*/
  1080. int WinModemClass::Send_Command_To_Modem(char *command, char terminator, char *buffer, int buflen, int delay, int retries)
  1081. {
  1082. int times;
  1083. unsigned char tmp_string[80];
  1084. char tmp_buff[80];
  1085. char term_string[2];
  1086. int time;
  1087. /*
  1088. ** Build the terminator string
  1089. */
  1090. term_string[0] = terminator;
  1091. term_string[1] = 0;
  1092. /*
  1093. ** Create the command from the supplied command and terminator
  1094. */
  1095. strcpy((char*)tmp_string, command);
  1096. strcat((char*)tmp_string, term_string);
  1097. /*
  1098. ** Flush out any pending characters from the port
  1099. */
  1100. unsigned char nothing_buff[80];
  1101. Read_From_Serial_Port(nothing_buff,80);
  1102. Sleep (100);
  1103. Read_From_Serial_Port(nothing_buff,80);
  1104. for (times = 0 ; times<retries; times++){
  1105. /*
  1106. ** Write the command to the serial port
  1107. */
  1108. //Smart_Printf("%s",tmp_string);
  1109. Write_To_Serial_Port (tmp_string, strlen((char*)tmp_string));
  1110. Wait_For_Serial_Write();
  1111. //Delay(120);
  1112. /*
  1113. ** Wait for the result of the command from the modem
  1114. */
  1115. memset(tmp_buff, 0, 80);
  1116. time = Get_Modem_Result(delay, tmp_buff, 80);
  1117. //Smart_Printf("%s%s",tmp_buff,"\r");
  1118. /*
  1119. ** If it is a pretty standard result then just return
  1120. */
  1121. if (!strcmp(tmp_buff,"0")) return (MODEM_CMD_0);
  1122. if (strstr(tmp_buff,"OK")) return (MODEM_CMD_OK);
  1123. if (strstr(tmp_buff,"ERROR")) return (MODEM_CMD_ERROR);
  1124. /*
  1125. ** If the result was a 3 digit number then copy it to the users buffer and return OK
  1126. */
  1127. if (strlen(tmp_buff)==3){
  1128. if ( (tmp_buff[0] >= '0' && tmp_buff[0] <='9') &&
  1129. (tmp_buff[1] >= '0' && tmp_buff[1] <='9') &&
  1130. (tmp_buff[2] >= '0' && tmp_buff[2] <='9')) {
  1131. strncpy(buffer, tmp_buff, MIN(buflen, 80));
  1132. return (MODEM_CMD_OK);
  1133. }
  1134. }
  1135. /*
  1136. ** It was a non-standard(ish) result so copy it to the users buffer
  1137. */
  1138. strncpy(buffer, tmp_buff, MIN(buflen, 80));
  1139. /*
  1140. ** Spurious write for no apparent reason. Well it was there in the DOS version so...
  1141. */
  1142. Sleep (100);
  1143. Write_To_Serial_Port((unsigned char*)"\r",1);
  1144. Wait_For_Serial_Write();
  1145. Sleep (100);
  1146. }
  1147. return (ASTIMEOUT);
  1148. }
  1149. /***********************************************************************************************
  1150. * WMC::Set_Echo_Function -- set up the echo function pointer *
  1151. * *
  1152. * *
  1153. * *
  1154. * INPUT: ptr to echo function *
  1155. * *
  1156. * OUTPUT: Nothing *
  1157. * *
  1158. * WARNINGS: None *
  1159. * *
  1160. * HISTORY: *
  1161. * 1/10/96 2:35PM ST : Created *
  1162. *=============================================================================================*/
  1163. void WinModemClass::Set_Echo_Function( void ( *func )( char c) )
  1164. {
  1165. EchoFunction = func;
  1166. }
  1167. /***********************************************************************************************
  1168. * WMC::Set_Abort_Function -- set up the abort function pointer *
  1169. * *
  1170. * *
  1171. * *
  1172. * INPUT: ptr to abort function *
  1173. * *
  1174. * OUTPUT: Nothing *
  1175. * *
  1176. * WARNINGS: None *
  1177. * *
  1178. * HISTORY: *
  1179. * 1/10/96 2:35PM ST : Created *
  1180. *=============================================================================================*/
  1181. void WinModemClass::Set_Abort_Function(int (*func)(void))
  1182. {
  1183. AbortFunction = func;
  1184. }
  1185. /***********************************************************************************************
  1186. * WMC::Get_Port_Handle -- returns a handle to the communications port *
  1187. * *
  1188. * *
  1189. * *
  1190. * INPUT: Nothing *
  1191. * *
  1192. * OUTPUT: Com port handle *
  1193. * *
  1194. * WARNINGS: None *
  1195. * *
  1196. * HISTORY: *
  1197. * 5/23/96 1:25PM ST : Created *
  1198. *=============================================================================================*/
  1199. HANDLE WinModemClass::Get_Port_Handle(void)
  1200. {
  1201. return (PortHandle);
  1202. }