home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 340.lha / JModem_v1.0 / protsupp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-01-23  |  12.9 KB  |  475 lines

  1. /****************************************************************
  2.  * Support routines for file transfer protocol implementations. *
  3.  * The routines in this file provide easy access to the serial  *
  4.  * device with true timeouts, and simplified window management. *
  5.  * Kenneth Ã–sterberg 02-May-1989                                *
  6.  ****************************************************************/
  7.  
  8. /* Compilation with Aztec C:
  9.  * cc +B -o protsupp.o protsupp.c
  10.  */
  11.  
  12. #include <exec/types.h>
  13. #include <exec/memory.h>
  14. #include <devices/serial.h>
  15. #include <devices/timer.h>
  16. #include <graphics/rastport.h>
  17. #include <intuition/intuition.h>
  18. #include <intuition/intuitionbase.h>
  19.  
  20. #define GWID 48        /* Gadget width */
  21. #define GHGT 12        /* Gadget height */
  22.  
  23. #define WC_NONE 0      /* Window cleanup (Wcleanup()) error codes. Call */
  24. #define WC_WINDOW 1    /* with WC_NONE when you want to get rid of the */
  25. #define WC_INTUI 2     /* window */
  26.  
  27. #define SC_RDPORT 5     /* Error codes for Scleanup(). Call the routine */
  28. #define SC_RDDEV 4      /* with SC_NONE to deallocate all serial port   */
  29. #define SC_WRREQ 3      /* resources. */
  30. #define SC_WRPORT 2
  31. #define SC_WRDEV 1
  32. #define SC_NONE 0
  33.  
  34. #define TC_PORT 2       /* Error codes for Tcleanup(). Call with TC_NONE */
  35. #define TC_DEV 1        /* to deallocate timer.device resources */
  36. #define TC_NONE 0
  37.  
  38. #define GS_TIMEOUT 1    /* Error codes returned by getserdata() and */
  39. #define GS_NONE 0       /* getserchar(). GS_NONE means everything's OK */
  40.  
  41. /* Amiga library routines used by this file */
  42.  
  43. extern APTR AllocMem();
  44. extern ULONG Wait();
  45. extern struct MsgPort *CreatePort();
  46. extern int OpenDevice(), DoIO();
  47. extern void FreeMem(), DeletePort(), CloseDevice(), DeletePort();
  48. extern ULONG AbortIO(), CheckIO();
  49. extern void CloseLibrary(), CloseWindow();
  50. extern struct Window *OpenWindow();
  51. extern APTR OpenLibrary();
  52. extern void SetAPen(), Move(), Text(), ClearEOL();
  53. extern struct IntuiMessage *GetMsg();
  54.  
  55. /* Global variables */
  56.  
  57. struct IOExtSer *RR, *WR;
  58. struct timerequest *TR;
  59. struct GfxBase *GfxBase = NULL;
  60. struct IntuitionBase *IntuitionBase = NULL;
  61. struct Window *pwin = NULL;
  62.  
  63. /* The structure that SetupWindow() takes as argument */
  64.  
  65. struct windef {
  66.   UWORD Width, Height;
  67.   UWORD GXpos, GYpos;
  68.   char *Title;
  69.   char **Text;
  70. };
  71.  
  72. /* Structures to create the Abort gadget */
  73.  
  74. struct IntuiText AText = { 1, 0, JAM2, 5, 2 ,NULL, (UBYTE *)"Abort", NULL };
  75. SHORT AVectors[] = { -1,-1, GWID,-1, GWID,GHGT, -1,GHGT, -1,-1 };
  76. struct Border ABorder = { 0, 0, 1, 0, JAM2, 5, AVectors, NULL };
  77. struct Gadget AbortGadget = { NULL, 0,0, GWID,GHGT, GADGHCOMP, RELVERIFY,
  78.   BOOLGADGET, (APTR)&ABorder, NULL, &AText, 0L, NULL, 0, NULL };
  79.  
  80. /* Local routines */
  81.  
  82. int OpenUpSerial(), OpenUpTimer(), getserdata(), getserchar();
  83. int sendserdata(), sendserchar();
  84. void Scleanup(), Tcleanup();
  85. int SetupWindow(), CheckAbort();
  86. void Wcleanup(), PText();
  87.  
  88. /********************
  89.  * The code section *
  90.  ********************/
  91.  
  92. int sendserchar(ch)
  93. /* Sends a character to the serial device. Returns the error from DoIO() */
  94. register char *ch;
  95. {
  96.   return(sendserdata(ch,1L));
  97. }
  98.  
  99. int sendserdata(ch,len)
  100. /* Sends a data buffer to the serial device. Returns the error from DoIO()
  101.  * Uses external variable struct IOExtSer *WR. */
  102. register UBYTE *ch;
  103. register ULONG len;
  104. {
  105.   register struct IOExtSer *rWR = WR; /* Cache pointer in a register */
  106.  
  107.   rWR->IOSer.io_Command = CMD_WRITE;
  108.   rWR->IOSer.io_Length = len;
  109.   rWR->IOSer.io_Data = (APTR) ch;
  110.   return(DoIO(rWR));
  111. }
  112.  
  113. int getserchar(timeout,chrptr)
  114. /* Get one character from the serial port */
  115. register ULONG timeout;
  116. register UBYTE *chrptr;
  117. {
  118.   return(getserdata(timeout,chrptr,1L));
  119. }
  120.  
  121. int getserdata(timeout,chrptr,len)
  122. /* Wait for a specific number of characters to arrive at the serial port.
  123.  * The routine doesn't return until all characters have arrived, or an
  124.  * timeout occurs. Uses the external variable struct IOExtSer *RR and
  125.  * struct timerequest *TR.
  126.  * The function returns an error code (see #defines with prefixes 'GS_') */
  127.  
  128. register ULONG timeout;
  129. UBYTE *chrptr;
  130. ULONG len;
  131. {
  132.   ULONG mask;
  133.   register ULONG ReadMask, TimeMask = 0L;
  134.   register struct timerequest *rTR = TR; /* TR into register for speed */
  135.   register struct IOExtSer *rRR = RR;    /* RR into register for speed */
  136.  
  137. /* Send the request for the characters we need. Try to use quick IO */
  138.  
  139.   rRR->IOSer.io_Command = CMD_READ;
  140.   rRR->IOSer.io_Data = (APTR)chrptr;
  141.   rRR->IOSer.io_Length = len;
  142.   rRR->IOSer.io_Flags |= IOF_QUICK;
  143.   BeginIO(rRR);
  144.  
  145. /* Check if quick IO succeeded. If so, we don't have to mess with all that
  146.  * message passing, and the timer doesn't even have to get involved. */
  147.  
  148.   if (rRR->IOSer.io_Flags & IOF_QUICK) {
  149.     return(GS_NONE);
  150.   }
  151.  
  152. /* If the timeout value <> 0 then send the request to the timer device.
  153.  * If you don't need any timeout limits then simply give a timeout value
  154.  * NULL to this routine, and a timeout will never occur. */
  155.  
  156.   if (timeout) {
  157.     rTR->tr_time.tv_secs = timeout / 50;
  158.     rTR->tr_time.tv_micro = (timeout % 50L) * 20000L;
  159.     rTR->tr_node.io_Command = TR_ADDREQUEST;
  160.     SendIO(rTR);
  161.     TimeMask = 1L << rTR->tr_node.io_Message.mn_ReplyPort->mp_SigBit;
  162.   }
  163.   ReadMask = 1L << rRR->IOSer.io_Message.mn_ReplyPort->mp_SigBit;
  164.  
  165. /* Wait until the characters have been received or a timeout occurs */
  166.  
  167.   do {
  168.     mask = Wait(ReadMask|TimeMask);
  169.  
  170. /* Check if the serial device request has completed */
  171.  
  172.     if ((mask & ReadMask) && (CheckIO(rRR))) {
  173.       if (timeout)
  174.         if (!CheckIO(rTR))
  175.           AbortIO(rTR);
  176.         GetMsg(rTR->tr_node.io_Message.mn_ReplyPort);
  177.       return(GS_NONE);  /* Return with no error */
  178.     }
  179.  
  180. /* Check if the timer device request has completed */
  181.  
  182.     if ((mask & TimeMask) && (CheckIO(rTR))) { 
  183.       GetMsg(rTR->tr_node.io_Message.mn_ReplyPort);
  184.       AbortIO(rRR);                              /* Abort the read request */
  185.       GetMsg(rRR->IOSer.io_Message.mn_ReplyPort);
  186.       return(GS_TIMEOUT);
  187.     }
  188.  
  189. /* Repeat the waiting loop until one of the requests has completed.
  190.  * I'd be extremely happy if someone could explain why we get all those
  191.  * dummy signals which do not correspond to any completed requests. */
  192.  
  193.   } while (1);
  194. }
  195.  
  196. int OpenUpTimer(TReq)
  197. /* Opens up the timer.device. If an error occured the routine releases
  198.  * all resources it has allocated and returns FALSE (==0) */
  199. struct timerequest **TReq;
  200. {
  201.   register struct timerequest *TR;
  202.  
  203.   TR = (struct timerequest *)AllocMem((ULONG)sizeof(*TR),MEMF_PUBLIC|MEMF_CLEAR);
  204.   if (TR == NULL) {
  205.     return(FALSE);
  206.   }
  207.   else
  208.     *TReq = TR;
  209.  
  210.   if ((TR->tr_node.io_Message.mn_ReplyPort = CreatePort("SerTimer",0L))==NULL) {
  211.     Tcleanup(TC_PORT);
  212.     return(FALSE);
  213.   }
  214.   if (OpenDevice(TIMERNAME, UNIT_VBLANK, TR, 0L)) {
  215.     Tcleanup(TC_DEV);
  216.     return(FALSE);
  217.   }
  218.   return(TRUE);
  219. }
  220.  
  221. void Tcleanup(num)
  222. /* Perform timer.device resource deallocation. Call this routine with
  223.  * Tcleanup(TC_NONE) to free all resources after your'e done with the
  224.  * timer. */
  225. register int num;
  226. {
  227.   switch(num) {
  228.   case TC_NONE:
  229.     CloseDevice(TR);
  230.   case TC_DEV:
  231.     DeletePort(TR->tr_node.io_Message.mn_ReplyPort);    
  232.   case TC_PORT:
  233.     FreeMem(TR,(ULONG)sizeof(*TR));
  234.   default:
  235.     TR = NULL;
  236.     break;
  237.   }
  238. }
  239.  
  240. int OpenUpSerial(RReq,WReq,bufsize,baud,unit,name)
  241. /* Opens up the named serial device for read and write. If an error
  242.  * occurs the routine releases all resources it has taken and returns
  243.  * FALSE, so that the caller may do it's own deallocation if serial isn't
  244.  * available. */
  245.  
  246. struct IOExtSer **RReq, **WReq;
  247. ULONG bufsize, baud, unit;
  248. char *name;
  249. {
  250.   register struct IOExtSer *RR, *WR;
  251.  
  252. /* Allocate the read request (IOExtSer) structure, initialize it and open
  253.  * the serial device for reading */
  254.  
  255.   RR = (struct IOExtSer *)AllocMem((ULONG)sizeof(*RR),MEMF_PUBLIC|MEMF_CLEAR);
  256.   if (RR == NULL)
  257.     return(FALSE);
  258.   else
  259.     *RReq = RR;
  260.   RR->io_SerFlags = SERF_SHARED|SERF_XDISABLED;  /* Disable XON/XOFF */
  261.   if ((RR->IOSer.io_Message.mn_ReplyPort = CreatePort("SerRead",0L)) == NULL) {
  262.     Scleanup(SC_RDPORT);
  263.     return(FALSE);
  264.   }
  265.   if (OpenDevice(name,unit,RR,NULL)) {
  266.     Scleanup(SC_RDDEV);
  267.     return(FALSE);
  268.   }
  269.  
  270. /* Allocate the write request (IOExtSer) structure, initialize it and open
  271.  * the serial device for writing */
  272.  
  273.   WR = (struct IOExtSer *)AllocMem((ULONG)sizeof(*WR),MEMF_PUBLIC|MEMF_CLEAR);
  274.   if (WR == NULL) {
  275.     Scleanup(SC_WRREQ);
  276.     return(FALSE);
  277.   }
  278.   else
  279.      *WReq = WR;
  280.  
  281.   WR->io_SerFlags = SERF_SHARED|SERF_XDISABLED;
  282.   if ((WR->IOSer.io_Message.mn_ReplyPort = CreatePort("SerWrite",0L)) == NULL) {
  283.     Scleanup(SC_WRPORT);
  284.     return(FALSE);
  285.   }
  286.   if (OpenDevice(name,unit,WR,NULL)) {
  287.     Scleanup(SC_WRDEV);
  288.     return(FALSE);
  289.   }
  290.  
  291. /* Set up needed parameters with SDCMD_SETPARAMS */
  292.  
  293.   RR->io_SerFlags = SERF_SHARED|SERF_XDISABLED;
  294.   RR->io_Baud = baud;
  295.   RR->io_ReadLen = 8;
  296.   RR->io_WriteLen = 8;
  297.   RR->io_StopBits = 1;
  298.   RR->io_CtlChar = 1L;
  299.   RR->io_RBufLen = bufsize;
  300.   RR->io_BrkTime = 500000L;
  301.   RR->IOSer.io_Command = SDCMD_SETPARAMS;
  302.   if (DoIO(RR)) {
  303.     Scleanup(SC_NONE);
  304.     return(FALSE);
  305.   }
  306.   else
  307.     return(TRUE);
  308. }
  309.  
  310. void Scleanup(num)
  311. /* This routine performs deallocation of serial device related resources.
  312.  * The variable 'num' specifies how much has been allocated before calling
  313.  * the routine. Call with Scleanup(SC_NONE) to free all resource.
  314.  * Uses external variables struct IOExtSer *RR, *WR. */
  315. register int num;
  316. {
  317.   switch(num) {
  318.   case SC_NONE:
  319.     CloseDevice(WR);
  320.   case SC_WRDEV:
  321.     DeletePort(WR->IOSer.io_Message.mn_ReplyPort);
  322.   case SC_WRPORT:
  323.     FreeMem(WR,(ULONG)sizeof(*WR));
  324.   case SC_WRREQ:
  325.     CloseDevice(RR);
  326.   case SC_RDDEV:
  327.     DeletePort(RR->IOSer.io_Message.mn_ReplyPort);
  328.   case SC_RDPORT:
  329.     FreeMem(RR,(ULONG)sizeof(*RR));
  330.   default:
  331.     RR = WR = NULL;
  332.     break;
  333.   }
  334. }
  335.  
  336. /***************************
  337.  * Window related routines *
  338.  ***************************/
  339.  
  340. int SetupWindow(wd)
  341. /* Open up the protocol window according to the windef structure
  342.  * provided. Returns TRUE if window opened without error. */
  343.  
  344. register struct windef *wd;
  345. {
  346.   struct NewWindow nw;
  347.   register struct Screen *fscr;
  348.   register char **strptr;
  349.   register int cnt;
  350.  
  351. /* Open graphics */
  352.  
  353.   GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",33L);
  354.   if (GfxBase == NULL)
  355.     return (FALSE);
  356.  
  357. /* Open intuition library */
  358.  
  359.   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",33L);
  360.   if (IntuitionBase == NULL) {  
  361.     Wcleanup(WC_INTUI);
  362.     return(FALSE);
  363.   }
  364.  
  365. /* Check that the provided window sizes are feasible */
  366.  
  367.   fscr = IntuitionBase->FirstScreen;    /* The screen we'll use */
  368.   if ((fscr->Width < wd->Width) || (fscr->Height < wd->Height)) {
  369.     Wcleanup(WC_WINDOW);
  370.     return (FALSE);
  371.   }
  372.  
  373. /* Initialize our NewWindow structure */
  374.  
  375.   nw.LeftEdge = (fscr->Width - wd->Width) >> 1;
  376.   nw.TopEdge = (fscr->Height - wd->Height) >> 1; 
  377.   nw.Width = wd->Width;
  378.   nw.Height = wd->Height;
  379.   nw.DetailPen = 0;
  380.   nw.BlockPen = 1;
  381.   nw.IDCMPFlags = GADGETUP;
  382.   nw.Flags = ACTIVATE|GIMMEZEROZERO|WINDOWDRAG|WINDOWDEPTH|SMART_REFRESH;
  383.   nw.FirstGadget = &AbortGadget;
  384.   nw.CheckMark = NULL;
  385.   nw.Title = (UBYTE *)wd->Title;
  386.   nw.Screen = fscr;
  387.   nw.BitMap = NULL;
  388.   if (strcmp(fscr->DefaultTitle,"Workbench Screen"))
  389.     nw.Type = CUSTOMSCREEN;
  390.   else
  391.     nw.Type = WBENCHSCREEN;
  392.  
  393.   AbortGadget.LeftEdge = wd->GXpos;  /* Gadget position within the window */
  394.   AbortGadget.TopEdge = wd->GYpos;
  395.  
  396. /* Open the window */
  397.  
  398.   if ((pwin = OpenWindow(&nw)) == NULL) {  
  399.     Wcleanup(WC_WINDOW);
  400.     return(FALSE);
  401.   }
  402.  
  403. /* Display the window texts */
  404.  
  405.   SetAPen(pwin->RPort,1L);
  406.   strptr = wd->Text;
  407.   cnt = 0;
  408.   if (strptr)
  409.     while (*strptr) {
  410.       Move(pwin->RPort,4L,(ULONG)++cnt * pwin->RPort->TxHeight);
  411.       Text(pwin->RPort,*strptr,(ULONG)strlen(*strptr));
  412.       strptr++;
  413.     }
  414.  
  415.   SetAPen(pwin->RPort,3L);
  416.   return(TRUE);
  417. }
  418.  
  419. void PText(line,col,string,arg1,arg2)
  420. /* Display a formatted string at a defined location in the window. The
  421.  * routine clears the rest of the line to get rid of old messages. Two
  422.  * ----> 32 bit <---- arguments (arg1 and arg2) are passed to sprintf()
  423.  */
  424. register UWORD line,col;
  425. register char *string;
  426. ULONG arg1, arg2;  /* Pleeeze, don't pass integer args to PText sprintf() */
  427. {
  428.   char tstr[80];
  429.   register struct RastPort *rp = pwin->RPort;
  430.  
  431.   sprintf(tstr,string,arg1,arg2);
  432.   Move(rp,(ULONG)col * rp->TxWidth + 4L, (ULONG)(line+1) * rp->TxHeight);
  433.   Text(rp,tstr,(ULONG)strlen(tstr));
  434.   ClearEOL(rp);
  435. }
  436.  
  437. int CheckAbort()
  438. /* This routine returns TRUE if the 'Abort' gadget has been pressed by
  439.  * the user. It is assumed that no other custom gadgets exist in the window.
  440.  */
  441. {
  442.   register struct IntuiMessage *imsg;
  443.  
  444.   if ((imsg = GetMsg(pwin->UserPort)) == NULL)
  445.     return(FALSE);
  446.   else
  447.     if (imsg->Class != GADGETUP) {
  448.       ReplyMsg(imsg);
  449.       return(FALSE);
  450.     }
  451.     else {
  452.       ReplyMsg(imsg);
  453.       return(TRUE);
  454.     }
  455. }
  456.  
  457. void Wcleanup(num)
  458. /* Perform window cleanup. Call this with WC_NONE to close window and
  459.  * libraries after usage */
  460.  
  461. register int num;
  462. {
  463.   switch (num) {
  464.   case WC_NONE:
  465.     CloseWindow(pwin);
  466.     pwin = NULL;
  467.   case WC_WINDOW:
  468.     CloseLibrary(IntuitionBase);
  469.     IntuitionBase = NULL;
  470.   case WC_INTUI:
  471.     CloseLibrary(GfxBase);
  472.     GfxBase = NULL;
  473.   }
  474. }
  475.