|
|
1.1 root 1: /*** modem.c
2: *
3: * TITLE
4: *
5: * modem.c
6: * Copyright (C) Microsoft Corporation 1987
7: * March 1987
8: *
9: * DESCRIPTION
10: *
11: * This module contains routines that support Hayes compatible modem.
12: *
13: ***/
14:
15: #include <stdio.h>
16: #include <doscalls.h>
17: #include <subcalls.h>
18: #include <malloc.h>
19: #include <string.h>
20: #include <memory.h>
21: #include <conio.h>
22: #include "term.h"
23:
24: #define min(a,b) (((a)<(b)) ? (a):(b)) /* This is pulled out of the old */
25: /* v2tov3.h (c v2.0) header file */
26:
27: extern char *ErrMsg[];
28: extern unsigned FileHndl;
29:
30: make_dial_cmd(char *, int);
31: void flush_ques(int);
32: void clr_com_error(void);
33: void com_clr_flush(void);
34:
35: static char Init[] = {'A', 'T', 'V', '0', 0x0d};
36: static char Attn[] = {'A', 'T', 0x0d};
37: static char Esc[] = {'+', '+', '+'};
38: static char OnHook[] = {'A', 'T', 'H', '0', 0X0d};
39: static char OffHook[] = {'A', 'T', 'H', '1', 0x0d};
40: static char Reset[] = {'A', 'T', 'Z', 0x0d};
41:
42: struct s_Cmd{
43: char *pCmd;
44: int CmdLen;
45: } Cmds[] = {
46: {Init, sizeof(Init)}, /* Initialize modem */
47: {Attn, sizeof(Attn)}, /* Attention cmd */
48: {Esc, sizeof(Esc)}, /* Modem escape sequence*/
49: {OnHook, sizeof(OnHook)}, /* Put phone on hook */
50: {OffHook, sizeof(OffHook)}, /* Take phone off hook */
51: {Reset, sizeof(Reset)} /* Reset command */
52: };
53:
54:
55:
56: /*** make_modem_conn - make modem connection
57: *
58: * This routine tries to setup the modem connection, retrying if
59: * appropriate.
60: *
61: * make_modem_conn()
62: *
63: * ENTRY
64: *
65: * EXIT
66: * TRUE if modem connection was made
67: * FALSE if modem connection did not go through
68: *
69: * WARNING
70: *
71: * EFFECTS
72: *
73: ***/
74:
75: make_modem_conn()
76: {
77: unsigned NumBytes, /* number of bytes to be written */
78: RetCode, /* return code from system calls */
79: Result = FALSE; /* to be returned by this routine */
80: char OutBuffer,
81: ModemRetry = TRUE, /* retry for modem connection */
82: NumRetries = 0; /* no. times connection retried */
83:
84: printf("trying modem connection...\n");
85:
86: while (ModemRetry)
87: switch (setup_modem_conn()) {
88: case MS_CONNECT :
89: case MS_CONNECT1200:
90: Result = TRUE;
91: ModemRetry = FALSE;
92: OutBuffer = '\r';
93: if ((RetCode = DOSWRITE(FileHndl, &OutBuffer, 1,
94: &NumBytes)) != 0)
95: error(ERR_DOSWRITE, RetCode);
96: break;
97: case MS_NOCARRIER :
98: case MS_NODIALTONE :
99: if (++NumRetries > NUM_RETRY) {
100: printf("modem connection failed\n");
101: ModemRetry = FALSE;
102: }
103: else
104: printf("modem connection failed; retrying...\n");
105: break;
106: case MS_NOREPLY :
107: case MS_ERROR :
108: case OT_FAILURE : /* OTher failure */
109: case MS_BUSY :
110: default :
111: ModemRetry = FALSE;
112: printf("modem connection failed\n");
113: break;
114: } /* switch (setup_modem_conn()) */
115:
116: return(Result);
117:
118: }
119:
120:
121:
122:
123: /*** setup_modem_conn - setup modem connection
124: *
125: * This is the helper routine for the make_modem_conn(). It initialises
126: * the modem connection and sends out the dial command to the modem.
127: *
128: * setup_modem_conn()
129: *
130: * ENTRY
131: *
132: * EXIT
133: * returns one of the following: MS_CONNECT MS_CONNECT1200
134: * MS_NOCARRIER MS_NODIALTONE MS_NOREPLY MS_ERROR MS_BUSY
135: * OT_FAILURE
136: *
137: * WARNING
138: *
139: * EFFECTS
140: *
141: ***/
142:
143: int setup_modem_conn()
144: {
145: int Result = OT_FAILURE;
146:
147: /* initialise modem connection */
148: if (!(send_modem_cmd(MC_INIT)))
149: return(Result);
150: if (get_modem_reply() != MS_OK)
151: return(Result);
152: DOSSLEEP((long) 100);
153:
154: /* write AT string to the modem. This will cause the modem to
155: * determine the communications rate of the terminal as well
156: * as its parity setting.
157: */
158: if (!(send_modem_cmd(MC_ATTN)))
159: return(Result);
160: if (get_modem_reply() != MS_OK)
161: return(Result);
162: DOSSLEEP((long) 100);
163:
164: /* send DIAL command to the modem */
165: if (!(send_modem_cmd(MC_DIAL)))
166: return(Result);
167:
168: return(get_modem_reply());
169: };
170:
171:
172:
173:
174: /*** send_modem_cmd - send a command to modem
175: *
176: * This routine sends a command to the modem and ensures that the echo
177: * from the modem matches the input command.
178: *
179: * send_modem_cmd(CmdType)
180: *
181: * ENTRY
182: * CmdType - type of modem command: MC_INIT MC_ATTN MC_ESC
183: * MC_ONHOOK MC_OFFHOOK MC_RESET MC_DIAL
184: *
185: * EXIT
186: * TRUE if command was sent succesfully
187: * FALSE if command failed
188: *
189: * WARNING
190: *
191: * EFFECTS
192: *
193: ***/
194:
195: send_modem_cmd(CmdType)
196: int CmdType; /* The command to send */
197: {
198: int Result = TRUE,
199: ReadCnt,
200: WriteCnt,
201: CmdLen,
202: RetCode;
203: char Buf[80],
204: Cmd[80],
205: *pDst,
206: *pCmd;
207:
208:
209: /* clear COM error and flush transmit/receive queues */
210: com_clr_flush();
211:
212: if (CmdType == MC_INIT) {
213: send_modem_cmd(MC_RESET); /* modem command: ATZ */
214: /* clear COM error and flush transmit/receive queues */
215: com_clr_flush();
216: };
217:
218: /* set pCmd -> command string; CmdLen = length of command string */
219: if (CmdType == MC_DIAL) {
220: CmdLen = make_dial_cmd(Cmd, sizeof(Cmd));
221: pCmd = Cmd;
222: }
223: else {
224: pCmd = Cmds[CmdType].pCmd;
225: CmdLen = Cmds[CmdType].CmdLen;
226: };
227:
228: /* write the command out to the modem */
229: if (((RetCode = DOSWRITE(FileHndl, pCmd, CmdLen, &WriteCnt)) != 0)
230: || (WriteCnt != CmdLen))
231: return(FALSE);
232:
233: /* wait for the echo & wait for the command to clear */
234: DOSSLEEP((long) 250);
235: if (CmdType == MC_DIAL || CmdType == MC_RESET)
236: DOSSLEEP((long) 750);
237:
238: /* read back the echo from the modem & check if it matches the input */
239: RetCode =
240: DOSREAD(FileHndl, Buf, min(WriteCnt, sizeof(Buf)), &ReadCnt);
241: if ((RetCode != 0) || (ReadCnt != WriteCnt))
242: Result = FALSE;
243: else {
244: pDst = Buf;
245: while (--ReadCnt >= 0) {
246: if (*pDst++ != *pCmd++) {
247: printf("send_modem_cmd: error in echo of modem input\n");
248: Result = FALSE;
249: break;
250: }
251: } /* while (--ReadCnt >= 0) */
252: }
253:
254: return(Result);
255: }
256:
257:
258:
259:
260: /*** make_dial_cmd - create a modem command for dialing
261: *
262: * builds the dial command string and returns its length in bytes
263: *
264: * make_dial_cmd(pBuf, BufLen)
265: *
266: * ENTRY
267: * pBuf - ptr to buffer
268: * BufLen - length of buffer in bytes
269: *
270: * EXIT
271: * pBuf -> dial command string
272: * make_dial_cmd = length of dial command string in bytes
273: *
274: * WARNING
275: *
276: * EFFECTS
277: *
278: ***/
279:
280: make_dial_cmd(pBuf, BufLen)
281: char *pBuf;
282: int BufLen;
283: {
284: char *pSrc,
285: *pDst,
286: Ch,
287: Cmd[80], /* allocate a huge command buffer */
288: *bin_to_dec();
289: int Len;
290: structModemOptions sModemOptions; /* modem options */
291:
292: get_modem_options(&sModemOptions);
293: pDst = Cmd;
294: *pDst++ = 'A'; /* get Modem's attention */
295: *pDst++ = 'T';
296: *pDst++ = 'S'; /* set R6 for wait for dial tone */
297: *pDst++ = '6';
298: *pDst++ = '=';
299: pDst = bin_to_dec(pDst, sModemOptions.iWaitTone);
300: *pDst++ = B_PAUSE;
301: *pDst++ = 'S'; /* set R7 for wait for carrier time */
302: *pDst++ = '7';
303: *pDst++ = '=';
304: pDst = bin_to_dec(pDst, sModemOptions.iWaitCarrier);
305: *pDst++ = B_PAUSE;
306: *pDst++ = 'D';
307: *pDst++ = (sModemOptions.chDialType == PULSE) ? 'P' : 'T';
308: pSrc = sModemOptions.pPhoneNumber;
309: while (Ch = *pSrc++)
310: if ((Ch >= '0' && Ch <= '9') || (Ch == ','))
311: *pDst++ = Ch;
312: *pDst++ = 0x0d;
313: *pDst = 0;
314:
315: /* copy the command string into caller's buffer */
316: pSrc = Cmd;
317: pDst = pBuf;
318: for (Len = 0; Len <= BufLen; ++Len)
319: if (*pSrc==0)
320: break;
321: else
322: *pDst++ = *pSrc++;
323: return(Len);
324: }
325:
326:
327:
328:
329: /*** bin_to_dec - convert a binary number to ASCII decimal
330: *
331: * bin_to_dec(pDst, i)
332: *
333: * ENTRY
334: * pDst -> buffer to place the ASCII decimal
335: * i = integer to be converted to ASCII decimal
336: *
337: * EXIT
338: * ASCII decimal placed in the buffer pointed by pDst
339: * bin_to_dec -> byte next to ASCII decimal in the buffer
340: *
341: * WARNING
342: *
343: * EFFECTS
344: *
345: ***/
346:
347: char *bin_to_dec(pDst, i)
348: char *pDst;
349: int i;
350: {
351: if (i > 10)
352: pDst = bin_to_dec (pDst, i/10);
353: *pDst++ = '0' + (i % 10);
354: return(pDst);
355: }
356:
357:
358:
359:
360: /*** get_modem_reply - get reply from modem
361: *
362: * get_modem_reply()
363: *
364: * ENTRY
365: *
366: * EXIT
367: * get_modem_reply = MS_CONNECT MS_CONNECT1200 MS_NOCARRIER
368: * MS_NODIALTONE MS_NOREPLY MS_ERROR MS_BUSY
369: *
370: * WARNING
371: *
372: * EFFECTS
373: *
374: ***/
375:
376: int get_modem_reply()
377: {
378: char Ch;
379: int Cnt,
380: Result,
381: RetCode;
382:
383: do /* skip CR, LF and get resultcode */
384: if ((RetCode = DOSREAD(FileHndl, &Ch, 1, &Cnt)) != 0)
385: Error(ERR_DOSREAD, RetCode);
386: while ((Cnt == 1) && ((Ch == 0x0d) || (Ch == 0x0a)));
387:
388: switch(Cnt) {
389: case 0: Result = MS_NOREPLY;
390: break;
391: case 1: if ((Ch >= '0') && (Ch <= '7'))
392: Result = Ch - '0';
393: else
394: Result = MS_ERROR;
395: break;
396: default: Result = MS_ERROR;
397: break;
398: }
399:
400: return(Result);
401: }
402:
403:
404:
405:
406: /*** discon_modem - disconnect the modem
407: *
408: * discon_modem()
409: *
410: * ENTRY
411: *
412: * EXIT
413: * modem disconnected
414: *
415: * WARNING
416: *
417: * EFFECTS
418: *
419: ***/
420:
421: void discon_modem()
422: {
423: /* Wait for the last command to clear, then be quiet for 1.5 seconds */
424: DOSSLEEP((long) 1000); /* wait 1. second */
425: flush_ques(FLUSHOUTPUT); /* flush the transmit que */
426: DOSSLEEP((long) 1500); /* wait 1.5 seconds */
427:
428: send_modem_cmd(MC_ESC); /* put modem in command mode */
429: DOSSLEEP((long) 2000); /* wait 2 seconds */
430:
431: send_modem_cmd(MC_ONHOOK); /* place phone back on hook */
432: DOSSLEEP((long) 200); /* wait for command to clear*/
433: }
434:
435:
436:
437:
438: /*** com_clr_flush - clear COM error and flush transmit/receive queues
439: *
440: * com_clr_flush()
441: *
442: * ENTRY
443: *
444: * EXIT
445: * com error cleared
446: * transmit and receive queues of com port flushed out
447: *
448: * WARNING
449: *
450: * EFFECTS
451: *
452: ***/
453:
454: void com_clr_flush()
455: {
456: /* retrieve and clear the com error information */
457: clr_com_error();
458: /* flush transmit and receive queues */
459: flush_ques(FLUSHINPUT);
460: flush_ques(FLUSHOUTPUT);
461: }
462:
463:
464:
465:
466: /*** flush_ques - flush COM transmit/receive queue
467: *
468: * flush_ques(FuncId)
469: *
470: * ENTRY
471: * FuncId - set to one of: FLUSHINPUT FLUSHOUTPUT
472: *
473: * EXIT
474: * transmit or receive queue of com port flushed
475: *
476: * WARNING
477: *
478: * EFFECTS
479: *
480: ***/
481:
482: void flush_ques(FuncId)
483: int FuncId;
484: {
485: char FlushData, /* data returned by flush IOCTL function */
486: FlushParm = FLUSH_CMDINFO; /* param to flush IOCTL function */
487: int RetCode;
488:
489: /* flush transmit/receive queue */
490: if ((RetCode = DOSDEVIOCTL(&FlushData, &FlushParm,
491: FuncId, GENERIC, FileHndl)) != 0)
492: Error(ERR_IOCTLFLUSHQUE, RetCode);
493: }
494:
495:
496:
497:
498: /*** clr_com_error - retrieve and clear COM error information
499: *
500: * clr_com_error()
501: *
502: * ENTRY
503: *
504: * EXIT
505: * com error cleared
506: *
507: * WARNING
508: *
509: * EFFECTS
510: *
511: ***/
512:
513: void clr_com_error()
514:
515: {
516: int ComError,
517: RetCode;
518:
519: if ((RetCode = DOSDEVIOCTL((char *) &ComError, 0L, GETCOMERROR,
520: SERIAL, FileHndl)) != 0)
521: Error(ERR_IOCTLGETCOMERROR, RetCode);
522: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.