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