home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- * Support routines for file transfer protocol implementations. *
- * The routines in this file provide easy access to the serial *
- * device with true timeouts, and simplified window management. *
- * Kenneth Österberg 02-May-1989 *
- ****************************************************************/
-
- /* Compilation with Aztec C:
- * cc +B -o protsupp.o protsupp.c
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <devices/serial.h>
- #include <devices/timer.h>
- #include <graphics/rastport.h>
- #include <intuition/intuition.h>
- #include <intuition/intuitionbase.h>
-
- #define GWID 48 /* Gadget width */
- #define GHGT 12 /* Gadget height */
-
- #define WC_NONE 0 /* Window cleanup (Wcleanup()) error codes. Call */
- #define WC_WINDOW 1 /* with WC_NONE when you want to get rid of the */
- #define WC_INTUI 2 /* window */
-
- #define SC_RDPORT 5 /* Error codes for Scleanup(). Call the routine */
- #define SC_RDDEV 4 /* with SC_NONE to deallocate all serial port */
- #define SC_WRREQ 3 /* resources. */
- #define SC_WRPORT 2
- #define SC_WRDEV 1
- #define SC_NONE 0
-
- #define TC_PORT 2 /* Error codes for Tcleanup(). Call with TC_NONE */
- #define TC_DEV 1 /* to deallocate timer.device resources */
- #define TC_NONE 0
-
- #define GS_TIMEOUT 1 /* Error codes returned by getserdata() and */
- #define GS_NONE 0 /* getserchar(). GS_NONE means everything's OK */
-
- /* Amiga library routines used by this file */
-
- extern APTR AllocMem();
- extern ULONG Wait();
- extern struct MsgPort *CreatePort();
- extern int OpenDevice(), DoIO();
- extern void FreeMem(), DeletePort(), CloseDevice(), DeletePort();
- extern ULONG AbortIO(), CheckIO();
- extern void CloseLibrary(), CloseWindow();
- extern struct Window *OpenWindow();
- extern APTR OpenLibrary();
- extern void SetAPen(), Move(), Text(), ClearEOL();
- extern struct IntuiMessage *GetMsg();
-
- /* Global variables */
-
- struct IOExtSer *RR, *WR;
- struct timerequest *TR;
- struct GfxBase *GfxBase = NULL;
- struct IntuitionBase *IntuitionBase = NULL;
- struct Window *pwin = NULL;
-
- /* The structure that SetupWindow() takes as argument */
-
- struct windef {
- UWORD Width, Height;
- UWORD GXpos, GYpos;
- char *Title;
- char **Text;
- };
-
- /* Structures to create the Abort gadget */
-
- struct IntuiText AText = { 1, 0, JAM2, 5, 2 ,NULL, (UBYTE *)"Abort", NULL };
- SHORT AVectors[] = { -1,-1, GWID,-1, GWID,GHGT, -1,GHGT, -1,-1 };
- struct Border ABorder = { 0, 0, 1, 0, JAM2, 5, AVectors, NULL };
- struct Gadget AbortGadget = { NULL, 0,0, GWID,GHGT, GADGHCOMP, RELVERIFY,
- BOOLGADGET, (APTR)&ABorder, NULL, &AText, 0L, NULL, 0, NULL };
-
- /* Local routines */
-
- int OpenUpSerial(), OpenUpTimer(), getserdata(), getserchar();
- int sendserdata(), sendserchar();
- void Scleanup(), Tcleanup();
- int SetupWindow(), CheckAbort();
- void Wcleanup(), PText();
-
- /********************
- * The code section *
- ********************/
-
- int sendserchar(ch)
- /* Sends a character to the serial device. Returns the error from DoIO() */
- register char *ch;
- {
- return(sendserdata(ch,1L));
- }
-
- int sendserdata(ch,len)
- /* Sends a data buffer to the serial device. Returns the error from DoIO()
- * Uses external variable struct IOExtSer *WR. */
- register UBYTE *ch;
- register ULONG len;
- {
- register struct IOExtSer *rWR = WR; /* Cache pointer in a register */
-
- rWR->IOSer.io_Command = CMD_WRITE;
- rWR->IOSer.io_Length = len;
- rWR->IOSer.io_Data = (APTR) ch;
- return(DoIO(rWR));
- }
-
- int getserchar(timeout,chrptr)
- /* Get one character from the serial port */
- register ULONG timeout;
- register UBYTE *chrptr;
- {
- return(getserdata(timeout,chrptr,1L));
- }
-
- int getserdata(timeout,chrptr,len)
- /* Wait for a specific number of characters to arrive at the serial port.
- * The routine doesn't return until all characters have arrived, or an
- * timeout occurs. Uses the external variable struct IOExtSer *RR and
- * struct timerequest *TR.
- * The function returns an error code (see #defines with prefixes 'GS_') */
-
- register ULONG timeout;
- UBYTE *chrptr;
- ULONG len;
- {
- ULONG mask;
- register ULONG ReadMask, TimeMask = 0L;
- register struct timerequest *rTR = TR; /* TR into register for speed */
- register struct IOExtSer *rRR = RR; /* RR into register for speed */
-
- /* Send the request for the characters we need. Try to use quick IO */
-
- rRR->IOSer.io_Command = CMD_READ;
- rRR->IOSer.io_Data = (APTR)chrptr;
- rRR->IOSer.io_Length = len;
- rRR->IOSer.io_Flags |= IOF_QUICK;
- BeginIO(rRR);
-
- /* Check if quick IO succeeded. If so, we don't have to mess with all that
- * message passing, and the timer doesn't even have to get involved. */
-
- if (rRR->IOSer.io_Flags & IOF_QUICK) {
- return(GS_NONE);
- }
-
- /* If the timeout value <> 0 then send the request to the timer device.
- * If you don't need any timeout limits then simply give a timeout value
- * NULL to this routine, and a timeout will never occur. */
-
- if (timeout) {
- rTR->tr_time.tv_secs = timeout / 50;
- rTR->tr_time.tv_micro = (timeout % 50L) * 20000L;
- rTR->tr_node.io_Command = TR_ADDREQUEST;
- SendIO(rTR);
- TimeMask = 1L << rTR->tr_node.io_Message.mn_ReplyPort->mp_SigBit;
- }
- ReadMask = 1L << rRR->IOSer.io_Message.mn_ReplyPort->mp_SigBit;
-
- /* Wait until the characters have been received or a timeout occurs */
-
- do {
- mask = Wait(ReadMask|TimeMask);
-
- /* Check if the serial device request has completed */
-
- if ((mask & ReadMask) && (CheckIO(rRR))) {
- if (timeout)
- if (!CheckIO(rTR))
- AbortIO(rTR);
- GetMsg(rTR->tr_node.io_Message.mn_ReplyPort);
- return(GS_NONE); /* Return with no error */
- }
-
- /* Check if the timer device request has completed */
-
- if ((mask & TimeMask) && (CheckIO(rTR))) {
- GetMsg(rTR->tr_node.io_Message.mn_ReplyPort);
- AbortIO(rRR); /* Abort the read request */
- GetMsg(rRR->IOSer.io_Message.mn_ReplyPort);
- return(GS_TIMEOUT);
- }
-
- /* Repeat the waiting loop until one of the requests has completed.
- * I'd be extremely happy if someone could explain why we get all those
- * dummy signals which do not correspond to any completed requests. */
-
- } while (1);
- }
-
- int OpenUpTimer(TReq)
- /* Opens up the timer.device. If an error occured the routine releases
- * all resources it has allocated and returns FALSE (==0) */
- struct timerequest **TReq;
- {
- register struct timerequest *TR;
-
- TR = (struct timerequest *)AllocMem((ULONG)sizeof(*TR),MEMF_PUBLIC|MEMF_CLEAR);
- if (TR == NULL) {
- return(FALSE);
- }
- else
- *TReq = TR;
-
- if ((TR->tr_node.io_Message.mn_ReplyPort = CreatePort("SerTimer",0L))==NULL) {
- Tcleanup(TC_PORT);
- return(FALSE);
- }
- if (OpenDevice(TIMERNAME, UNIT_VBLANK, TR, 0L)) {
- Tcleanup(TC_DEV);
- return(FALSE);
- }
- return(TRUE);
- }
-
- void Tcleanup(num)
- /* Perform timer.device resource deallocation. Call this routine with
- * Tcleanup(TC_NONE) to free all resources after your'e done with the
- * timer. */
- register int num;
- {
- switch(num) {
- case TC_NONE:
- CloseDevice(TR);
- case TC_DEV:
- DeletePort(TR->tr_node.io_Message.mn_ReplyPort);
- case TC_PORT:
- FreeMem(TR,(ULONG)sizeof(*TR));
- default:
- TR = NULL;
- break;
- }
- }
-
- int OpenUpSerial(RReq,WReq,bufsize,baud,unit,name)
- /* Opens up the named serial device for read and write. If an error
- * occurs the routine releases all resources it has taken and returns
- * FALSE, so that the caller may do it's own deallocation if serial isn't
- * available. */
-
- struct IOExtSer **RReq, **WReq;
- ULONG bufsize, baud, unit;
- char *name;
- {
- register struct IOExtSer *RR, *WR;
-
- /* Allocate the read request (IOExtSer) structure, initialize it and open
- * the serial device for reading */
-
- RR = (struct IOExtSer *)AllocMem((ULONG)sizeof(*RR),MEMF_PUBLIC|MEMF_CLEAR);
- if (RR == NULL)
- return(FALSE);
- else
- *RReq = RR;
- RR->io_SerFlags = SERF_SHARED|SERF_XDISABLED; /* Disable XON/XOFF */
- if ((RR->IOSer.io_Message.mn_ReplyPort = CreatePort("SerRead",0L)) == NULL) {
- Scleanup(SC_RDPORT);
- return(FALSE);
- }
- if (OpenDevice(name,unit,RR,NULL)) {
- Scleanup(SC_RDDEV);
- return(FALSE);
- }
-
- /* Allocate the write request (IOExtSer) structure, initialize it and open
- * the serial device for writing */
-
- WR = (struct IOExtSer *)AllocMem((ULONG)sizeof(*WR),MEMF_PUBLIC|MEMF_CLEAR);
- if (WR == NULL) {
- Scleanup(SC_WRREQ);
- return(FALSE);
- }
- else
- *WReq = WR;
-
- WR->io_SerFlags = SERF_SHARED|SERF_XDISABLED;
- if ((WR->IOSer.io_Message.mn_ReplyPort = CreatePort("SerWrite",0L)) == NULL) {
- Scleanup(SC_WRPORT);
- return(FALSE);
- }
- if (OpenDevice(name,unit,WR,NULL)) {
- Scleanup(SC_WRDEV);
- return(FALSE);
- }
-
- /* Set up needed parameters with SDCMD_SETPARAMS */
-
- RR->io_SerFlags = SERF_SHARED|SERF_XDISABLED;
- RR->io_Baud = baud;
- RR->io_ReadLen = 8;
- RR->io_WriteLen = 8;
- RR->io_StopBits = 1;
- RR->io_CtlChar = 1L;
- RR->io_RBufLen = bufsize;
- RR->io_BrkTime = 500000L;
- RR->IOSer.io_Command = SDCMD_SETPARAMS;
- if (DoIO(RR)) {
- Scleanup(SC_NONE);
- return(FALSE);
- }
- else
- return(TRUE);
- }
-
- void Scleanup(num)
- /* This routine performs deallocation of serial device related resources.
- * The variable 'num' specifies how much has been allocated before calling
- * the routine. Call with Scleanup(SC_NONE) to free all resource.
- * Uses external variables struct IOExtSer *RR, *WR. */
- register int num;
- {
- switch(num) {
- case SC_NONE:
- CloseDevice(WR);
- case SC_WRDEV:
- DeletePort(WR->IOSer.io_Message.mn_ReplyPort);
- case SC_WRPORT:
- FreeMem(WR,(ULONG)sizeof(*WR));
- case SC_WRREQ:
- CloseDevice(RR);
- case SC_RDDEV:
- DeletePort(RR->IOSer.io_Message.mn_ReplyPort);
- case SC_RDPORT:
- FreeMem(RR,(ULONG)sizeof(*RR));
- default:
- RR = WR = NULL;
- break;
- }
- }
-
- /***************************
- * Window related routines *
- ***************************/
-
- int SetupWindow(wd)
- /* Open up the protocol window according to the windef structure
- * provided. Returns TRUE if window opened without error. */
-
- register struct windef *wd;
- {
- struct NewWindow nw;
- register struct Screen *fscr;
- register char **strptr;
- register int cnt;
-
- /* Open graphics */
-
- GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",33L);
- if (GfxBase == NULL)
- return (FALSE);
-
- /* Open intuition library */
-
- IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",33L);
- if (IntuitionBase == NULL) {
- Wcleanup(WC_INTUI);
- return(FALSE);
- }
-
- /* Check that the provided window sizes are feasible */
-
- fscr = IntuitionBase->FirstScreen; /* The screen we'll use */
- if ((fscr->Width < wd->Width) || (fscr->Height < wd->Height)) {
- Wcleanup(WC_WINDOW);
- return (FALSE);
- }
-
- /* Initialize our NewWindow structure */
-
- nw.LeftEdge = (fscr->Width - wd->Width) >> 1;
- nw.TopEdge = (fscr->Height - wd->Height) >> 1;
- nw.Width = wd->Width;
- nw.Height = wd->Height;
- nw.DetailPen = 0;
- nw.BlockPen = 1;
- nw.IDCMPFlags = GADGETUP;
- nw.Flags = ACTIVATE|GIMMEZEROZERO|WINDOWDRAG|WINDOWDEPTH|SMART_REFRESH;
- nw.FirstGadget = &AbortGadget;
- nw.CheckMark = NULL;
- nw.Title = (UBYTE *)wd->Title;
- nw.Screen = fscr;
- nw.BitMap = NULL;
- if (strcmp(fscr->DefaultTitle,"Workbench Screen"))
- nw.Type = CUSTOMSCREEN;
- else
- nw.Type = WBENCHSCREEN;
-
- AbortGadget.LeftEdge = wd->GXpos; /* Gadget position within the window */
- AbortGadget.TopEdge = wd->GYpos;
-
- /* Open the window */
-
- if ((pwin = OpenWindow(&nw)) == NULL) {
- Wcleanup(WC_WINDOW);
- return(FALSE);
- }
-
- /* Display the window texts */
-
- SetAPen(pwin->RPort,1L);
- strptr = wd->Text;
- cnt = 0;
- if (strptr)
- while (*strptr) {
- Move(pwin->RPort,4L,(ULONG)++cnt * pwin->RPort->TxHeight);
- Text(pwin->RPort,*strptr,(ULONG)strlen(*strptr));
- strptr++;
- }
-
- SetAPen(pwin->RPort,3L);
- return(TRUE);
- }
-
- void PText(line,col,string,arg1,arg2)
- /* Display a formatted string at a defined location in the window. The
- * routine clears the rest of the line to get rid of old messages. Two
- * ----> 32 bit <---- arguments (arg1 and arg2) are passed to sprintf()
- */
- register UWORD line,col;
- register char *string;
- ULONG arg1, arg2; /* Pleeeze, don't pass integer args to PText sprintf() */
- {
- char tstr[80];
- register struct RastPort *rp = pwin->RPort;
-
- sprintf(tstr,string,arg1,arg2);
- Move(rp,(ULONG)col * rp->TxWidth + 4L, (ULONG)(line+1) * rp->TxHeight);
- Text(rp,tstr,(ULONG)strlen(tstr));
- ClearEOL(rp);
- }
-
- int CheckAbort()
- /* This routine returns TRUE if the 'Abort' gadget has been pressed by
- * the user. It is assumed that no other custom gadgets exist in the window.
- */
- {
- register struct IntuiMessage *imsg;
-
- if ((imsg = GetMsg(pwin->UserPort)) == NULL)
- return(FALSE);
- else
- if (imsg->Class != GADGETUP) {
- ReplyMsg(imsg);
- return(FALSE);
- }
- else {
- ReplyMsg(imsg);
- return(TRUE);
- }
- }
-
- void Wcleanup(num)
- /* Perform window cleanup. Call this with WC_NONE to close window and
- * libraries after usage */
-
- register int num;
- {
- switch (num) {
- case WC_NONE:
- CloseWindow(pwin);
- pwin = NULL;
- case WC_WINDOW:
- CloseLibrary(IntuitionBase);
- IntuitionBase = NULL;
- case WC_INTUI:
- CloseLibrary(GfxBase);
- GfxBase = NULL;
- }
- }
-