home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 2 / goldfish_vol2_cd1.bin / files / comm / misc / cyberpager / source / dialer / serial.c < prev    next >
C/C++ Source or Header  |  1994-10-05  |  13KB  |  627 lines

  1. #include "/include/memory.h"
  2.  
  3. #include "dialer.h"
  4.  
  5.  /*
  6.   * note that you probably don't want to have both debug's turned on at the
  7.   * same time...
  8.   */
  9.  
  10. /* #define DEBUG_WRITES */
  11. /* #define DEBUG_READS */
  12.  
  13.  /* storage for various magic items */
  14.  
  15. static struct IOExtSer SerialRead;
  16. static struct IOExtSer SerialWrite;
  17. static struct MsgPort *SReadPort;
  18. static struct MsgPort *SWritePort;
  19. static ULONG SReadSigMask;
  20. static ULONG SWriteSigMask;
  21. static BOOL SerialUp = FALSE;
  22.  
  23. static UBYTE SReadBuf[256];
  24. static ULONG SReadPos;
  25. static ULONG SReadSize;
  26.  
  27. static UBYTE SWriteBuf[256];
  28. static ULONG SWritePos;
  29.  
  30. /* hold some magic info */
  31.  
  32. static struct MsgPort *TimerPort;
  33. struct timerequest TimerIO;
  34. ULONG TimerSigMask;
  35. BOOL TimerUp = FALSE;
  36.  
  37. /* open up the timer for use */
  38.  
  39. static BOOL OpenTimer(void)
  40. {
  41.     if (!(TimerPort = CreatePort(NULL, 0)))
  42.         return FALSE;
  43.  
  44.     TimerSigMask = 1L << TimerPort->mp_SigBit;
  45.  
  46.     if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)&TimerIO, 0)) {
  47.         DeletePort(TimerPort);
  48.         return FALSE;
  49.     }
  50.  
  51.     TimerIO.tr_node.io_Message.mn_ReplyPort = TimerPort;
  52.  
  53.     TimerUp = TRUE;
  54.  
  55.     return TRUE;
  56. }
  57.  
  58.  /* shut down our timer handling stuff */
  59.  
  60. static void CloseTimer(void)
  61. {
  62.     if (TimerUp) {
  63.         CloseDevice((struct IORequest *)&TimerIO);
  64.         DeletePort(TimerPort);
  65.         TimerUp = FALSE;
  66.     }
  67. }
  68.  
  69. typedef struct {
  70.     STRPTR mi_Device;
  71.     ULONG mi_Unit;
  72.     ULONG mi_MaxBaud;
  73.     BOOL mi_MatchDTE;
  74.     BOOL mi_CTSRTS;
  75.     UBYTE mi_ModemInit[1];
  76. }
  77. ModemInfo_t;
  78.  
  79. ModemInfo_t *openedMi = NULL;
  80.  
  81. ULONG currentBaud;
  82. BOOL use8N1;
  83.  
  84.  /* try and OpenDevice() and set the appropriate serial parameters */
  85.  
  86. static BOOL InitSer(ModemInfo_t * mi)
  87. {
  88.     register struct IOExtSer *ior = &SerialRead;
  89.     register struct IOExtSer *iow = &SerialWrite;
  90.  
  91.     /* try and open the device */
  92.     ior->io_SerFlags = 0;
  93.     if (mi->mi_CTSRTS)
  94.         ior->io_SerFlags |= SERF_7WIRE;
  95.     else
  96.         ior->io_SerFlags &= ~SERF_7WIRE;
  97.  
  98.     ior->IOSer.io_Message.mn_ReplyPort = SReadPort;
  99.  
  100.     if (OpenDevice(openedMi->mi_Device, openedMi->mi_Unit, (struct IORequest *)ior, 0)) {
  101.         return FALSE;
  102.     }
  103.  
  104.     ior->IOSer.io_Command = SDCMD_QUERY;
  105.     DoIO((struct IORequest *)ior);
  106.  
  107.     /*
  108.      * supposedly you are only allowed to set SERF_7WIRE before you open
  109.      * the device.  However, it seems that the oldser.device used by the
  110.      * A2232 is screwing this up.  So we reset it after out open device
  111.      * call just in case.
  112.      */
  113.  
  114.     if (mi->mi_CTSRTS)
  115.         ior->io_SerFlags |= SERF_7WIRE;
  116.     else
  117.         ior->io_SerFlags &= ~SERF_7WIRE;
  118.  
  119.     ior->io_Baud = currentBaud;
  120.     ior->io_StopBits = 1;
  121.     ior->io_RBufLen = 1024;
  122.  
  123.     if (use8N1) {
  124.         ior->io_ReadLen = ior->io_WriteLen = 8;
  125.         ior->io_SerFlags &= ~(SERF_PARTY_ODD | SERF_PARTY_ON | SERF_XDISABLED);    /* insure no parity is
  126.                                              * in use */
  127.     }
  128.     else {
  129.         ior->io_ReadLen = ior->io_WriteLen = 7;
  130.         ior->io_SerFlags &= ~(SERF_PARTY_ODD | SERF_XDISABLED);
  131.         ior->io_SerFlags |= SERF_PARTY_ON;
  132.         ior->io_ExtFlags &= ~SEXTF_MSPON;
  133.     };
  134.  
  135.     ior->IOSer.io_Command = SDCMD_SETPARAMS;
  136.     if (DoIO((struct IORequest *)ior)) {
  137.         CloseDevice((struct IORequest *)&SerialRead);
  138.         return FALSE;
  139.     }
  140.  
  141.     CopyMem((APTR)ior, (APTR)iow, sizeof(struct IOExtSer));
  142.  
  143.     iow->IOSer.io_Message.mn_ReplyPort = SWritePort;
  144.  
  145.     SReadPos = SReadSize = 0;
  146.  
  147.     SerialUp = TRUE;
  148.  
  149.     return TRUE;
  150. }
  151.  
  152.  /* open up the serial device */
  153.  
  154. static BOOL OpenSerial(ModemInfo_t * mi, BOOL AttemptMode)
  155. {
  156.     STRPTR ODUresult;
  157.  
  158.     /* save these away for when we need to close the device */
  159.  
  160.     openedMi = mi;
  161.  
  162.     /* allocate our message ports */
  163.     if (!(SReadPort = CreatePort(NULL, 0))) {
  164.         openedMi = NULL;
  165.         return FALSE;
  166.     }
  167.  
  168.     if (!(SWritePort = CreatePort(NULL, 0))) {
  169.         DeletePort(SReadPort);
  170.         openedMi = NULL;
  171.         return FALSE;
  172.     }
  173.  
  174.     SReadSigMask = 1L << SReadPort->mp_SigBit;
  175.     SWriteSigMask = 1L << SWritePort->mp_SigBit;
  176.  
  177.     if (AttemptMode)
  178.         ODUresult = AttemptDevUnit(openedMi->mi_Device, openedMi->mi_Unit, PROGNAME, 0L);
  179.     else
  180.         ODUresult = LockDevUnit(openedMi->mi_Device, openedMi->mi_Unit, PROGNAME, 0L);
  181.  
  182.     if (ODUresult) {
  183.         DeletePort(SWritePort);
  184.         DeletePort(SReadPort);
  185.         openedMi = NULL;
  186.         return FALSE;
  187.     }
  188.  
  189.     currentBaud = mi->mi_MaxBaud;
  190.     use8N1 = FALSE;
  191.  
  192.     if (!InitSer(mi)) {
  193.         FreeDevUnit(openedMi->mi_Device, openedMi->mi_Unit);
  194.  
  195.         DeletePort(SWritePort);
  196.         DeletePort(SReadPort);
  197.         openedMi = NULL;
  198.         return FALSE;
  199.     }
  200.  
  201.     if (!OpenTimer()) {
  202.         CloseSerial();
  203.         return FALSE;
  204.     }
  205.  
  206.     return TRUE;
  207. }
  208.  
  209.  /* this expects that the baud rate passed in is the baud rate of the service */
  210.  
  211. void SwitchBaud(ULONG baud)
  212. {
  213.     currentBaud = baud;
  214.  
  215.     if (openedMi->mi_MatchDTE) {
  216.         if (baud > openedMi->mi_MaxBaud)
  217.             baud = openedMi->mi_MaxBaud;
  218.     }
  219.     else
  220.         baud = openedMi->mi_MaxBaud;
  221.  
  222.     SerialRead.io_Baud = baud;
  223.     SerialRead.IOSer.io_Command = SDCMD_SETPARAMS;
  224.     DoIO((struct IORequest *)&SerialRead);
  225.  
  226.     SerialWrite.io_Baud = baud;
  227.     SerialWrite.IOSer.io_Command = SDCMD_SETPARAMS;
  228.     DoIO((struct IORequest *)&SerialWrite);
  229. }
  230.  
  231. BOOL Connected(void)
  232. {
  233.     SerialRead.IOSer.io_Command = SDCMD_QUERY;
  234.     DoIO((struct IORequest *)&SerialRead);
  235.  
  236.     if (SerialRead.io_Status & (1L << 5))
  237.         return FALSE;
  238.     else
  239.         return TRUE;
  240. }
  241.  
  242. #define MODEM_TEMPLATE "DEVICE/A,UNIT/N/A,MAXBAUD/N/A,MATCHDTE/A,CTSRTS/A,INITSTRING/A"
  243. enum ModemArgs {
  244.     ARG_DEVICE,
  245.     ARG_UNIT,
  246.     ARG_BAUD,
  247.     ARG_DTE,
  248.     ARG_CTS,
  249.     ARG_INIT,
  250.     ARG_sizeof
  251. };
  252.  
  253. static ModemInfo_t *ReadModemInfo(LONG modemNumber)
  254. {
  255.     ModemInfo_t *mi = NULL;
  256.     UBYTE modemName[32];
  257.     STRPTR modemConfig;
  258.     STRPTR buffer;
  259.     struct RDArgs *ArgsPtr;
  260.     struct RDArgs *MyArgs;
  261.     STRPTR ArgArray[ARG_sizeof];
  262.  
  263.     sprintf(modemName, "MODEM%ld", modemNumber);
  264.  
  265.     if (modemNumber == 1)
  266.         modemConfig = FindPagerConfigDefault(ph, modemName, "serial.device 0 1200 y n ATZ\\r\\d\\d\\dATM0\\r\\dATD");
  267.     else
  268.         modemConfig = FindPagerConfig(ph, modemName);
  269.  
  270.     if (modemConfig) {
  271.         if (buffer = MyAllocVec(strlen(modemConfig) + 4)) {
  272.             strcpy(buffer, modemConfig);
  273.             strcat(buffer, "\n");
  274.  
  275.             if (MyArgs = (struct RDArgs *)AllocDosObject(DOS_RDARGS, TAG_DONE)) {
  276.                 MyArgs->RDA_Flags |= RDAF_NOPROMPT;
  277.                 MyArgs->RDA_Source.CS_Buffer = buffer;
  278.                 MyArgs->RDA_Source.CS_Length = strlen(buffer);
  279.                 MyArgs->RDA_Source.CS_CurChr = 0L;
  280.  
  281.                 memset((char *)ArgArray, 0, sizeof(ArgArray));
  282.                 if (ArgsPtr = ReadArgs(MODEM_TEMPLATE, (LONG *)&ArgArray, MyArgs)) {
  283.                     if (mi = (ModemInfo_t *) MyAllocVec(sizeof(ModemInfo_t) + strlen(ArgArray[ARG_DEVICE]) + strlen(ArgArray[ARG_INIT]) + 2)) {
  284.                         strcpy(mi->mi_ModemInit, ArgArray[ARG_INIT]);
  285.  
  286.                         mi->mi_Device = &mi->mi_ModemInit[strlen(mi->mi_ModemInit) + 1];
  287.                         strcpy(mi->mi_Device, ArgArray[ARG_DEVICE]);
  288.  
  289.                         mi->mi_Unit = *((LONG *)ArgArray[ARG_UNIT]);
  290.                         mi->mi_MaxBaud = *((LONG *)ArgArray[ARG_BAUD]);
  291.                         mi->mi_MatchDTE = PagerConfigYesNo(ArgArray[ARG_DTE]);
  292.                         mi->mi_CTSRTS = PagerConfigYesNo(ArgArray[ARG_CTS]);
  293.                     }
  294.                     else
  295.                         ErrorMsg("out of memory!");
  296.  
  297.                     FreeArgs(ArgsPtr);
  298.                 }
  299.                 else {
  300.                     ErrorMsg("%s config entry badly formatted.", modemName);
  301.                     ULog(ph, -1, "%s config entry badly formatted.", modemName);
  302.                 }
  303.  
  304.                 FreeDosObject(DOS_RDARGS, MyArgs);
  305.             }
  306.             else
  307.                 ErrorMsg("out of memory!");
  308.  
  309.             MyFreeVec(buffer);
  310.         }
  311.         else
  312.             ErrorMsg("out of memory!");
  313.  
  314.         FreePagerConfig(modemConfig);
  315.     }
  316.  
  317.     return mi;
  318. }
  319.  
  320. LONG OpenModem(LONG modemNumber, LONG modemStart)
  321. {
  322.     ModemInfo_t *mi;
  323.  
  324.     online = FALSE;
  325.  
  326.     if (modemNumber) {
  327.         if (mi = ReadModemInfo(modemNumber)) {
  328.             if (OpenSerial(mi, FALSE) == FALSE) {
  329.                 MyFreeVec(mi);
  330.                 return 0L;
  331.             }
  332.             else
  333.                 return modemNumber;
  334.         }
  335.     }
  336.     else {
  337.         modemNumber = modemStart;
  338.  
  339.         while (mi = ReadModemInfo(modemNumber++))
  340.             if (OpenSerial(mi, TRUE))
  341.                 return modemNumber - 1;
  342.  
  343.         return 0L;
  344.     }
  345. }
  346.  
  347.  /* close down the serial handling stuff */
  348.  
  349. void CloseSerial(void)
  350. {
  351.     CloseTimer();
  352.  
  353.     if (SerialUp) {
  354.         CloseDevice((struct IORequest *)&SerialRead);
  355.         online = SerialUp = FALSE;
  356.     }
  357.  
  358.     FreeDevUnit(openedMi->mi_Device, openedMi->mi_Unit);
  359.  
  360.     MyFreeVec(openedMi);
  361.     openedMi = NULL;
  362.  
  363.     DeletePort(SWritePort);
  364.     DeletePort(SReadPort);
  365. }
  366.  
  367.  /* hang up the modem -- we use a DTR drop to do this */
  368. BOOL HangUp(void)
  369. {
  370.     if (SerialUp) {
  371.         CloseDevice((struct IORequest *)&SerialRead);
  372.         online = SerialUp = FALSE;
  373.     }
  374.  
  375.     Delay(TICKS_PER_SECOND);
  376.  
  377.     return InitSer(openedMi);
  378. }
  379.  
  380.  /* determine if we should be using 8N1 or 7E1 */
  381. BOOL Use8N1(BOOL set8N1)
  382. {
  383.     BOOL old8N1;
  384.  
  385.     old8N1 = use8N1;
  386.  
  387.     use8N1 = set8N1;
  388.  
  389.     /*
  390.      * if they really changed the use8N1 state then we need to check to
  391.      * see if the modem is currently on-line and reset it if so.
  392.      */
  393.  
  394.     if (use8N1 != old8N1) {
  395.         if (SerialUp) {
  396.             CloseDevice((struct IORequest *)&SerialRead);
  397.             online = SerialUp = FALSE;
  398.         }
  399.  
  400.         Delay(TICKS_PER_SECOND);
  401.  
  402.         return InitSer(openedMi);
  403.     }
  404.     else
  405.         return TRUE;
  406. }
  407.  
  408.  /* flush out the serial read buffer */
  409.  
  410. void ClearSerial(void)
  411. {
  412.     SReadPos = SReadSize = 0;
  413.  
  414.     SerialRead.IOSer.io_Command = CMD_CLEAR;
  415.     DoIO((struct IORequest *)&SerialRead);
  416. }
  417.  
  418.  /* send a string to the serial device */
  419.  
  420. void SerWrite(STRPTR Buf, ULONG Len)
  421. {
  422. #ifdef DEBUG_WRITES
  423.     FWrite(Output(), Buf, 1, Len);
  424. #endif
  425.  
  426.     SerialWrite.IOSer.io_Command = CMD_WRITE;
  427.     SerialWrite.IOSer.io_Length = Len;
  428.     SerialWrite.IOSer.io_Data = (APTR)Buf;
  429.     DoIO((struct IORequest *)&SerialWrite);
  430.  
  431.     if (SerialWrite.IOSer.io_Error)
  432.         ULog(ph, -1, "serial write error %ld", SerialWrite.IOSer.io_Error);
  433. }
  434.  
  435. void SerPutChar(UBYTE value)
  436. {
  437.     UBYTE Buf[2];
  438.  
  439. #ifdef DEBUG_WRITES
  440.     FPutC(Output(), value);
  441. #endif
  442.  
  443.     Buf[0] = value;
  444.  
  445.     SerialWrite.IOSer.io_Command = CMD_WRITE;
  446.     SerialWrite.IOSer.io_Length = 1;
  447.     SerialWrite.IOSer.io_Data = (APTR)Buf;
  448.     DoIO((struct IORequest *)&SerialWrite);
  449.  
  450.     if (SerialWrite.IOSer.io_Error)
  451.         ULog(ph, -1, "serial write error %ld", SerialWrite.IOSer.io_Error);
  452. }
  453.  
  454.  /*
  455.   * wait for a specific string to be read from the device.  this is
  456.   * case-insensitive
  457.   */
  458.  
  459. BOOL SerWaitString(STRPTR target, LONG timeout)
  460. {
  461.     UWORD byteRead;
  462.     int i, len;
  463.  
  464.     len = strlen(target);
  465.     i = 0;
  466.  
  467.     while ((byteRead = SerGetRawChar(timeout)) != TIMEOUT) {
  468.         if (tolower(byteRead) == tolower(target[i])) {
  469.             if (++i == len)
  470.                 return TRUE;
  471.         }
  472.         else
  473.             i = 0;
  474.     }
  475.  
  476.     return FALSE;
  477. }
  478.  
  479.  /* get a character from the serial device with a timeout */
  480.  
  481. UWORD SerGetRawChar(LONG timeout)
  482. {
  483.     UBYTE Buffer[2];
  484.     ULONG Signals;
  485.     ULONG secs, micro;
  486.  
  487.     if (timeout < 0) {
  488.         secs = 0;
  489.         micro = -timeout;
  490.     }
  491.     else {
  492.         secs = timeout;
  493.         micro = 0;
  494.     }
  495.  
  496.     if (SReadPos < SReadSize) {
  497. #ifdef DEBUG_READS
  498.         Printf("%lc", SReadBuf[SReadPos]);
  499. #endif
  500.         return (UWORD)SReadBuf[SReadPos++];
  501.     }
  502.  
  503.     SetSignal(0L, SReadSigMask | TimerSigMask);
  504.  
  505.     SerialRead.IOSer.io_Command = CMD_READ;
  506.     SerialRead.IOSer.io_Length = 1;
  507.     SerialRead.IOSer.io_Data = (APTR)Buffer;
  508.     SendIO((struct IORequest *)&SerialRead);
  509.  
  510.     TimerIO.tr_node.io_Command = TR_ADDREQUEST;
  511.     TimerIO.tr_time.tv_secs = secs;
  512.     TimerIO.tr_time.tv_micro = micro;
  513.     SendIO((struct IORequest *)&TimerIO);
  514.  
  515.     Signals = Wait(SReadSigMask | TimerSigMask);
  516.  
  517.     if (Signals & SReadSigMask) {
  518.         if (!CheckIO((struct IORequest *)&TimerIO)) {
  519.             AbortIO((struct IORequest *)&TimerIO);
  520.         }
  521.         WaitIO((struct IORequest *)&TimerIO);
  522.  
  523.         WaitIO((struct IORequest *)&SerialRead);
  524.  
  525.         if (!SerialRead.IOSer.io_Error && SerialRead.IOSer.io_Actual) {
  526.             SerialRead.IOSer.io_Command = SDCMD_QUERY;
  527.             DoIO((struct IORequest *)&SerialRead);
  528.  
  529.             if (SerialRead.IOSer.io_Actual) {
  530.                 SerialRead.IOSer.io_Command = CMD_READ;
  531.                 SerialRead.IOSer.io_Length = min(sizeof(SReadBuf), SerialRead.IOSer.io_Actual);
  532.                 SerialRead.IOSer.io_Data = (APTR)SReadBuf;
  533.                 DoIO((struct IORequest *)&SerialRead);
  534.  
  535.                 if (!SerialRead.IOSer.io_Error) {
  536.                     SReadPos = 0;
  537.                     SReadSize = SerialRead.IOSer.io_Actual;
  538.                 }
  539.             }
  540.  
  541. #ifdef DEBUG_READS
  542.             Printf("%lc", Buffer[0]);
  543. #endif
  544.             return (UWORD)Buffer[0];
  545.         }
  546.         else
  547.             return 0;
  548.     }
  549.  
  550.     if (Signals & TimerSigMask)
  551.         WaitIO((struct IORequest *)&TimerIO);
  552.  
  553.     /* if we get down here we have timed out waiting for a character */
  554.  
  555.     if (!CheckIO((struct IORequest *)&SerialRead)) {
  556.         AbortIO((struct IORequest *)&SerialRead);
  557.     }
  558.     WaitIO((struct IORequest *)&SerialRead);
  559.  
  560.     return TIMEOUT;
  561. }
  562.  
  563. BOOL InitModem(void)
  564. {
  565.     STRPTR ptr;
  566.     UWORD c;
  567.     BOOL validEscape;
  568.  
  569. #define MAX_AT_RETRIES (3)
  570.  
  571.     /* try to get the modem's attention. */
  572.     for (c = 0; c < MAX_AT_RETRIES; c++) {
  573.         SerWrite("AT\r", 3);
  574.         if (SerWaitString("OK\r\n", 6))
  575.             break;
  576.     }
  577.  
  578.     if (c == MAX_AT_RETRIES) {
  579.         ErrorMsg("modem %ld not responding.", openedModem);
  580.         ULog(ph, -1, "modem %ld not responding.", openedModem);
  581.         return FALSE;
  582.     }
  583.  
  584.     Delay(TICKS_PER_SECOND);
  585.  
  586.     ClearSerial();
  587.  
  588.     /* now start sending the init string out */
  589.  
  590.     ptr = openedMi->mi_ModemInit;
  591.  
  592.     while (c = *ptr++) {
  593.         validEscape = FALSE;
  594.  
  595.         if (c == '\\') {
  596.             validEscape = TRUE;
  597.  
  598.             switch (tolower(*ptr)) {
  599.             case 'd':
  600.                 Delay(2 * TICKS_PER_SECOND);
  601.                 c = 0xFFFF;
  602.                 break;
  603.  
  604.             case 'r':
  605.                 c = '\r';
  606.                 break;
  607.  
  608.             default:
  609.                 validEscape = FALSE;
  610.                 break;
  611.             }
  612.         }
  613.  
  614.         if (c != 0xFFFF)
  615.             SerPutChar(c);
  616.  
  617.         if (c == '\r')
  618.             while ((c = SerGetRawChar(-100)) != TIMEOUT) ;
  619.  
  620.         if (validEscape) {
  621.             ptr++;
  622.         }
  623.     }
  624.  
  625.     return TRUE;
  626. }
  627.