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