2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: comm.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
20 #define WIN32_LEAN_AND_MEAN
33 #define ASCII_XON 0x11
34 #define ASCII_XOFF 0x13
36 #define MODEM_REGISTRY_PATH "System\\CurrentControlSet\\Services\\Class\\Modem"
39 static long comm_delay_val = 0;
41 DWORD FAR PASCAL comm_thread_proc(LPSTR lpdata);
42 int FAR PASCAL comm_idle_function(COMM_OBJ *obj);
43 void comm_dump_info(COMM_OBJ *obj);
46 // ---------------------------------------------------------------------
48 int comm_get_modem_info(int modem, COMM_OBJ *obj)
55 memset(obj, 0, sizeof(COMM_OBJ));
61 obj->port = (char)(modem * -1);
66 sprintf(buf, "\\%04d", modem);
68 strcpy(path, MODEM_REGISTRY_PATH);
71 mprintf((0, "Looking for modem in HKEY_LOCAL_MACHINE\\%s\n", path));
73 err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &hKey);
75 if (err != ERROR_SUCCESS) return 0;
77 // We have a key into the modem 000x
78 // Retreive all pertinant info.
80 err = RegQueryValueEx(hKey, "Model", 0, &type, buf, &len);
81 if (err != ERROR_SUCCESS) {
86 strcpy(obj->name, buf);
89 err = RegQueryValueEx(hKey, "PortSubClass", 0, &type, buf, &len);
90 if (err != ERROR_SUCCESS) {
94 mprintf((0, "COM:%d\n", buf[0]));
99 err = RegQueryValueEx(hKey, "Reset", 0, &type, buf, &len);
100 if (err != ERROR_SUCCESS) {
105 strcpy(obj->cmd[COMM_RESET_CMD], buf);
107 // Retreive some settings stuff
108 err = RegOpenKeyEx(hKey, "Answer", 0, KEY_READ, &hSubKey);
109 if (err !=ERROR_SUCCESS) {
114 err = RegQueryValueEx(hSubKey, "1", 0, &type, buf, &len);
115 if (err != ERROR_SUCCESS) {
116 RegCloseKey(hSubKey);
120 strcpy(obj->cmd[COMM_ANSWER_CMD], buf);
121 RegCloseKey(hSubKey);
123 err = RegOpenKeyEx(hKey, "Hangup", 0, KEY_READ, &hSubKey);
124 if (err !=ERROR_SUCCESS) {
129 err = RegQueryValueEx(hSubKey, "1", 0, &type, buf, &len);
130 if (err != ERROR_SUCCESS) {
131 RegCloseKey(hSubKey);
135 strcpy(obj->cmd[COMM_HANGUP_CMD], buf);
136 RegCloseKey(hSubKey);
138 err = RegOpenKeyEx(hKey, "Settings", 0, KEY_READ, &hSubKey);
139 if (err !=ERROR_SUCCESS) {
144 err = RegQueryValueEx(hSubKey, "DialPrefix", 0, &type, buf, &len);
145 if (err != ERROR_SUCCESS) {
146 RegCloseKey(hSubKey);
150 strcpy(obj->cmd[COMM_DIALPREF_CMD], buf);
153 err = RegQueryValueEx(hSubKey, "Tone", 0, &type, buf, &len);
154 if (err != ERROR_SUCCESS) {
155 RegCloseKey(hSubKey);
159 strcat(obj->cmd[COMM_DIALPREF_CMD], buf);
162 err = RegQueryValueEx(hSubKey, "Prefix", 0, &type, buf, &len);
163 if (err != ERROR_SUCCESS) {
164 RegCloseKey(hSubKey);
168 strcpy(obj->cmd[COMM_PREFIX_CMD], buf);
170 RegCloseKey(hSubKey);
179 // int comm_open_connection(COMM_OBJ *obj);
180 // ----------------------------------------------------------------------------
181 int comm_open_connection(COMM_OBJ *obj)
184 COMMTIMEOUTS ctimeouts;
186 sprintf(filename, "COM%d", obj->port);
188 obj->handle = CreateFile(filename,
189 GENERIC_READ | GENERIC_WRITE,
193 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
194 if (obj->handle == INVALID_HANDLE_VALUE)
197 // Modem COMport is open.
198 SetCommMask(obj->handle, EV_RXCHAR);
199 SetupComm(obj->handle, 4096, 4096);
200 PurgeComm( obj->handle,
203 PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
205 // Timeout after 10 sec.
206 ctimeouts.ReadIntervalTimeout = 0xffffffff;
207 ctimeouts.ReadTotalTimeoutMultiplier = 0;
208 ctimeouts.ReadTotalTimeoutConstant = 10000;
209 ctimeouts.WriteTotalTimeoutMultiplier = 0;
210 ctimeouts.WriteTotalTimeoutConstant = 10000;
211 SetCommTimeouts(obj->handle, &ctimeouts);
213 memset(&obj->rov, 0, sizeof(OVERLAPPED));
214 memset(&obj->wov, 0, sizeof(OVERLAPPED));
216 obj->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
217 if (obj->rov.hEvent == NULL) {
218 mprintf((0, "COMM: Unable to create read event.\n"));
219 CloseHandle(obj->handle);
222 obj->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
223 if (obj->wov.hEvent == NULL) {
224 mprintf((0, "COMM: Unable to create write event.\n"));
225 CloseHandle(obj->rov.hEvent);
226 CloseHandle(obj->handle);
230 // Setup parameters for Connection
232 obj->dcb.DCBlength = sizeof(DCB);
233 GetCommState(obj->handle, &obj->dcb);
236 obj->dcb.BaudRate = obj->baud;
237 else obj->baud = obj->dcb.BaudRate;
239 mprintf((0, "COM%d (%d) is opened.\n", obj->port, obj->baud));
241 obj->dcb.fBinary = 1;
242 obj->dcb.Parity = NOPARITY;
244 obj->dcb.XonChar = ASCII_XON;
245 obj->dcb.XoffChar = ASCII_XOFF;
246 obj->dcb.XonLim = 1024;
247 obj->dcb.XoffLim = 1024;
248 obj->dcb.EofChar = 0;
249 obj->dcb.EvtChar = 0;
250 obj->dcb.fDtrControl = DTR_CONTROL_ENABLE;// dtr=on
251 obj->dcb.fRtsControl = RTS_CONTROL_ENABLE;
253 obj->dcb.ByteSize = 8;
254 obj->dcb.StopBits = ONESTOPBIT;
255 obj->dcb.fParity = FALSE;
257 obj->dcb.fOutxDsrFlow = FALSE;
258 obj->dcb.fOutxCtsFlow = FALSE; // rts/cts off
260 // obj->dcb.fInX = obj->dcb.fOutX = 1; // Software flow control XON/XOFF
262 if (SetCommState(obj->handle, &obj->dcb) == TRUE)
265 obj->threadID = (DWORD)(-1);
268 EscapeCommFunction(obj->handle, SETDTR);
272 mprintf((1, "COMM: Unable to set CommState: (%x)\n", GetLastError()));
275 obj->threadID = (DWORD)(-1);
276 obj->connect = FALSE;
277 // CloseHandle(obj->wov.hEvent);
278 // CloseHandle(obj->rov.hEvent);
279 CloseHandle(obj->handle);
288 // int comm_close_connection(COMM_OBJ *obj);
289 // ----------------------------------------------------------------------------
290 int comm_close_connection(COMM_OBJ *obj)
292 CloseHandle(obj->wov.hEvent);
293 CloseHandle(obj->rov.hEvent);
295 SetCommMask(obj->handle, 0);
296 EscapeCommFunction(obj->handle, CLRDTR);
297 PurgeComm( obj->handle,
300 PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
301 CloseHandle(obj->handle);
303 obj->connect = FALSE;
305 mprintf((0, "COM%d closed.\n", obj->port));
310 // int comm_read_char(COMM_OBJ *obj);
311 // ----------------------------------------------------------------------------
313 #define ROTBUF_SIZE 16
315 static char rotbuf[ROTBUF_SIZE];
316 static int rotbuf_cur=0, rotbuf_tail=0;
318 int comm_read_char(COMM_OBJ *obj)
320 DWORD errflags, result;
322 DWORD length, length_to_read;
324 if (!obj->connect) return COMM_BUF_EMPTY;
326 // Do read buffer stuff
327 if (rotbuf_cur < rotbuf_tail) {
328 return (int)rotbuf[rotbuf_cur++];
331 // Now if we have a condition of cur = tail, then the buffer is empty
332 // and we have to refill it.
334 ClearCommError(obj->handle, &errflags, &comstat);
336 if (comstat.cbInQue > 0) {
337 if (comstat.cbInQue < ROTBUF_SIZE)
338 length_to_read = comstat.cbInQue;
340 length_to_read = ROTBUF_SIZE;
342 result = ReadFile(obj->handle, rotbuf, length_to_read, &length, &obj->rov);
345 if ((errflags = GetLastError()) != ERROR_IO_PENDING) {
346 mprintf((1, "CommReadChar err: %X\n", errflags));
347 ClearCommError(obj->handle, &errflags, &comstat);
350 while (!GetOverlappedResult(obj->handle, &obj->rov, &length, TRUE))
352 errflags = GetLastError();
353 if (errflags == ERROR_IO_INCOMPLETE) {
357 mprintf((1, "GetOverlappedResult error: %d.\n", errflags));
358 rotbuf_cur = rotbuf_tail;
359 return COMM_BUF_EMPTY;
366 Assert(length <= ROTBUF_SIZE);
367 rotbuf_tail = length;
368 return (int)rotbuf[rotbuf_cur++];
370 else return COMM_BUF_EMPTY;
374 // int comm_read_char_timed(COMM_OBJ *obj, int msecs);
375 // ----------------------------------------------------------------------------
376 int comm_read_char_timed(COMM_OBJ *obj, int msecs)
381 long timeout = timeGetTime() + (long)msecs;
383 ClearCommError(obj->handle, &err, &cstat);
384 while (cstat.cbInQue == 0)
386 status = comm_idle_function(obj);
387 if (!status) return -1;
388 ClearCommError(obj->handle, &err, &cstat);
389 if (timeout <= timeGetTime()) return -1;
391 return comm_read_char(obj);
395 // int comm_write_char(COMM_OBJ *obj, int ch);
396 // ----------------------------------------------------------------------------
397 int comm_write_char(COMM_OBJ *obj, int ch)
404 if (!obj->connect) return 0;
408 // mprintf((0, "%c", c));
410 if (!WriteFile(obj->handle, &c, 1, &length, &obj->wov)) {
411 if (GetLastError() == ERROR_IO_PENDING) {
412 while (!GetOverlappedResult(obj->handle, &obj->wov, &length, TRUE))
414 errflags = GetLastError();
415 if (errflags == ERROR_IO_INCOMPLETE)
418 ClearCommError(obj->handle, &errflags, &comstat);
419 mprintf((1, "Comm: Write error!\n"));
425 ClearCommError(obj->handle, &errflags, &comstat);
426 mprintf((1, "Comm: Write error!\n"));
431 //mprintf((0, "[%c]", c));
437 // int comm_get_cd(COMM_OBJ *obj);
438 // ----------------------------------------------------------------------------
439 int comm_get_cd(COMM_OBJ *obj)
443 if (!obj->connect) return 0;
445 GetCommModemStatus(obj->handle, &status);
446 if (status & MS_RLSD_ON) return 1;
451 // int comm_get_line_status(COMM_OBJ *obj);
452 // ----------------------------------------------------------------------------
453 int comm_get_line_status(COMM_OBJ *obj)
459 if (!obj->connect) return 0;
461 ClearCommError(obj->handle, &err, &comstat);
463 if (err & CE_BREAK) status |= COMM_STATUS_BREAK;
464 if (err & CE_FRAME) status |= COMM_STATUS_FRAME;
465 if (err & CE_OVERRUN) status |= COMM_STATUS_OVERRUN;
466 if (err & CE_RXPARITY) status |= COMM_STATUS_RXPARITY;
472 // void comm_clear_line_status(COMM_OBJ *obj)
473 // ----------------------------------------------------------------------------
474 void comm_clear_line_status(COMM_OBJ *obj)
480 // void comm_set_dtr(COMM_OBJ *obj, int flag);
481 // ----------------------------------------------------------------------------
482 void comm_set_dtr(COMM_OBJ *obj, int flag)
484 if (!obj->connect) return;
486 GetCommState(obj->handle, &obj->dcb);
488 if (flag == 1) obj->dcb.fDtrControl = DTR_CONTROL_ENABLE;
489 else obj->dcb.fDtrControl = DTR_CONTROL_DISABLE;
491 SetCommState(obj->handle, &obj->dcb);
495 // void comm_set_rtscts(COMM_OBJ *obj, int flag);
496 // ----------------------------------------------------------------------------
497 void comm_set_rtscts(COMM_OBJ *obj, int flag)
500 if (!obj->connect) return;
502 GetCommState(obj->handle, &obj->dcb);
505 obj->dcb.fOutxCtsFlow = TRUE; // rts/cts off
506 obj->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
509 obj->dcb.fOutxCtsFlow = FALSE; // rts/cts off
510 obj->dcb.fRtsControl = RTS_CONTROL_ENABLE;
513 SetCommState(obj->handle, &obj->dcb);
517 // int comm_modem_input_line(COMM_OBJ *obj, int msecs, char *buffer, int chars);
518 // ----------------------------------------------------------------------------
519 int comm_modem_input_line(COMM_OBJ *obj, int msecs, char *buffer, int chars)
528 timeout = timeGetTime() + msecs;
530 if (chars <= 0) return 0;
534 ch = comm_read_char(obj);
537 // mprintf((0, "\n"));
540 if (ch == '\n') continue;
541 buffer[i++] = (char)ch;
543 if (chars == 0) break;
545 else if (ch == COMM_BUF_EMPTY) {
553 if (timeout <= timeGetTime()) break;
557 if (retval < 0) return retval;
559 retval = timeout - timeGetTime();
560 if (retval < 0) retval = 0;
565 // void comm_set_delay(COMM_OBJ *obj, int msecs)
566 // ----------------------------------------------------------------------------
567 void comm_set_delay(COMM_OBJ *obj, int msecs)
569 comm_delay_val = (long)msecs;
573 // void comm_wait(COMM_OBJ *obj, int msecs)
574 // ----------------------------------------------------------------------------
575 int comm_wait(COMM_OBJ *obj, int msecs)
579 delaytime = timeGetTime() + (long)msecs;
581 while (timeGetTime() < delaytime) {
582 if (!comm_idle_function(obj)) {
583 mprintf((1, "Comm_wait: THIS IS NOT GOOD!!\n"));
591 // int comm_modem_send_string(COMM_OBJ *obj, char *str);
592 // ----------------------------------------------------------------------------
593 int comm_modem_send_string(COMM_OBJ *obj, char *str)
599 mprintf((0, "Commodem: send %s\n", str));
600 retval = comm_modem_send_string_nowait(obj, str, -2);
601 if (!retval) return 0;
603 if (comm_delay_val > 0) {
604 if (!comm_wait(obj, comm_delay_val)) return 0;
607 // Checking for OK response
608 curtime = comm_delay_val;
611 curtime = comm_modem_input_line(obj, curtime, buf, 64);
613 mprintf((1, "CommSendString: Didn't get an OK!\n"));
616 if (strcmp("OK", buf) == 0) {
617 return comm_wait(obj, 500);
624 // int comm_modem_send_string_nowait(COMM_OBJ *obj, char *str, int term);
625 // ----------------------------------------------------------------------------
626 int comm_modem_send_string_nowait(COMM_OBJ *obj, char *str, int term)
630 if (term < -2 || term > 255) return 0;
632 // mprintf((0, "<%s", str));
633 for (i= 0; i < lstrlen(str); i++)
634 comm_write_char(obj, str[i]);
636 //@@ if (!WriteFile(obj->handle, &str, lstrlen(str), &length, &obj->wov)) {
637 //@@ if (GetLastError() == ERROR_IO_PENDING) {
638 //@@ mprintf((0,"Comm: SendStringNoWait IO pending...\n"));
639 //@@ while (!GetOverlappedResult(obj->handle, &obj->wov, &length, TRUE))
641 //@@ errflags = GetLastError();
642 //@@ if (errflags == ERROR_IO_INCOMPLETE)
645 //@@ ClearCommError(obj->handle, &errflags, &comstat);
646 //@@ mprintf((1, "Comm: SendStringNoWait error!\n"));
652 //@@ ClearCommError(obj->handle, &errflags, &comstat);
653 //@@ mprintf((1, "Comm: SendStringNoWait error!\n"));
659 comm_write_char(obj, term);
660 else if (term == -2) {
661 comm_write_char(obj, '\r');
662 comm_write_char(obj, '\n');
669 // int comm_modem_reset(COMM_OBJ *obj);
670 // ----------------------------------------------------------------------------
671 int comm_modem_reset(COMM_OBJ *obj)
673 return comm_modem_send_string(obj, obj->cmd[COMM_RESET_CMD]);
677 // int comm_modem_dial(COMM_OBJ *obj, char *phonenum);
678 // ----------------------------------------------------------------------------
679 int comm_modem_dial(COMM_OBJ *obj, char *phonenum)
683 strcpy(str, obj->cmd[COMM_PREFIX_CMD]);
684 strcat(str, obj->cmd[COMM_DIALPREF_CMD]);
685 strcat(str, phonenum);
686 return comm_modem_send_string_nowait(obj, str, '\r');
690 // int comm_modem_answer(COMM_OBJ *obj);
691 // ----------------------------------------------------------------------------
692 int comm_modem_answer(COMM_OBJ *obj)
694 return comm_modem_send_string_nowait(obj, obj->cmd[COMM_ANSWER_CMD], '\r');
699 //@@ DWORD FAR PASCAL comm_thread_proc (LPSTR lpData);
700 //@@ -------------------------------------------------------------------------
701 //@@DWORD FAR PASCAL comm_thread_proc (LPSTR lpData)
703 //@@ DWORD event_mask;
705 //@@ COMM_OBJ *obj = (COMM_OBJ *)lpData;
707 //@@ memset(&os, 0, sizeof(OVERLAPPED));
708 //@@ os.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
709 //@@ if (os.hEvent == NULL) {
710 //@@ mprintf((1, "CommThread: unable to create event!\n"));
714 //@@ if (!SetCommMask(obj->handle, EV_RXCHAR)) return FALSE;
716 //@@ while (obj->connected)
719 //@@ WaitCommEvent(obj->handle, &event_mask, NULL);
720 //@@ if ((event_mask & EV_RXCHAR) == EV_RXCHAR) {
726 // int FAR PASCAL comm_idle_function(COMM_OBJ *obj);
727 // ----------------------------------------------------------------------------
728 int FAR PASCAL comm_idle_function(COMM_OBJ *obj)
732 while (PeekMessage(&msg, 0,0,0, PM_REMOVE)) {
733 TranslateMessage(&msg);
734 DispatchMessage(&msg);
742 // ----------------------------------------------------------------------------
743 void comm_dump_info(COMM_OBJ *obj)
747 switch (obj->dcb.BaudRate)
749 case CBR_9600: baud = 9600; break;
750 case CBR_14400: baud = 14400; break;
751 case CBR_19200: baud = 19200; break;
752 case CBR_38400: baud = 38400; break;
753 case CBR_57600: baud = 57600; break;
757 mprintf((0, "CommObj %x:\n", obj->handle));
758 mprintf((0, "\tConnect: %d\n\tDevice: %s\n", obj->connect, obj->name));
759 mprintf((0, "\tPort: COM%d\n", obj->port));
760 mprintf((0, "\tBaud: %d\n\tDTR:[%d] RTS/CTS:[%d|%d]\n", baud, obj->dcb.fDtrControl,obj->dcb.fRtsControl,obj->dcb.fOutxCtsFlow));
761 mprintf((0, "\tXON/XOFF [In|Out]:[%d|%d] XON/OFF thresh:[%d|%d]\n", obj->dcb.fInX, obj->dcb.fOutX, obj->dcb.XonLim, obj->dcb.XoffLim));