Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ut-sally!ut-ngp!mic From: mic@ut-ngp.UUCP (Mic Kaczmarczik) Newsgroups: net.micro.amiga Subject: Re: Picking a terminal emulator Message-ID: <3821@ut-ngp.UUCP> Date: Tue, 19-Aug-86 23:27:05 EDT Article-I.D.: ut-ngp.3821 Posted: Tue Aug 19 23:27:05 1986 Date-Received: Wed, 20-Aug-86 22:52:05 EDT References: <232@neoucom.UUCP> <148600124@uiucuxc> <637@cbmvax.cbmvax.cbm.UUCP> Reply-To: mic@ngp.UUCP (Mic Kaczmarczik) Organization: UTexas Computation Center, Austin, Texas Lines: 1452 The following is a modified version of the Amigaterm terminal emulator written by Michael Mounier in the distant past (ca. last winter). This program has no relation (except in function) to the Amigaterm terminal emulator soon to be marketed by Commodore-Amiga. The program was compiled with Lattice C version 3.03. There's just one source file, so compile it and link with Lstartup.obj and amiga.lib. "Awright, who needs another version of Amigaterm???", you ask. Well, I'm posting this because it gives an example of 1) connecting the console device to a window, and 2) using the serial command SDCMD_QUERY to read in as many characters as possible at a time from the serial port, which makes it *MUCH* faster! Using this program, I've managed to keep up with page after page of 80-column lines at 9600 baud, although sending an XOFF to the host takes a while to have any apparent effect at such high speeds. It's also nice to have an 80-column window, full-screen editing... Enjoy, Mic Kaczmarczik UUCP: ...!ihnp4!seismo!ut-sally!ut-ngp!mic ARPA: mic@a20.cc.utexas.edu BITNET: ccep001@utadnx.bitnet --------If you don't cut here, you'll see lots of compilation errors------ /* * AmigaTerm! * * A terminal program that has ascii and xmodem transfer capability * * Use ESC to abort xmodem transfer * * Written by Michael Mounier * * Console stuff, quit, preference items (and serious hacking trying to * improve throughput) by Mic Kaczmarczik * * Thrust into the harsh light of public scrutiny August 19, 1986 */ #include #include #include #include #include #include #include #include #include #include /* specify which revision level of the Graphics and Intuition * libraries we'll settle for */ #define INTUITION_REV 1 #define GRAPHICS_REV 1 /* things for xmodem send and recieve */ #define SECSIZ 0x80 #define TTIME 30 /* number of seconds for timeout */ #define BufSize 0x1000 /* Text buffer */ #define ERRORMAX 10 /* Max errors before abort */ #define RETRYMAX 10 /* Maximum retrys before abort */ #define SOH 1 /* Start of sector char */ #define EOT 4 /* end of transmission char */ #define ACK 6 /* acknowledge sector transmission */ #define NAK 21 /* error in transmission detected */ /* New window structure */ struct NewWindow NewWindow = { 0, 0, 640, 200, 0, 1, CLOSEWINDOW | MENUPICK, WINDOWCLOSE | SMART_REFRESH | ACTIVATE | BORDERLESS | WINDOWDEPTH, NULL, NULL, "AmigaTerm 1.7(6)", NULL, NULL, 160, 50, 640, 200, WBENCHSCREEN, }; struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Window *mywindow; /* ptr to applications window */ struct IntuiMessage *NewMessage; /* msg structure for GetMsg() */ /***************************************************/ /* Main Menu Definition */ /* */ /* This section of code is where the simple */ /* menu definition goes. */ /***************************************************/ /* Number of available menu topics */ #define MAXMENU 3 struct Menu menu[MAXMENU]; #define FILEMAX 5 struct MenuItem FileItem[FILEMAX]; struct IntuiText FileText[FILEMAX]; #define SETMAX 3 struct MenuItem SetItem[SETMAX]; struct IntuiText SetText[SETMAX]; #define TWMAX 5 struct MenuItem TWItem[TWMAX]; struct IntuiText TWText[TWMAX]; /*****************************************************/ /* Settings submenus */ /*****************************************************/ /* BaudRate submenu */ #define RSMAX 6 struct MenuItem RSItem[RSMAX]; struct IntuiText RSText[RSMAX]; int baudrates[RSMAX] = { 300, 450, 1200, 2400, 4800, 9600 }; char *baudstrings[RSMAX] = { " 300", " 450", " 1200", " 2400", " 4800", " 9600" }; /* Parity submenu */ #define PSMAX 3 struct MenuItem PSItem[RSMAX]; struct IntuiText PSText[RSMAX]; /* Byte length submenu */ #define BSMAX 2 struct MenuItem BSItem[BSMAX]; struct IntuiText BSText[BSMAX]; /* Flags for various preferences. * This lack of structure is not good for later improvements :-) * * bs_to_del -- map BS to DEL and DEL to BS * echo -- local echo * wrap -- line wrap (nice for small terminal windows) * newline -- console interprets \n as \r\n? * debug -- show how bad our throughput is */ int bs_to_del = 1; /* BS -> DEL */ int echo = 0; /* local echo */ int wrap = 1; /* auto wrap */ int newline = 1; /* console NL acts like CR + NL*/ int debug = 0; /* put '|' around each modem read */ /*********************************************** declarations for the serial stuff ***********************************************/ extern struct MsgPort *CreatePort(); extern struct IOStdReq *CreateStdIO(); struct IOExtSer *Read_Request; struct IOExtSer *Write_Request; unsigned char ser_in[BufSize], /* serial input buffer */ ser_out[2], /* serial output buffer */ capbuf[BufSize]; /* capture buffer */ int fd, timeout = FALSE; long bytes_xferred; /******************************************* Declarations for console device *******************************************/ struct IOStdReq *consoleWriteMsg; /* I/O request block pointer */ struct IOStdReq *consoleReadMsg; /* Ditto */ struct MsgPort *consoleWritePort; /* port at which to receive replies*/ struct MsgPort *consoleReadPort; /* ditto */ unsigned char con_in[1], /* Buffer for console read */ con_out[BufSize]; /* Ditto for console write */ /**************************************************** Error handling ****************************************************/ #define ERR_INTUITIONBASE 1 #define ERR_GFXBASE 2 #define ERR_NEWWINDOW 3 #define ERR_ALLOC_READ_REQ 4 #define ERR_CRE_READ_PORT 5 #define ERR_OPEN_SER_READ 6 #define ERR_ALLOC_WRITE_REQ 7 #define ERR_OPEN_SER_WRITE 8 #define ERR_CRE_WRITE_PORT 9 #define ERR_CRE_CON_WRITE 10 #define ERR_CRE_STD_WRITE 11 #define ERR_CRE_CON_READ 12 #define ERR_CRE_STD_READ 13 #define ERR_OPENCONSOLE 14 #define SERIAL_CHAR (1<IOSer.io_Message.mn_ReplyPort->mp_SigBit; IntuitionBit = mywindow->UserPort->mp_SigBit; ConsoleBit = consoleReadPort->mp_SigBit; /* * Queue up reads to the serial and console devices */ SendIO(Read_Request); SendIO(consoleReadMsg); /* * Main event loop */ while( KeepGoing ) { /* wait for window, console, or serial port message */ EventMask = Wait(SERIAL_CHAR | TYPED_CHAR | INTUITION_EVENT); if (CheckIO(Read_Request)) /* serial char */ Handle_Modem(); if (EventMask & TYPED_CHAR) /* from keyboard */ Handle_Char(); /* Intuition events */ while (NewMessage = (struct IntuiMessage *) GetMsg(mywindow->UserPort)) { class = NewMessage->Class; code = NewMessage->Code; ReplyMsg( NewMessage ); switch (class) { case CLOSEWINDOW: /* User is ready to quit, so indicate that * execution should terminate with next * iteration of the loop. */ KeepGoing = FALSE; break; case MENUPICK: if (code == MENUNULL) break; menunum = MENUNUM(code); itemnum = ITEMNUM(code); subnum = SUBNUM(code); switch (menunum) { case 0: /* File Menu */ DoFileMenu(itemnum); break; case 1: /* Settings menu */ switch (itemnum) { case 0: DoBaudRateMenu(subnum); break; case 1: DoParityMenu(subnum); break; case 2: DoByteMenu(subnum); break; } break; case 2: /* Tweak menu */ DoTweakMenu(itemnum); break; } /* switch (menunum) */ } /* switch (class) */ } /* while (newmessage) */ } /* while (keepgoing) */ /* It must be time to quit, so we clean up and exit. */ cleanup(0); } /* * Called when CheckIO() has returned true in main program. * Since this routine has a large impact on throughput, there's * lots of spaghetti and speed optimization -- some of which might * actually work (?). */ Handle_Modem() { unsigned char ch; register struct IOStdReq *request; register unsigned char *cp, *obufp, *top; /* we use Read_Request->IOSer a lot, so cache it in a register */ request = &Read_Request->IOSer; /* complete the read and buffer the character */ WaitIO(Read_Request); obufp = con_out; if ((ch = (ser_in[0] & 0x7F)) && (ch != 0x7F)) { if (debug) *(obufp++) = '|'; *(obufp++) = ch; } /* peek into the serial buffer for more characters */ request->io_Command = SDCMD_QUERY; DoIO(Read_Request); request->io_Command = CMD_READ; /* eager... */ /* got some? if so, copy into the buffer, filtering as we go */ if (request->io_Actual > 0L) { request->io_Length = request->io_Actual; DoIO(Read_Request); top = ser_in + request->io_Actual; for (cp = ser_in; cp < top; cp++) if ((*cp &= 0x7F) && (*cp != 0x7F)) *(obufp++) = *cp; } if (debug) *(obufp++) = '}'; /* requeue read request */ request->io_Length = (ULONG) 1; SendIO(Read_Request); /* put the character(s) on the screen */ consoleWriteMsg->io_Length = (LONG) (obufp - con_out); consoleWriteMsg->io_Data = (APTR) con_out; DoIO(consoleWriteMsg); /* Ascii capture (always slower than not doing it) */ if (capture) for (cp = con_out; cp < obufp; cp++) fputc(*cp, tranr); } /* * Respond to a typed character */ Handle_Char() { GetMsg(consoleReadPort); /* Handle command sequence introducer */ if ((con_in[0] & 0xFF) == 0x9B) { ser_out[0] = 0x1B; DoIO(Write_Request); if (echo) emit(ser_out[0]); con_in[0] = '['; } if (bs_to_del) { if (con_in[0] == '\b') con_in[0] = 0177; else if (con_in[0] == 0177) con_in[0] = '\b'; } ser_out[0] = con_in[0]; /* Requeue read AFTER done with con_in!! */ SendIO(consoleReadMsg); DoIO(Write_Request); if (echo) { emit(ser_out[0]); if (capture) fputc(ser_out[0], tranr); } } /* * Implement File menu commands */ DoFileMenu(ItemNumber) USHORT ItemNumber; { switch( ItemNumber ) { case 0: /* Ascii receive */ if (capture) { capture = FALSE; fclose(tranr); emits("\r\nEnd File Capture\r\n"); } else { emits("\r\nAscii Capture:"); filename(name); if (!strlen(name)) break; if ((tranr = fopen(name,"w")) == NULL) { capture=FALSE; emits("\r\nError Opening File\r\n"); break; } capture = TRUE; } break; case 1: /* Ascii send */ emits("\r\nAscii Send:"); filename(name); if (!strlen(name)) break; emits("\r\nType ESC to abort\r\n"); if ((trans=fopen(name,"r")) == NULL) { emits("\r\nError Opening File\r\n"); break; } Ascii_Send(trans); fclose(trans); emits("\r\nSend completed\r\n"); break; case 2: /* Xmodem recieve */ emits("\r\nXmodem Receive:"); filename(name); if (!strlen(name)) break; if (XMODEM_Read_File(name)) emits("\r\nRecieved File\r\n"); else { close(fd); emits("Xmodem Receive Failed\r\n"); } break; case 3: /* Xmodem send */ emits("\r\nXmodem Send:"); filename(name); if (!strlen(name)) break; if (XMODEM_Send_File(name)) emits("\r\nSent File\r\n"); else { close(fd); emits("\r\nXmodem Send Failed\r\n"); } break; case 4: /* Quit */ KeepGoing = 0; /* Quit after last message*/ break; } /* Switch (file item menu number) */ return (0); } /* DoFileMenu */ /* * Implement BaudRate menu */ DoBaudRateMenu(ItemNumber) USHORT ItemNumber; { AbortIO(Read_Request); Read_Request->io_Baud = baudrates[ItemNumber]; setparams(Read_Request); return (0); } /* DoBaudRateMenu */ /* * Ditto mit der tveek menu... */ DoTweakMenu(ItemNumber) USHORT ItemNumber; { switch(ItemNumber) { case 0: /* BS <-> DEL */ set_toggle(bs_to_del = !bs_to_del,&TWItem[ItemNumber].Flags); break; case 1: /* local echo */ set_toggle(echo = !echo,&TWItem[ItemNumber].Flags); break; case 2: /* auto wrap */ set_toggle(wrap = !wrap,&TWItem[ItemNumber].Flags); emits(wrap ? "\x9B?7h" : "\x9B?7l"); break; case 3: /* newline */ set_toggle(newline = !newline,&TWItem[ItemNumber].Flags); emits(newline ? "\x9b20h" : "\x9b20l"); break; case 4: /* debug */ set_toggle(debug = !debug,&TWItem[ItemNumber].Flags); break; } /* switch */ return (0); } /* * Parity setting menu (wot a gross hack) */ DoParityMenu(ItemNumber) USHORT ItemNumber; { AbortIO(Read_Request); switch(ItemNumber) { case 0: /* none -- clear "parity on" flag */ Read_Request->io_SerFlags &= ~(SERF_PARTY_ON | SERF_PARTY_ODD); break; case 1: /* even parity -- clear ODD bit, turn parity on*/ Read_Request->io_SerFlags |= SERF_PARTY_ON; Read_Request->io_SerFlags &= ~SERF_PARTY_ODD; break; case 2: /* odd -- set ODD bit, turn parity on */ Read_Request->io_SerFlags |= SERF_PARTY_ON | SERF_PARTY_ODD; break; } setparams(Read_Request); /* set 'em, go back to reading */ return 0; } /* DoParityMenu */ /* * Byte length menu */ DoByteMenu(ItemNumber) USHORT ItemNumber; { AbortIO(Read_Request); switch(ItemNumber) { case 0: /* 7 bit bytes */ Read_Request->io_ReadLen = 7; Read_Request->io_WriteLen = 7; break; case 1: /* 8 bit bytes */ Read_Request->io_ReadLen = 8; Read_Request->io_WriteLen = 8; break; } setparams(Read_Request); return 0; } /* DoParityMenu */ /* * Set the CHECKED bit of a MenuItem's Flags field. I suspect * this could be avoided if I understood the MutualExclude field * a little better... */ set_toggle(onoff,flgp) int onoff; USHORT *flgp; { *flgp = onoff ? (*flgp | CHECKED) : (*flgp & ~CHECKED); } /* * Reset the parameters on the serial device, then return * it to "READ" state and queue the next read. */ setparams(Read_Request) struct IOExtSer *Read_Request; { Read_Request->IOSer.io_Command = SDCMD_SETPARAMS; DoIO(Read_Request); /* Reset read_request to read again */ Read_Request->IOSer.io_Command = CMD_READ; SendIO(Read_Request); return (0); } /***************************************************************** * * Initialization And Cleanup * *****************************************************************/ /* * Open windows and Intuition */ OpenUpWindows() { IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", INTUITION_REV); if( IntuitionBase == NULL ) cleanup(ERR_INTUITIONBASE); GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",GRAPHICS_REV); if( GfxBase == NULL ) cleanup(ERR_GFXBASE); if(( mywindow = (struct Window *) OpenWindow(&NewWindow) ) == NULL) cleanup(ERR_NEWWINDOW); } /* * Open serial device and initialize things */ OpenUpSerial() { Read_Request = (struct IOExtSer *) AllocMem(sizeof(*Read_Request),MEMF_PUBLIC|MEMF_CLEAR); if (Read_Request == NULL) cleanup(ERR_ALLOC_READ_REQ); Read_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED; Read_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Read_RS",0); if (Read_Request->IOSer.io_Message.mn_ReplyPort == 0) cleanup(ERR_CRE_READ_PORT); if(OpenDevice(SERIALNAME,NULL,Read_Request,NULL)) cleanup(ERR_OPEN_SER_READ); Read_Request->IOSer.io_Command = CMD_READ; Read_Request->IOSer.io_Length = 1; Read_Request->IOSer.io_Data = (APTR) &ser_in[0]; Write_Request = (struct IOExtSer *) AllocMem(sizeof(*Write_Request),MEMF_PUBLIC|MEMF_CLEAR); if (Write_Request == NULL) cleanup(ERR_ALLOC_WRITE_REQ); Write_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED; Write_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Write_RS",0); if (!Write_Request->IOSer.io_Message.mn_ReplyPort) cleanup(ERR_CRE_WRITE_PORT); if(OpenDevice(SERIALNAME,NULL,Write_Request,NULL)) cleanup(ERR_OPEN_SER_WRITE); Write_Request->IOSer.io_Command = CMD_WRITE; Write_Request->IOSer.io_Length = 1; Write_Request->IOSer.io_Data = (APTR) &ser_out[0]; Read_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED; Read_Request->io_Baud = 1200; Read_Request->io_ReadLen = 8; Read_Request->io_WriteLen = 8; Read_Request->io_StopBits = 1; Read_Request->io_CtlChar = 1L; Read_Request->io_RBufLen = 1024; /* bigger buffer */ Read_Request->IOSer.io_Command = SDCMD_SETPARAMS; DoIO(Read_Request); Read_Request->IOSer.io_Command = CMD_READ; } /* OpenUpSerial() */ /* * Open up console device stuff */ OpenUpConsole() { if ((consoleWritePort = CreatePort("Write_Con",0)) == 0) cleanup(ERR_CRE_CON_WRITE); if ((consoleWriteMsg = CreateStdIO(consoleWritePort)) == 0) cleanup(ERR_CRE_STD_WRITE); if ((consoleReadPort = CreatePort("Read_Con",0)) == 0) cleanup(ERR_CRE_CON_READ); if ((consoleReadMsg = CreateStdIO(consoleReadPort)) == 0) cleanup(ERR_CRE_STD_READ); if (OpenConsoleW(consoleWriteMsg,consoleReadMsg,mywindow)) cleanup(ERR_OPENCONSOLE); consoleWriteMsg->io_Command = CMD_WRITE; consoleReadMsg->io_Command = CMD_READ; consoleReadMsg->io_Data = (APTR) &con_in[0]; consoleReadMsg->io_Length = 1; } /* OpenUpConsole */ /* * Release system resources in the order they were allocated. It's * organized as sort of a jump table so we can 'jump' * into the correct part of the cleanup code. * Things like this are ****REALLY**** dependent on the way code gets * called in the main program, so perhaps a better approach would be to * use a bit mask, one bit for each allocated resource. Maybe even a * number of bit masks, one for each type of resource (menus, windows, * serial, console, etc). */ cleanup(error) int error; { switch (error) { case 0: /* Everything... */ ClearMenuStrip(mywindow); CloseDevice(consoleWriteMsg); case ERR_OPENCONSOLE: DeleteStdIO(consoleReadMsg); case ERR_CRE_STD_READ: DeletePort(consoleReadPort); case ERR_CRE_CON_READ: DeleteStdIO(consoleWriteMsg); case ERR_CRE_STD_WRITE: DeletePort(consoleWritePort); case ERR_CRE_CON_WRITE: CloseDevice(Write_Request); case ERR_CRE_WRITE_PORT: DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort); case ERR_OPEN_SER_WRITE: FreeMem(Write_Request,sizeof(*Write_Request)); case ERR_ALLOC_WRITE_REQ: CloseDevice(Read_Request); case ERR_OPEN_SER_READ: DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort); case ERR_CRE_READ_PORT: FreeMem(Read_Request,sizeof(*Read_Request)); case ERR_ALLOC_READ_REQ: CloseWindow( mywindow ); case ERR_NEWWINDOW: CloseLibrary(GfxBase); case ERR_GFXBASE: CloseLibrary(IntuitionBase); case ERR_INTUITIONBASE: exit(error); break; } exit(error); } /************************************************* * Function to get a string from user. * ignores other events. *************************************************/ filename(name) char name[]; { int keepgoing = TRUE; int i = 0; while (keepgoing) { Wait(TYPED_CHAR); /* ignore other events */ GetMsg(consoleReadPort); /* get character */ switch (con_in[0]) { /* Process it */ case 13: /* Carriage return */ case 10: /* Line feed */ name[i] = '\0'; emit(13); keepgoing = FALSE; break; case 8: /* Backspace */ case 0177: /* Delete */ if (i > 0) { i--; emits("\b \b"); } break; case 24: /* ^X */ case 033: /* ESC */ while ((i > 0) && i--) emits("\b \b"); i = 0; break; default: name[i++] = con_in[0]; emit(con_in[0]); break; } SendIO(consoleReadMsg); /* requeue the read */ } /* while KeepGoing */ return (0); } /***************************************************************** * Send ASCII file * Escape aborts send... * *****************************************************************/ Ascii_Send(file) FILE *file; { int c; while ((c=getc(trans)) != EOF) { /* check for serial or typed character */ if (CheckIO(Read_Request)) Handle_Modem(); if (GetMsg(consoleReadPort)) { SendIO(consoleReadMsg); /* requeue the read */ if (con_in[0] == 033) { emits("File Send Cancelled\r\n"); break; } /* if (con_in) */ } /* if */ sendchar(c); } /* while */ return (0); } /**************************************************************/ /* send char and read char functions for the xmodem function */ /************************************************************/ sendchar(ch) int ch; { ser_out[0] = ch; DoIO(Write_Request); } readchar() { int rd, mask, ch; unsigned char c; rd = FALSE; while (rd == FALSE) { mask = Wait(SERIAL_CHAR | TYPED_CHAR); if (CheckIO(Read_Request) ) { WaitIO(Read_Request); ch = ser_in[0]; rd = TRUE; SendIO(Read_Request); } if (mask & TYPED_CHAR) { GetMsg(consoleReadPort); /* get it */ if (con_in[0] == 033) { emits("\r\nUser Cancelled Transfer\r\n"); break; /* out of loop */ } SendIO(consoleReadMsg); /* requeue read */ } } /* while */ if (!rd) { timeout = TRUE; emits("\r\nTimeout Waiting For Character\r\n"); } c = (char) ch; return ((int) c); } /**************************************/ /* xmodem send and recieve functions */ /************************************/ XMODEM_Read_File(file) char *file; { int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag; unsigned int checksum, j, bufptr, i = 0; char numb[10]; bytes_xferred = 0L; if ((fd = creat(file, 0)) < 0) { emits("Cannot Open File\r\n"); return FALSE; } else emits("Receiving File\r\n"); timeout = FALSE; sectnum = errors = bufptr = 0; sendchar(NAK); firstchar = 0; while (firstchar != EOT && errors != ERRORMAX) { errorflag = FALSE; do { /* get sync char */ firstchar = readchar(); if (timeout == TRUE) return FALSE; } while (firstchar != SOH && firstchar != EOT); if (firstchar == SOH) { emits("Getting Block "); sprintf(numb,"%4d",sectnum); emits(numb); emits("..."); sectcurr = readchar(); if (timeout == TRUE) return FALSE; sectcomp = readchar(); if (timeout == TRUE) return FALSE; if ((sectcurr + sectcomp) == 255) { if (sectcurr == ((sectnum + 1) & 0xff)) { checksum = 0; for (j = bufptr; j < (bufptr + SECSIZ); j++) { capbuf[j] = readchar(); if (timeout == TRUE) return FALSE; checksum = (checksum + capbuf[j]) & 0xff; } if (checksum == readchar()) { errors = 0; sectnum++; bufptr += SECSIZ; bytes_xferred += SECSIZ; emits("verified\r\n"); if (bufptr == BufSize) { bufptr = 0; if (write(fd, capbuf, BufSize) == EOF) { emits("\r\nError Writing File\r\n"); return FALSE; }; }; sendchar(ACK); } else { errorflag = TRUE; if (timeout == TRUE) return FALSE; } } else { if (sectcurr == (sectnum & 0xff)) { emits("\r\nReceived Duplicate Sector\r\n"); sendchar(ACK); } else errorflag = TRUE; } } else errorflag = TRUE; } if (errorflag == TRUE) { errors++; emits("\r\nError\r\n"); sendchar(NAK); } }; /* end while */ if ((firstchar == EOT) && (errors < ERRORMAX)) { sendchar(ACK); write(fd, capbuf, bufptr); close(fd); return TRUE; } return FALSE; } XMODEM_Send_File(file) char *file; { int sectnum, bytes_to_send, size, attempts, c, i = 0; unsigned checksum, j, bufptr; char numb[10]; timeout=FALSE; bytes_xferred = 0; if ((fd = open(file, 1)) < 0) { emits("Cannot Open Send File\r\n"); return FALSE; } else emits("Sending File\r\n"); attempts = 0; sectnum = 1; /* wait for sync char */ j=1; while (((c = readchar()) != NAK) && (j++ < ERRORMAX)); if (j >= (ERRORMAX)) { emits("\r\nReceiver not sending NAKs\r\n"); return FALSE; }; while ((bytes_to_send = read(fd, capbuf, BufSize)) && attempts != RETRYMAX) { if (bytes_to_send == EOF) { emits("\r\nError Reading File\r\n"); return FALSE; }; bufptr = 0; while (bytes_to_send > 0 && attempts != RETRYMAX) { attempts = 0; do { sendchar(SOH); sendchar(sectnum); sendchar(~sectnum); checksum = 0; size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send; bytes_to_send -= size; for (j = bufptr; j < (bufptr + SECSIZ); j++) if (j < (bufptr + size)) { sendchar(capbuf[j]); checksum += capbuf[j]; } else { sendchar(0); } sendchar(checksum & 0xff); attempts++; c = readchar(); if (timeout == TRUE) return FALSE; } while ((c != ACK) && (attempts != RETRYMAX)); bufptr += size; bytes_xferred += size; emits("Block "); sprintf(numb,"%4d",sectnum); emits(numb); emits(" sent\r\n"); sectnum++; } } close(fd); if (attempts == RETRYMAX) { emits("\r\nNo Acknowledgment Of Sector, Aborting\r\n"); return FALSE; } else { attempts = 0; do { sendchar(EOT); attempts++; } while ((readchar() != ACK) && (attempts != RETRYMAX) && (timeout == FALSE)); if (attempts == RETRYMAX) emits("\r\nNo Acknowledgment Of End Of File\r\n"); }; return TRUE; } /************************************************* * Utility functions ************************************************/ /* * function to output ascii chars to window */ emit(c) char c; { consoleWriteMsg->io_Length = 1; consoleWriteMsg->io_Data = (APTR) &c; DoIO(consoleWriteMsg); } /* * function to print a string */ emits(string) char *string; { consoleWriteMsg->io_Data = (APTR) string; consoleWriteMsg->io_Length = -1; DoIO(consoleWriteMsg); } /*****************************************************************/ /* The following function initializes the structure arrays */ /* needed to provide the File menu topic. */ /*****************************************************************/ InitFileItems() { short n; /* initialize each menu item and IntuiText with loop */ for( n=0; n DEL */ TWText[0].IText = (UBYTE *) " BS <-> DEL"; if (bs_to_del) TWItem[0].Flags |= CHECKED; /* Item 1 -- local echo */ TWText[1].IText = (UBYTE *) " Local Echo"; if (echo) TWItem[1].Flags |= CHECKED; /* Item 2 -- auto wrap */ TWText[2].IText = (UBYTE *) " Auto Wrap"; if (wrap) TWItem[2].Flags |= CHECKED; /* Item 3 -- new line -> carriage return + newline */ TWText[3].IText = (UBYTE *) " Newline"; if (newline) TWItem[3].Flags |= CHECKED; /* item 4 -- show throughput (debug) */ TWText[4].IText = (UBYTE *) " Throughput"; if (debug) TWItem[4].Flags |= CHECKED; return( 0 ); } /**********************************************************************/ /* The following function initializes the Menu structure array with */ /* appropriate values for our simple menu strip. Review the manual */ /* if you need to know what each value means. */ /**********************************************************************/ InitMenu() { /* File menu */ menu[0].NextMenu = &menu[1]; menu[0].LeftEdge = 5; menu[0].TopEdge = 0; menu[0].Width = 50; menu[0].Height = 10; menu[0].Flags = MENUENABLED; menu[0].MenuName = "File"; menu[0].FirstItem = &FileItem[0]; /* Settings menu */ menu[1].NextMenu = &menu[2]; menu[1].LeftEdge = 2 + menu[0].Width + menu[0].LeftEdge; menu[1].TopEdge = 0; menu[1].Width = 76; menu[1].Height = 10; menu[1].Flags = MENUENABLED; menu[1].MenuName = "Settings"; menu[1].FirstItem = &SetItem[0]; /* Tweak menu */ menu[2].NextMenu = NULL; menu[2].LeftEdge = 2 + menu[1].Width + menu[1].LeftEdge; menu[2].TopEdge = 0; menu[2].Width = 60; menu[2].Height = 10; menu[2].Flags = MENUENABLED; menu[2].MenuName = "Prefs"; menu[2].FirstItem = &TWItem[0]; return( 0 ); } /* * Open up a console device for writing only */ OpenConsoleW(writerequest,readrequest,window) struct IOStdReq *writerequest, *readrequest; struct Window *window; { int error; writerequest->io_Data = (APTR) window; writerequest->io_Length = sizeof(*window); error = OpenDevice("console.device",0,writerequest,0); readrequest->io_Device = writerequest->io_Device; readrequest->io_Unit = writerequest->io_Unit; return (error); }