/** xprascii.c * * These are the protocol transfer routines for a simple ASCII upload. * **/ #include #include #include /* * xproto.h is the include file given in Appendix B. */ #include "xproto.h" /* * The following two strings must exist. */ char XPRname[] = "xprascii.library"; char XPRid[] = "xprascii 0.9 (May 89)\r\n"; UWORD XPRrevision = 9; long atol(); /* * The callxx...() routines are described later. They provide the * assembler interface from the XPR library to the call-back routines. */ long calla(), callaa(), callad(), calladd(), calladda(); char *malloc(); /** * * Send a file * **/ long XProtocolSend(IO) struct XPR_IO *IO; { long fp, r, i; long brkflag = 0, fl = 0L, sd = 0L; long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfread)(), (*xsread)(), (*xchkabort)(); unsigned char *buff = NULL, *serbuff = NULL; struct XPR_UPDATE xpru; /* * These are the call-backs we need. If any of them isn't provided, quit. * Could do some error reporting if at least xupdate is there. */ if ((xupdate = IO->xpr_update) == NULL) return(0L); if ((xswrite = IO->xpr_swrite) == NULL) return(0L); if ((xfopen = IO->xpr_fopen) == NULL) return(0L); if ((xfclose = IO->xpr_fclose) == NULL) return(0L); if ((xfread = IO->xpr_fread) == NULL) return(0L); if ((xsread = IO->xpr_sread) == NULL) return(0L); if ((xchkabort = IO->xpr_chkabort) == NULL) return(0L); /* * Allocate a few buffers. */ buff = (unsigned char *) malloc(80); serbuff = (unsigned char *) malloc(80); /* * If we ran out of memory, print a message. * The argument needs to go in A0: calla does this for us. */ if (buff == NULL || serbuff == NULL) { xpru.xpru_updatemask = XPRU_ERRORMSG; xpru.xpru_errormsg = "Ran out of memory!"; calla(xupdate, &xpru); return(0L); } /* * Read the send delay, if a XProtocolSetup() was done before. * If send delay is too large, cut it off at 10 seconds. * In this example, the xpr_data field contains a null terminated string * containing the number of ticks to delay each 80 characters. */ if (IO->xpr_data) { sd = atol(IO->xpr_data); if (sd > 500L) sd = 500L; } /* * Open the file. One could do wild card detection here. * xfopen requires two arguments, in a0 and a1 respectively. * Again, this must be done in assembler, and callaa does it. */ fp = callaa(xfopen, IO->xpr_filename, "r"); if (fp == NULL) { free(buff); free(serbuff); xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_FILENAME; xpru.xpru_errormsg = "Failed to open input file"; xpru.xpru_filename = IO->xpr_filename; calla(xupdate, &xpru); return(0L); } /* * Start the transfer. See 3.8 for a discussion on how to implement * xupdate. */ xpru.xpru_updatemask = XPRU_MSG | XPRU_FILENAME; xpru.xpru_msg = "Starting ASCII Send"; xpru.xpru_filename = IO->xpr_filename; calla(xupdate, &xpru); /* * Now read 80 byte chunks from the file using xfread. * xfread requires four arguments, a0, d0, d1 and a1. */ xpru.xpru_blocks = 0L; while (r = calladda(xfread, buff, 1L, 80L, fp)) { /* * Convert line feeds to carriage returns before sending to host. * fl counts the characters. Display how many characters are sent. */ for (i = 0L; i < r; i++) if (buff[i] == '\n') buff[i] = '\r'; fl += r; xpru.xpru_updatemask = XPRU_BYTES | XPRU_BLOCKS | XPRU_BLOCKSIZE; xpru.xpru_bytes = fl; xpru.xpru_blocks++; xpru.xpru_blocksize = r; calla(xupdate, &xpru); callad(xswrite, buff, r); /* * Every 80 bytes, put out a message and delay if requested. */ xpru.xpru_updatemask = XPRU_PACKETDELAY; xpru.xpru_packetdelay = sd * 20L; /* msec! */ calla(xupdate, &xpru); /* * Can't use Delay() here, because Delay() is in dos.library! * However writing an equivalent function using the timer.device is * trivial. */ TimeOut(sd); /* * Eat any characters that might arrive from the serial port. * calladd stores arg1 in a0, arg2 in d0, arg3 in d1. * We're not really waiting for any characters: use a timeout of 0L. */ while (calladd(xsread, serbuff, 80L, 0L) > 0L) ; /* * Check for "abort" here. Perhaps should call chkmisc() as well. */ if (brkflag = xchkabort()) break; } /* * Close the file */ calla(xfclose, fp); free(buff); free(serbuff); /* * If we got here through chkabort() say Aborted. */ xpru.xpru_updatemask = XPRU_MSG; if (brkflag) xpru.xpru_msg = "Aborted"; else xpru.xpru_msg = "Done"; calla(xupdate, &xpru); if (brkflag) return(0L); else return(1L); } /** * * Receive a file. * **/ long XProtocolReceive(IO) struct XPR_IO *IO; { long fp, r, i; long brkflag = 0, fl = 0L, sd = 0L; long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfwrite)(), (*xsread)(), (*xchkabort)(); unsigned char *serbuff = NULL; struct XPR_UPDATE xpru; /* * These are the call-backs we need. If any of them isn't provided, quit. * Could do some error reporting if at least xupdate is there. */ if ((xupdate = IO->xpr_update) == NULL) return(0L); if ((xswrite = IO->xpr_swrite) == NULL) return(0L); if ((xfopen = IO->xpr_fopen) == NULL) return(0L); if ((xfclose = IO->xpr_fclose) == NULL) return(0L); if ((xfwrite = IO->xpr_fwrite) == NULL) return(0L); if ((xsread = IO->xpr_sread) == NULL) return(0L); if ((xchkabort = IO->xpr_chkabort) == NULL) return(0L); /* * Allocate a buffer. */ serbuff = (unsigned char *) malloc(80); /* * If we ran out of memory, print a message. * The argument needs to go in A0: calla does this for us. */ if (serbuff == NULL) { xpru.xpru_updatemask = XPRU_ERRORMSG; xpru.xpru_errormsg = "Ran out of memory!"; calla(xupdate, &xpru); return(0L); } /* * Open the file. One could do wild card detection here. * xfopen requires two arguments, in a0 and a1 respectively. * Again, this must be done in assembler, and callaa does it. */ fp = callaa(xfopen, IO->xpr_filename, "w"); if (fp == NULL) { free(serbuff); xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_FILENAME; xpru.xpru_errormsg = "Failed to open output file"; xpru.xpru_filename = IO->xpr_filename; calla(xupdate, &xpru); return(0L); } /* * Start the transfer. See 3.8 for a discussion on how to implement * xupdate. */ xpru.xpru_updatemask = XPRU_MSG | XPRU_FILENAME; xpru.xpru_msg = "Starting ASCII Receive"; xpru.xpru_filename = IO->xpr_filename; calla(xupdate, &xpru); /* * Now read 80 byte chunks from the serial port using xsread. Stop * when no characters arrive for 5 sec. */ xpru.xpru_blocks = 0L; while ((r = calladd(xsread, serbuff, 80L, 5000000L)) > 0L) { /* * Strip high-bit before storing in file. * fl counts the characters. Display how many characters are received. */ for (i = 0L; i < r; i++) serbuff[i] &= 0177; fl += r; xpru.xpru_updatemask = XPRU_BYTES | XPRU_BLOCKS | XPRU_BLOCKSIZE; xpru.xpru_bytes = fl; xpru.xpru_blocks++; xpru.xpru_blocksize = r; calla(xupdate, &xpru); /* * Write 80 byte chunks to the file using xwrite */ calladda(xfwrite, serbuff, 1L, r, fp); /* * Check for "abort" here. Perhaps should call chkmisc() as well. */ if (brkflag = xchkabort()) break; } /* * Close the file */ calla(xfclose, fp); free(serbuff); /* * If we got here through chkabort() say Aborted. */ xpru.xpru_updatemask = XPRU_MSG; if (brkflag) xpru.xpru_msg = "Aborted"; else xpru.xpru_msg = "Done"; calla(xupdate, &xpru); if (brkflag) return(0L); else return(1L); } /** * * Setup * **/ long XProtocolSetup(IO) struct XPR_IO *IO; { long (*xupdate)(), (*xgets)(); struct XPR_UPDATE xpru; if ((xupdate = IO->xpr_update) == NULL) return(0L); if ((xgets = IO->xpr_gets) == NULL) return(0L); /* * Allocate a bit of memory for a data buffer */ if (IO->xpr_data == NULL) { if ((IO->xpr_data = (long *) malloc(256)) == NULL) { xpru.xpru_updatemask = XPRU_ERRORMSG; xpru.xpru_errormsg = "ASCII - Out of memory!"; calla(xupdate, &xpru); return(0L); } } /* * If setup string isn't handed to us, ask questions */ if (IO->xpr_filename == NULL) { /* * Get the value for the send dealy */ callaa(xgets, "Enter ASCII send delay (ticks, 1 tick = 20 msec)", IO->xpr_data); } else { strcpy(IO->xpr_data, IO->xpr_filename); } return(1L); } /** * * Cleanup * **/ long XProtocolCleanup(IO) struct XPR_IO *IO; { if (IO->xpr_data) free(IO->xpr_data); IO->xpr_data = NULL; return(1L); } /** * * The following functions setup the proper registers for the call-back * functions. * **/ #asm public _callad _callad: movea.l 8(sp),a0 ; Second argument goes in a0 move.l 12(sp),d0 ; Third argument goes in d0 /* * Now this is a trick to avoid using another register. * Charlie taught me this... */ move.l 4(sp),-(sp) ; First argument is function rts public _calladda _calladda: movea.l 8(sp),a0 ; Second argument goes in a0 move.l 12(sp),d0 ; Third argument goes in d0 move.l 16(sp),d1 ; Fourth argument goes in d1 movea.l 20(sp),a1 ; Fifth argument goes in a1 move.l 4(sp),-(sp) ; First argument is function rts public _calla _calla: movea.l 8(sp),a0 ; Second argument goes in a0 move.l 4(sp),-(sp) ; First argument is function rts public _callaa _callaa: movea.l 8(sp),a0 ; Second argument goes in a0 movea.l 12(sp),a1 ; Third argument goes in a1 move.l 4(sp),-(sp) ; First argument is function rts public _calladd _calladd: move.l 8(sp),a0 ; Second argument goes in a0 move.l 12(sp),d0 ; Third argument goes in d0 move.l 16(sp),d1 ; Fourth argument goes in d1 move.l 4(sp),-(sp) ; First argument is function rts #endasm /* * Could have added any other functions needed for other call-backs. * Could have written a fancier single one... Could've... */