ek@tilt.FUN (Eleftherios Koutsofios) (04/13/86)
I saw a couple of postings this last week, about having a terminal emulator that can speak as well as print incomming text. I had the same idea some time ago, so I modified the terminal program that I use, to include that. The following is a terminal emulation program for the amiga. Its features are: ANSI protocol (25 lines x 80 columns) XMODEM file transfer graphics mode, where you can draw something on the amiga from a host machine. speech mode, where you can have the amiga speak as well as print incomming text. Since I only got my ROM Kernel Manuals this week, I had to play with other peoples' programs, to do what I wanted. This is the reason why the source looks a bit strange. It consists of parts from other programs. So, please, no comments on style :-). The program is far from finished. There are many more options that can be added. Maybe you can help. This program compiles and links under the Lattice 3.02 C. If you have any problems, send me mail. ------ Lefteris Koutsofios (princeton!tilt!ek) ------ #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # makefile # term.c # gr.c # speech.c # termcap # say.c # This archive created: Sun Apr 13 04:22:20 1986 export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(7880 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' term - a terminal emulator. A few comments -------------- The files term.c gr.c and speech.c contain the sources for a terminal emulator for the amiga. This terminal emulator has several features. This a sort description: 1) ANSI protocol. This terminal uses the amiga's ANSI capabilities (see Developer's manual for details). It gives you 25 lines by 80 columns. A unix termcap entry can be found in the file termcap (in this posting). It assumes 1200 baud and it has no problem of keeping up with this rate (it does buffered I/O, in that it doesn't print anything, as long as the host keeps sending). 2) XMODEM file transfer. You can send a file to a host or get one from the host using the XMODEM protocol. It works ok, and I have seen it recovering from line noise. I have only tried it with text files (not with binaries). 3) Graphics. You can get a picture from your host to your amiga. You need of course a program on the host to send the appropriate sequences. The program understands only 3 commands: set color, draw line, and terminate :-). There are many more that can be added (most notably mouse commands). In fact what I use has one more command: draw polygon (possibly filled). The reason I have removed it is that the source I used for that belongs to Princeton University. I guess you can add your own code (I have left the part of the source that understands the polygon command, so all you need to do is add your own. See function Graphics at the end of file term.c). The reason I didn't do it yet, is because my source does some clipping and I don't know how to do this yet (remember I just got my manuals and they are BIG! :-)). The program as it is assumes high resolution - interlaced mode (640 x 400) pixels. 4) Speech. Well, the speech option is simple: it 'reads out loud' everything between a control A and the first non-printable character. So, to make it read a file, preceed every line by a control A. You can switch the speech option on and off. What I really like is to play hack with this!! It's fun! To do this instead of the the amiga entry, use the amiga-s entry. Then you will get to hear things like: you hit the kobolt, or you die!! It slows down the game but its fun, and you can always turn the speech option off. I have included a file called say.c that you can install on your host and then use it to make your amiga talk. How to use the program ---------------------- To create the executable do a cc term.c gr.c speech.c -o term, or use the makefile supplied. Under Lattice 3.02 everything should work ok, (but you will of course get the usual warnings!! :-) ). To run the program type term (or whatever you want to call it). The program should start by opening a window, with no borders. The borders are there, but by printing the appropriate escapes I get to use the whole screen for text. The prompt term: should appear. You are in the offline mode. press the help key to get a listing of all the commands. Type on. You are now in the online mode. If everything is ok, you should now be able to talk to whatever is at the other end of the serial port. To return to the offline mode, press the function key 7 (don't ask why 7, I don't have a logical explanation :-)). You should get an offline message, but note that this is temporary. You can only execute one command on the amiga, then the program will automatically return you to the online mode. This is useful for executing commands like sb or rb that transfer files. To stay to the offline mode type off. To exit the program, first get to offline mode (f7 then type off) and then type end. You should note that you can give any command from offline. The program 'executes' them (this of course does not work with cd). There is one bug, in that the program may crash when you try to go to offline mode, but this happens very very rarely. To use the XMODEM commands, get to online mode, give the appropriate command to your host, then press f7 and give the corresponding command to the amiga. So, if say that you want to send something to the host, get to online, type rb filename, then press f7 and type sb df1:filename or whatever. The program should then start transfering your file. At the same time it will print a count of blocks transfered. You do need of course XMODEM commands on your host. There are a couple of bugs. When receiving a file, the last line contains garbage. You need to edit the file and remove it. When sending a file, the file contains some nulls. If your host runs unix, just enter vi and do a w!. The graphics option works like this: to draw a picture on the amiga, first send an escape G. This gets you in graphics mode. Everything that comes after this must be a graphics sequence. The implemented sequences are: T0 which exits the graphics mode, C %d %d %d %d\n that sets the color (C pennum r g b, where pennum the pen number, and r g b the rgb coefficients), and L %d %d %d %d %d\n to draw a line (L x1 y1 x2 y2 pennum, where pennum the pen number). The parser understands also the command P %d %d %d %d %d %d %d\n that draws a polygon possibly filled (P num_of_points pennum clip xmin ymin xmax ymax, where clip is a flag of whether to clip or not and xmin .. are the clip boundaries). After this command you must supply the points on the polygon, each on a separate line (%d %d\n. I didn't include the source for this routine, for the reasons I mentioned before. When the escG is received the program opens a screen (640 x 400), and starts drawing on it according to the incomming commands. When it finishes, the menu strip that wasn't visible up to now comes up. To return to the text window, drag this screen down or send it back. What I chose to do is not to delete the screen when it finishes. Instead it stays around until you try to end the program. This way you can keep your picture for as long as you want, and maybe print it out using a screen dump program that was posted some time ago. If you want draw a new picture however, and since I forgot to add a clear screen command :-), you must go to offline mode and type gfxoff which will delete the screen. If while in graphics mode you want to abort the drawing, press the menu button on the mouse and then select the quit option from the menu. The menu still works even when not visible. Then get back to the text screen and do whatever necessary to stop the host from sending the graphics sequences. Since the program does handshaking you'll probably need to press control Q first, to get your host to continue. You should make sure that the host sends the correct sequences, although a character out of place (line noise) will usually destroy just a small part of the picture. (My problem is that the graphics packages I use initialize the screen even when I give a command like: foo | amiga, where amiga is my filter and foo is a non-existent command. In this case the program will hung. The sound option is easy. Just preceed everything you want 'read' by a control A. Acknowledgments --------------- As I mentioned before, this program uses parts (and bugs :-)) from a few other programs. The basic program comes from the myCLI program of Mike Schwartz. I modified that to get a 25 x 80 screen. I then added the XMODEM transfer routines that were posted by Michael Mounier, as part of his terminal program. I used the sparks demo by Scott Ballantyne to get an idea of how the graphics work. Finally I used Rob Peck's program speech, to add the speech option. Thanks for the help! (If only it hadn't taken Commodore all these months to give me my manuals! :-( ). SHAR_EOF if test 7880 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 7880 characters)' fi fi # end of overwriting check echo shar: extracting "'makefile'" '(146 characters)' if test -f 'makefile' then echo shar: will not over-write existing file "'makefile'" else cat << \SHAR_EOF > 'makefile' term : term.o gr.o speech.o cc term.o gr.o speech.o term.o : term.c cc -c term.c gr.o : gr.c cc -c gr.c speech.o : speech.c cc -c speech.c SHAR_EOF if test 146 -ne "`wc -c < 'makefile'`" then echo shar: error transmitting "'makefile'" '(should have been 146 characters)' fi fi # end of overwriting check echo shar: extracting "'term.c'" '(21608 characters)' if test -f 'term.c' then echo shar: will not over-write existing file "'term.c'" else cat << \SHAR_EOF > 'term.c' #include <stdio.h> #include <exec/types.h> #include <exec/exec.h> #include <libraries/dos.h> #include <libraries/dosextens.h> #include <devices/serial.h> #define MAX_CHARS 102 #define SECSIZ 0x80 #define TTIME 30 #define BufSize 0x1000 #define ERRORMAX 10 #define RETRYMAX 10 #define SOH 1 #define EOT 4 #define ACK 6 #define CTRLQ (char)17 #define CTRLS (char)19 #define NAK 21 static char bufr[BufSize]; static int fd, timeout = FALSE; static long bytes_xferred; static int oktosay = 1; /* * External functions */ extern unsigned char *stpblk(); extern unsigned char *AllocMem(); extern struct MsgPort *CreatePort(); extern struct FileHandle *Open(); /* * forward references */ int define_function_key(), end(), help(), offline(), online(), sb(), rb(), gfxoff(), speechon(), speechoff(); /* * Tables */ struct { unsigned char *cmdname; int (*cmdfunc)(); } command_table[] = { (unsigned char *)"define", &define_function_key, (unsigned char *)"def", &define_function_key, (unsigned char *)"end", &end, (unsigned char *)"help", &help, (unsigned char *)"online", &online, (unsigned char *)"on", &online, (unsigned char *)"offline", &offline, (unsigned char *)"off", &offline, (unsigned char *)"gfxoff", &gfxoff, (unsigned char *)"sb", &sb, (unsigned char *)"rb", &rb, (unsigned char *)"speechon", &speechon, (unsigned char *)"speechoff", &speechoff, (unsigned char *)"\0", &help, }; unsigned char *help_messages[] = { "sb = send file using Xmodem", "rb = receive file using Xmodem", "def = define a function key", "define = define a function key", "end = exit the program", "help = print this list", "online = enter or re-enter terminal mode", "offline = terminate communication", "gfxoff = terminate graphics", "speechon = permit speech", "speechoff = forbid speech", 0}; unsigned char *function_key_definitions[20] = { 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0 }; /* * Globals */ unsigned char work[512]; unsigned char buf[512]; unsigned char iobuf[1024]; int num_of_chars, no_io; /* * Terminal globals */ struct FileHandle *terminal_infp; struct FileHandle *terminal_outfp; /* * Terminal emulator stuff */ struct Message *mymessage; struct IOExtSer *ModemReadRequest; struct IOExtSer *ModemWriteRequest; unsigned char *WelcomeMessage = "Entering Terminal Mode\nUse ^C for command mode\n"; unsigned char *GoodbyeMessage = "Disconnected\n"; unsigned char *OfflineMessage = "--- Offline ---\n"; unsigned char *OnlineMessage = "--- Online ---\n"; unsigned char rs_in[2], rs_out[2]; int bdoneflag = 0; int TermEcho = 0; int modem_online = 0; static int gfx_flag; main(argc, argv) int argc; unsigned char *argv[]; { gfx_flag = 0; num_of_chars = 0; no_io = 0; sprintf(work, "Raw:0/0/640/200/Terminal"); terminal_infp = Open(work, MODE_NEWFILE); if (terminal_infp == 0) { printf("Can't open window\n"); exit(1); } terminal_outfp = terminal_infp; sprintf(work, "\033[0x\033[0y\033[25t\033[80u\014"); WriteWork(); while (1) { Write(terminal_outfp, "\033[7mterm:\033[m ", 13); getcommand(buf); CommandInterpreter(buf); } } WriteWork() { Write(terminal_outfp, work, strlen(work)); } CommandInterpreter(command) unsigned char *command; { int i; command = stpblk(command); /* * Scan through the command table for the string and invoke the function * to do the actual work of the command. Each of these commands is * defined below, and the functions each take a pointer to the * string containing the arguments passed the command line. */ for (i=0; command_table[i].cmdname[0] != '\0'; i++) if (strncmp(command, command_table[i].cmdname, strlen(command_table[i].cmdname)) == 0) { (*command_table[i].cmdfunc) (stpblk(&command[strlen(command_table[i].cmdname)])); goto FinishedCommand; } /* * Not found, so look for it on the disk. */ executive(stpblk(&command[0])); FinishedCommand: } executive(s) unsigned char *s; { if (!Execute(s, 0, terminal_outfp)) printf("%d\n", IoErr()); } define_function_key(s) unsigned char *s; { int i; if (s[0] == '\0') for (i=0; i<20; i++) { if (function_key_definitions[i]) { sprintf(work, "F%-2d = %s\n", i+1, function_key_definitions[i]); WriteWork(); } } else if (s[0] == 'f' || s[0] == 'F') { s++; i = atoi(s); if (i < 1 || i > 20) { sprintf(work, "%c[36mInvalid function key%c[0m\n", 0x1b, 0x1b); WriteWork(); } else { i--; if (function_key_definitions[i]) FreeMem(function_key_definitions[i], strlen(function_key_definitions[i])+1); while (isdigit(*s)) s++; s = stpblk(s); if (*s != '\0') { function_key_definitions[i] = AllocMem(strlen(s)+1, MEMF_PUBLIC|MEMF_CLEAR); if (function_key_definitions[i] == 0) { sprintf(work, "%c[36mDefine Error: not enough memory%c[0m\n", 0x1b, 0x1b); WriteWork(); } else strcpy(function_key_definitions[i], s); } } } else { sprintf(work, "%c[36mDefine Error: invalid function key specified%c[0m\n", 0x1b, 0x1b); WriteWork(); } } end(s) unsigned char *s; { if (modem_online) { sprintf(work, "%c[36mTerminal Mode Error: Modem still online%c[0m\n", 0x1b, 0x1b); WriteWork(); } else { if (gfx_flag == 1) terminate(); Close(terminal_outfp); exit(0); } } help(s) unsigned char *s; { int i; sprintf(work,"%c[7m MyCli Help %c[0m\n", 0x1b, 0x1b); WriteWork(); for (i=0; help_messages[i]; i++) { sprintf(work, "%s\n", help_messages[i]); WriteWork(); } sprintf(work, "%c[7m End of Help %c[0m\n", 0x1b, 0x1b); WriteWork(); } gfxoff() { if (gfx_flag == 1) terminate(); gfx_flag = 0; } speechon() { oktosay = 1; } speechoff() { oktosay = 0; } offline(s) unsigned char *s; { modem_online = 0; say_string((char*)0, 1); } online(s) unsigned char *s; { modem_online = !0; /* signal that modem is live !!! */ if (initialize()) { /* set baud rate, etc. */ Write(terminal_outfp, WelcomeMessage, strlen(WelcomeMessage)); while (modem_online) { bdoneflag = 0; /* terminal mode on flag */ Write(terminal_outfp, OnlineMessage, strlen(OnlineMessage)); while (!bdoneflag) { check_keyboard(); check_modem(); if (bdoneflag || num_of_chars > MAX_CHARS || no_io > 0) { if (num_of_chars > 0) { Write(terminal_outfp, iobuf, num_of_chars); num_of_chars = 0; } } } Write(terminal_outfp, OfflineMessage, strlen(OfflineMessage)); Write(terminal_outfp, "\033[7mterm:\033[m ", 13); getcommand(buf); CommandInterpreter(buf); } cleanup(); } modem_online = 0; } getcommand(s) unsigned char *s; { unsigned char c; unsigned col; col = 0; while (1) { Read(terminal_infp, &c, 1); switch(c) { case 8: if (col) { c = 8; Write(terminal_outfp, &c, 1); c = ' '; Write(terminal_outfp, &c, 1); c = 8; Write(terminal_outfp, &c, 1); col--; } continue; case 10: case 13: sprintf(work, "\n"); WriteWork(); s[col++] = '\0'; break; case 0x1b: case 24: while (col) { c = 8; Write(terminal_outfp, &c, 1); c = ' '; Write(terminal_outfp, &c, 1); c = 8; Write(terminal_outfp, &c, 1); col--; } continue; case 0x9b: if (process_event(&s[col])) { strcat(s, "\n"); Write(terminal_outfp, &s[col], strlen(&s[col])); break; } continue; default: s[col++] = c; Write(terminal_outfp, &c, 1); continue; } break; } } /* * this function converts an incoming ANSI escape sequence * and processes it. A buffer is passed where any function * key expansion is to take place. If the buffer is modified * for any reason, this function returns true. */ process_event(cmd_line) unsigned char *cmd_line; { int i; unsigned char c; char event_buffer[32]; i = 0; while (1) { Read(terminal_infp, &c, 1); event_buffer[i] = c; if (c == '~' || c == '|' || c == 'A' || c == 'B' || c == 'C' || c == 'D') break; i++; } event_buffer[i+1] = '\0'; if (event_buffer[i] == '~') { if (event_buffer[0] == '?') { strcpy(cmd_line, "help"); return !0; } else if (isdigit(event_buffer[0])) { if (function_key(atoi(event_buffer), cmd_line)) return !0; else if (atoi(event_buffer) == 6) bdoneflag = !0; } } else if (i == 0 && (event_buffer[0] >= 'A' && event_buffer[0] <= 'D')) { cmd_line[0] = '\033'; cmd_line[1] = event_buffer[0]; cmd_line[2] = '\000'; return !0; } return 0; } /* * if a definition for the function key fkey exists (0-19), then * the translation for the function key is copied to the string * s, and this function returns !0. Otherwise, now translation * exists, and this function returns 0. */ function_key(fkey, s) int fkey; unsigned char *s; { int i; if (function_key_definitions[fkey] != 0) { for (i=0; function_key_definitions[fkey][i] != '\0'; i++) s[i] = function_key_definitions[fkey][i]; s[i] = '\0'; return !0; } return 0; } initialize() { ModemReadRequest = (struct IOExtSer *)AllocMem(sizeof(*ModemReadRequest), MEMF_PUBLIC | MEMF_CLEAR); ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED; ModemReadRequest->IOSer.io_Message.mn_ReplyPort = CreatePort("Read_RS",0); if (OpenDevice(SERIALNAME, NULL, ModemReadRequest, NULL)) { sprintf(work, "%c[36mCan't open serial read device%c[0m\n", 0x1b, 0x1b); WriteWork(); DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemReadRequest, sizeof(*ModemReadRequest)); return 0; } ModemReadRequest->IOSer.io_Command = CMD_READ; ModemReadRequest->IOSer.io_Length = 1; ModemReadRequest->IOSer.io_Data = (APTR) &rs_in[0]; ModemWriteRequest = (struct IOExtSer *)AllocMem(sizeof(*ModemWriteRequest), MEMF_PUBLIC | MEMF_CLEAR); ModemWriteRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED; ModemWriteRequest->IOSer.io_Message.mn_ReplyPort = CreatePort("Write_RS",0); if (OpenDevice(SERIALNAME, NULL, ModemWriteRequest, NULL)) { sprintf(work, "%c[36mCan't open serial write device%c[0m\n", 0x1b, 0x1b); WriteWork(); DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemReadRequest, sizeof(*ModemReadRequest)); DeletePort(ModemWriteRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemWriteRequest, sizeof(*ModemWriteRequest)); return 0; } ModemWriteRequest->IOSer.io_Command = CMD_WRITE; ModemWriteRequest->IOSer.io_Length = 1; ModemWriteRequest->IOSer.io_Data = (APTR) &rs_out[0]; ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED; ModemReadRequest->io_Baud = 1200; ModemReadRequest->io_ReadLen = 8; ModemReadRequest->io_WriteLen = 8; ModemReadRequest->io_CtlChar = 1L; ModemReadRequest->IOSer.io_Command = SDCMD_SETPARAMS; DoIO(ModemReadRequest); ModemReadRequest->IOSer.io_Command = CMD_READ; BeginIO(ModemReadRequest); return !0; } cleanup() { CloseDevice(ModemReadRequest); DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemReadRequest, sizeof(*ModemReadRequest)); CloseDevice(ModemWriteRequest); DeletePort(ModemWriteRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemWriteRequest, sizeof(*ModemWriteRequest)); Write(terminal_outfp, GoodbyeMessage, strlen(GoodbyeMessage)); } check_keyboard() { unsigned char *pc; if (WaitForChar(terminal_infp, 1)) { Read(terminal_infp, &rs_out[0], 1); switch ((unsigned char)rs_out[0]) { case 0x9b: /* ANSI keyboard stuff */ if (process_event(&buf[0])) { /* send the translation */ pc = &buf[0]; while (*pc != '\0') { rs_out[0] = *pc++; if (TermEcho) Write(terminal_outfp, &rs_out[0], 1); DoIO(ModemWriteRequest); check_modem(); } } break; case 0x05: /* toggle keystroke echo */ TermEcho = !TermEcho; sprintf(work, "%c[36mEcho %s%c[0m\n", 0x1b, TermEcho?"ON":"OFF", 0x1b); WriteWork(); break; default: if (TermEcho) Write(terminal_outfp, &rs_out[0], 1); DoIO(ModemWriteRequest); } } } /* * Check to see if the Read Request IO has completed from the modem. */ check_modem() { static int sayflag = 0; static char saystring[133]; static int sayind = 0; static int escape_sequence = 0; if (CheckIO(ModemReadRequest)) { WaitIO(ModemReadRequest); rs_in[0] &= 0x7f; if (rs_in[0] == '\001' && oktosay == 1) { sayflag = 1; BeginIO(ModemReadRequest); return; } if (oktosay == 1 && sayflag) { if (rs_in[0] >= ' ' && rs_in[0] < (char)127) { saystring[sayind++] = rs_in[0]; } else { Write(terminal_outfp, iobuf, num_of_chars); rs_out[0] = CTRLS; DoIO(ModemWriteRequest); num_of_chars = 0; saystring[sayind++] = (char)0; say_string(saystring,0); sayind = 0; sayflag = 0; rs_out[0] = CTRLQ; DoIO(ModemWriteRequest); } } if (rs_in[0] == '\033') { escape_sequence = 1; } else if (escape_sequence == 1) { if (rs_in[0] == 'G') { Graphics(); } else { iobuf[num_of_chars++] = '\033'; iobuf[num_of_chars++] = rs_in[0]; no_io = 0; } escape_sequence = 0; } else { iobuf[num_of_chars++] = rs_in[0]; no_io = 0; } BeginIO(ModemReadRequest); } else { no_io++; } } sendchar(ch) int ch; { rs_out[0] = ch; DoIO(ModemWriteRequest); } readchar() { unsigned char c; int rd,ch; rd = FALSE; while (rd == FALSE) { if(CheckIO(ModemReadRequest)) { WaitIO(ModemReadRequest); ch=rs_in[0]; rd = TRUE; BeginIO(ModemReadRequest); } } if (rd == FALSE) { timeout = TRUE; emits("\nTimeout Waiting For Character\n"); } c = ch; return(c); } rb(file) char *file; { int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag; unsigned int checksum, j, bufptr,i; char numb[10]; bytes_xferred = 0L; i = 10; if ((fd = creat(file, 0)) < 0) { emits("Cannot Open File\n"); return FALSE; } else emits("Receiving File\n"); timeout=FALSE; sectnum = errors = bufptr = 0; sendchar(NAK); firstchar = 0; while (firstchar != EOT && errors != ERRORMAX) { errorflag = FALSE; do { firstchar = readchar(); if (timeout == TRUE) return FALSE; } while (firstchar != SOH && firstchar != EOT); if (firstchar == SOH) { emits("Getting Block "); stci_d(numb,sectnum,i); 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++) { bufr[j] = readchar(); if (timeout == TRUE) return FALSE; checksum = (checksum + bufr[j]) & 0xff; } if (checksum == readchar()) { errors = 0; sectnum++; bufptr += SECSIZ; bytes_xferred += SECSIZ; emits("verified\n"); if (bufptr == BufSize) { bufptr = 0; if (write(fd, bufr, BufSize) == EOF) { emits("\nError Writing File\n"); return FALSE; }; }; sendchar(ACK); } else { errorflag = TRUE; if (timeout == TRUE) return FALSE; } } else { if (sectcurr == (sectnum & 0xff)) { emits("\nReceived Duplicate Sector\n"); sendchar(ACK); } else errorflag = TRUE; } } else errorflag = TRUE; } if (errorflag == TRUE) { errors++; emits("\nError\n"); sendchar(NAK); } }; if ((firstchar == EOT) && (errors < ERRORMAX)) { sendchar(ACK); write(fd, bufr, bufptr); write(fd, "\n", 1); close(fd); return TRUE; } return FALSE; } sb(file) char *file; { int sectnum, bytes_to_send, size, attempts, c, i; unsigned checksum, j, bufptr; char numb[10]; timeout=FALSE; bytes_xferred = 0; i = 10; if ((fd = open(file, 1)) < 0) { emits("Cannot Open Send File\n"); return FALSE; } else emits("Sending File\n"); attempts = 0; sectnum = 1; j=1; while (((c = readchar()) != NAK) && (j++ < ERRORMAX)); if (j >= (ERRORMAX)) { emits("\nReceiver not sending NAKs\n"); return FALSE; }; while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX) { if (bytes_to_send == EOF) { emits("\nError Reading File\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(bufr[j]); checksum += bufr[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 "); stci_d(numb,sectnum,i); emits(numb); emits(" sent\n"); sectnum++; } } close(fd); if (attempts == RETRYMAX) { emits("\nNo Acknowledgment Of Sector, Aborting\n"); return FALSE; } else { attempts = 0; do { sendchar(EOT); attempts++; } while ((readchar() != ACK) && (attempts != RETRYMAX) && (timeout == FALSE)); if (attempts == RETRYMAX) emits("\nNo Acknowledgment Of End Of File\n"); }; return TRUE; } emits(embuf) char *embuf; { Write(terminal_outfp, embuf, strlen(embuf)); } Graphics() { char buf[82], *gr_buf; int gr_len, r, g, b, color, x1, y1, x2, y2; int polx[256], poly[256], n, clip, xmin, ymin, xmax, ymax; int i; if (gfx_flag == 0) { gfx_flag = 1; initialise(); } else get_screen(); rs_out[0] = CTRLS; DoIO(ModemWriteRequest); BeginIO(ModemReadRequest); for(;;) { gr_len = 0; buf[0] = (char)0; gr_buf = &(buf[1]); while(gr_buf[gr_len-1] != '\015') { if (CheckIO(ModemReadRequest)) { WaitIO(ModemReadRequest); rs_in[0] &= 0x7f; if (rs_in[0] != '\012') { gr_buf[gr_len++] = rs_in[0]; } BeginIO(ModemReadRequest); } else { rs_out[0] = CTRLQ; DoIO(ModemWriteRequest); } } rs_out[0] = CTRLS; DoIO(ModemWriteRequest); gr_buf[gr_len-1] = (char)0; switch (gr_buf[0]) { case 'T': /* terminate(); */ put_screen(); rs_out[0] = CTRLQ; DoIO(ModemWriteRequest); return; case 'C': sscanf(&(gr_buf[1]), "%d%d%d%d", &color, &r, &g, &b); define_color(color, r, g, b); if (check_user_action() == -1) { put_screen(); return; } break; case 'L': sscanf(&(gr_buf[1]), "%d%d%d%d%d", &x1, &y1, &x2, &y2, &color); draw(x1, y1, x2, y2, color); if (check_user_action() == -1) { put_screen(); return; } break; case 'P': sscanf(&(gr_buf[1]), "%d%d%d%d%d%d%d", &n, &color, &clip, &xmin, &ymin, &xmax, &ymax); for (i=0; i<n; i++) { gr_len = 0; buf[0] = (char)0; gr_buf = &(buf[1]); while(gr_buf[gr_len-1] != '\015') { if (CheckIO(ModemReadRequest)) { WaitIO(ModemReadRequest); rs_in[0] &= 0x7f; if (rs_in[0] != '\012') { gr_buf[gr_len++] = rs_in[0]; } BeginIO(ModemReadRequest); } else { rs_out[0] = CTRLQ; DoIO(ModemWriteRequest); } } gr_buf[gr_len-1] = (char)0; sscanf(gr_buf,"%d%d", &(polx[i]), &(poly[i])); } rs_out[0] = CTRLS; DoIO(ModemWriteRequest); /* poly_draw(polx, poly, n, color, clip, xmin, ymin, xmax, ymax); */ if (check_user_action() == -1) { put_screen(); return; } break; } } } SHAR_EOF if test 21608 -ne "`wc -c < 'term.c'`" then echo shar: error transmitting "'term.c'" '(should have been 21608 characters)' fi fi # end of overwriting check echo shar: extracting "'gr.c'" '(5005 characters)' if test -f 'gr.c' then echo shar: will not over-write existing file "'gr.c'" else cat << \SHAR_EOF > 'gr.c' #include <exec/types.h> #include <exec/exec.h> #include <exec/execbase.h> #include <hardware/blit.h> #include <graphics/copper.h> #include <graphics/regions.h> #include <graphics/rastport.h> #include <graphics/gfxbase.h> #include <graphics/gfxmacros.h> #include <graphics/gels.h> #include <graphics/display.h> #include <intuition/intuition.h> struct IntuitionBase *IntuitionBase = NULL; struct GfxBase *GfxBase = NULL; #define MAXX 640 struct NewScreen MyScreen = { 0,0,MAXX,400,4,0,1,HIRES | INTERLACE, CUSTOMSCREEN, NULL, "Graphics", 0,0,}; struct NewWindow DrawWindow = { 0,0,MAXX,400, 0,1, MENUPICK, BORDERLESS | BACKDROP | ACTIVATE, NULL, NULL, NULL, NULL, NULL, 0,0,0,0, CUSTOMSCREEN, }; struct Screen *Screen = NULL; struct Window *Backdrop = NULL; struct RastPort *DrawRP; struct ViewPort *DrawVP; struct IntuiMessage *message; struct MenuItem OnlyMenuItems[3]; struct IntuiText OnlyMenuText[3]; struct Menu OnlyMenu[1]; #define MAXLINES 125 #define ERASE 0 initialise() { if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))) exit(1); if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) { cleanitup(); exit(2); } if(!(Screen = (struct Screen *)OpenScreen(&MyScreen))) { cleanitup(); exit(3); } DrawWindow.Screen = Screen; if(!(Backdrop = (struct Window *)OpenWindow(&DrawWindow))) { cleanitup(); exit(4); } DrawRP = Backdrop->RPort; /* Draw into backdrop window */ DrawVP = &Screen->ViewPort; /* Set colors in Screens VP */ initmenuitems(); initmenu(); SetMenuStrip(Backdrop, &OnlyMenu[0]); ShowTitle(Screen,FALSE); define_color( 0, 0, 0, 0); define_color( 1, 15, 15, 15); define_color( 2, 15, 0, 0); define_color( 3, 7, 0, 0); define_color( 4, 0, 15, 0); define_color( 5, 0, 7, 0); define_color( 6, 0, 0, 15); define_color( 7, 0, 0, 7); define_color( 8, 15, 15, 0); define_color( 9, 7, 7, 0); define_color(10, 15, 0, 15); define_color(11, 7, 0, 7); define_color(12, 0, 15, 15); define_color(13, 0, 7, 7); define_color(14, 7, 7, 7); define_color(15, 3, 3, 3); } terminate() { ShowTitle(Screen,TRUE); /* while(check_user_action() != -1); */ cleanitup(); } cleanitup() /* release allocated resources */ { if (Backdrop) CloseWindow(Backdrop); if (Screen) CloseScreen(Screen); if (GfxBase) CloseLibrary(GfxBase); if (IntuitionBase) CloseLibrary(IntuitionBase); } draw(x1, y1, x2, y2, color) int x1, x2; int y1, y2; BYTE color; { SetAPen(DrawRP, color); SetDrMd(DrawRP, JAM1); Move(DrawRP, x1, y1); Draw(DrawRP, x2, y2); } define_color(color, r, g, b) int color, r, g, b; { SetRGB4(DrawVP, color, r, g, b); } initmenuitems() { short n; for(n = 0; n < 3; n++) { /* One struct for each item */ OnlyMenuItems[n].NextItem = &OnlyMenuItems[n + 1]; /* next item */ OnlyMenuItems[n].LeftEdge = 0; OnlyMenuItems[n].TopEdge = 10 * n; OnlyMenuItems[n].Width = 112; OnlyMenuItems[n].Height = 10; OnlyMenuItems[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP; OnlyMenuItems[n].MutualExclude = 0; OnlyMenuItems[n].ItemFill = (APTR)&OnlyMenuText[n]; OnlyMenuItems[n].SelectFill = NULL; OnlyMenuItems[n].Command = 0; OnlyMenuItems[n].SubItem = NULL; OnlyMenuItems[n].NextSelect = 0; OnlyMenuText[n].FrontPen = 0; OnlyMenuText[n].BackPen = 1; OnlyMenuText[n].DrawMode = JAM2; OnlyMenuText[n].LeftEdge = 0; OnlyMenuText[n].TopEdge = 1; OnlyMenuText[n].ITextFont = NULL; OnlyMenuText[n].NextText = NULL; } OnlyMenuItems[2].NextItem = NULL; /* Last item */ OnlyMenuText[0].IText = (UBYTE *)"Hide Title Bar"; OnlyMenuText[1].IText = (UBYTE *)"Show Title Bar"; OnlyMenuText[2].IText = (UBYTE *)"QUIT!"; } initmenu() { OnlyMenu[0].NextMenu = NULL; /* No more menus */ OnlyMenu[0].LeftEdge = 0; OnlyMenu[0].TopEdge = 0; OnlyMenu[0].Width = 85; OnlyMenu[0].Height = 10; OnlyMenu[0].Flags = MENUENABLED; /* All items selectable */ OnlyMenu[0].MenuName = "Actions"; OnlyMenu[0].FirstItem = &OnlyMenuItems[0]; /* Pointer to first item */ } check_user_action() { ULONG class; USHORT code, ItemNum; int action; action = 0; while(message = (struct IntuiMessage *)GetMsg(Backdrop->UserPort)) { class = message->Class; code = message->Code; ReplyMsg(message); if (class == MENUPICK && code != MENUNULL) { ItemNum = ITEMNUM( code ); switch (ItemNum) { case 0: ShowTitle(Screen, FALSE); break; case 1: ShowTitle(Screen, TRUE); break; case 2: /* ClearMenuStrip(Backdrop); */ action = -1; return(action); } } } return (action); } put_screen() { /* ScreenToBack(Screen); */ ShowTitle(Screen,TRUE); } get_screen() { ScreenToFront(Screen); ShowTitle(Screen,TRUE); } SHAR_EOF if test 5005 -ne "`wc -c < 'gr.c'`" then echo shar: error transmitting "'gr.c'" '(should have been 5005 characters)' fi fi # end of overwriting check echo shar: extracting "'speech.c'" '(8123 characters)' if test -f 'speech.c' then echo shar: will not over-write existing file "'speech.c'" else cat << \SHAR_EOF > 'speech.c' /* Here is a sample speech demo program that compiles on * Amiga (Lattice) C. It can be thought of as a stripped * down version of the speechtoy (lucas). I haven't * provided the graphics for the drawing of the mouth, * but the access to the mouth variables is shown here. * * It is the sample program from the rev 1.1 ROM KERNEL * manual, now at the printers. * * Rob Peck. * * This code may be freely utilized to create programs for the Amiga. */ #include "exec/types.h" #include "exec/exec.h" #include "exec/nodes.h" #include "exec/lists.h" #include "exec/memory.h" #include "exec/interrupts.h" #include "exec/ports.h" #include "exec/libraries.h" #include "exec/io.h" #include "exec/tasks.h" #include "exec/execbase.h" #include "devices/narrator.h" #include "libraries/translator.h" struct MsgPort *readport=0; struct MsgPort *writeport=0; extern struct MsgPort *CreatePort(); extern struct IORequest *CreateExtIO(); struct narrator_rb *writeNarrator=0; struct mouth_rb *readNarrator=0; struct Library *TranslatorBase=0; UBYTE outputstring[500]; /* place to put the translation */ SHORT rtnCode; /* return code from function */ SHORT readError; SHORT writeError; SHORT error; BYTE audChanMasks[4] = { 3,5,10,12 }; /* which channels to use */ #define CANT_OPEN_TRANSLATOR -100 #define CANT_OPEN_NARRATOR -200 #define CREATE_PORT_PROBLEMS -300 #define CREATE_IO_PROBLEMS -400 #define CANT_PERFORM_WRITE -500 #define REVISION 1 extern struct Library *OpenLibrary(); say_string(Txt,done) UBYTE *Txt; int done; { static FirstTime = 1; if (FirstTime) { FirstTime = 0; TranslatorBase = OpenLibrary("translator.library",REVISION); if(TranslatorBase == NULL) exit (CANT_OPEN_TRANSLATOR); rtnCode = Translate(Txt,strlen(Txt)+1,outputstring,500); error = rtnCode + 100; if(rtnCode != 0) goto cleanup0; writeport = CreatePort(0,0); if(writeport == NULL) { error=CREATE_PORT_PROBLEMS; goto cleanup1; } readport = CreatePort(0,0); if(readport == NULL) { error=CREATE_PORT_PROBLEMS; goto cleanup2; } writeNarrator = (struct narrator_rb *)CreateExtIO(writeport, sizeof(struct narrator_rb)); if(writeNarrator == NULL) { error=CREATE_IO_PROBLEMS; goto cleanup3; } readNarrator = (struct mouth_rb *)CreateExtIO(readport, sizeof(struct mouth_rb)); if(readNarrator == NULL) { error=CREATE_IO_PROBLEMS; goto cleanup4; } /* SET UP THE PARAMETERS FOR THE WRITE-MESSAGE TO THE NARRATOR DEVICE */ /* show where to find the channel masks */ writeNarrator->ch_masks = (audChanMasks); /* and tell it how many of them there are */ writeNarrator->nm_masks = sizeof(audChanMasks); /* tell it where to find the string to speak */ writeNarrator->message.io_Data = (APTR)outputstring; /* tell it how many characters the translate function returned */ writeNarrator->message.io_Length = strlen(outputstring); /* if nonzero, asks that mouths be calculated during speech */ writeNarrator->mouths = 1; /* tell it this is a write-command */ writeNarrator->message.io_Command = CMD_WRITE; /* select rate of 165 words/min. */ writeNarrator->rate = (UWORD)165; /* Open the device */ error = OpenDevice("narrator.device", 0, writeNarrator, 0); if(error != 0) goto cleanup4; /* SET UP THE PARAMETERS FOR THE READ-MESSAGE TO THE NARRATOR DEVICE */ /* tell narrator for whose speech a mouth is to be generated */ readNarrator->voice.message.io_Device = writeNarrator->message.io_Device; readNarrator->voice.message.io_Unit = writeNarrator->message.io_Unit; readNarrator->width = 0; readNarrator->height = 0; /* initial mouth parameters */ readNarrator->voice.message.io_Command = CMD_READ; /* initial error value */ readNarrator->voice.message.io_Error = 0; /* Send an asynchronous write request to the device */ writeError = SendIO(writeNarrator); if(writeError != NULL) { error=CANT_PERFORM_WRITE; goto cleanup5; } /* return immediately, run tasks concurrently */ /* keep sending reads until it comes back saying "no write in progress" */ while((readError = readNarrator->voice.message.io_Error) != ND_NoWrite) { DoIO(readNarrator); /* put task to sleep waiting for a different * mouth shape or return of the message block * with the error field showing no write in * process */ } Delay(30); return; } if ( !done ) { rtnCode = Translate(Txt,strlen(Txt)+1,outputstring,500); /* writeNarrator->sex = FEMALE; writeNarrator->pitch = MAXPITCH; /* raise pitch from default value */ writeNarrator->message.io_Data = (APTR)outputstring; writeNarrator->message.io_Length = strlen(outputstring); DoIO(writeNarrator); Delay(30); return; } cleanup5: if(writeNarrator != 0) CloseDevice(writeNarrator); /* terminate access to the device */ /* now return system memory to the memory allocator */ cleanup4: if(readNarrator != 0) DeleteExtIO(readNarrator,sizeof(struct mouth_rb)); cleanup3: if(writeNarrator != 0) DeleteExtIO(writeNarrator,sizeof(struct narrator_rb)); cleanup2: if(readport != 0) DeletePort(readport); cleanup1: if(writeport != 0) DeletePort(writeport); cleanup0: if(TranslatorBase != 0) CloseLibrary(TranslatorBase); /* terminate access to the library */ if(error != 0) exit(error); } /* end of test */ /*********************************************************************** * * Exec Support Function -- Extended IO Request * ***********************************************************************/ extern APTR AllocMem(); /****** exec_support/CreateExtIO ************************************** * * NAME * CreateExtIO() -- create an Extended IO request * * SYNOPSIS * ioReq = CreateExtIO(ioReplyPort,size); * * FUNCTION * Allocates memory for and initializes a new IO request block * of a user-specified number of bytes. * * INPUTS * ioReplyPort - a pointer to an already initialized * message port to be used for this IO request's reply port. * * RESULT * Returns a pointer to the new block. Pointer is of the type * struct IORequest. * * 0 indicates inability to allocate enough memory for the request block * or not enough signals available. * * EXAMPLE * struct IORequest *myBlock; * if( (myBlock = CreateExtIO(myPort,sizeof(struct IOExtTD)) == NULL) * exit(NO_MEM_OR_SIGNALS); * * example used to allocate space for IOExtTD (trackdisk driver * IO Request block for extended IO operations). * * SEE ALSO * DeleteExtIO * ***********************************************************************/ struct IORequest *CreateExtIO(ioReplyPort,size) struct MsgPort *ioReplyPort; LONG size; { struct IORequest *ioReq; if (ioReplyPort == 0) return ((struct IORequest *) 0); ioReq = (struct IORequest *)AllocMem (size, MEMF_CLEAR | MEMF_PUBLIC); if (ioReq == 0) return ((struct IORequest *) 0); ioReq -> io_Message.mn_Node.ln_Type = NT_MESSAGE; ioReq -> io_Message.mn_Node.ln_Pri = 0; ioReq -> io_Message.mn_ReplyPort = ioReplyPort; ioReq -> io_Message.mn_Length = (size - sizeof(struct Message)); /* new (rap) */ return (ioReq); } /****** exec_support/DeleteExtIO ************************************** * * NAME * DeleteExtIO() - return memory allocated for extended IO request * * SYNOPSIS * DeleteExtIO(ioReq,size); * * FUNCTION * See summary line at NAME. Also frees the signal bit which * had been allocated by the call to CreateExtIO. * * INPUTS * A pointer to the IORequest block whose resources are to be freed. * * RESULT * Frees the memory. Returns (no error conditions shown) * * EXAMPLE * struct IORequest *myBlock; * DeleteExtIO(myBlock,(sizeof(struct IOExtTD))); * * example shows that CreateExtIO had been used to create a trackdisk * (extended) IO Request block. * * SEE ALSO * CreateExtIO * **************************************************************************/ DeleteExtIO(ioExt,size) struct IORequest *ioExt; LONG size; { ioExt -> io_Message.mn_Node.ln_Type = 0xff; ioExt -> io_Device = (struct Device *) -1; ioExt -> io_Unit = (struct Unit *) -1; FreeMem (ioExt, size); } SHAR_EOF if test 8123 -ne "`wc -c < 'speech.c'`" then echo shar: error transmitting "'speech.c'" '(should have been 8123 characters)' fi fi # end of overwriting check echo shar: extracting "'termcap'" '(532 characters)' if test -f 'termcap' then echo shar: will not over-write existing file "'termcap'" else cat << \SHAR_EOF > 'termcap' #normal amiga entry am|amiga:\ :al=\E[L:bs:cd=\E[J:ce=\E[K:cl=^L:cm=\E[%i%d;%dH:co#80:cr=^M:\ :dc=\E[P:do=\E[B:kd=\EB:kl=\ED:kr=\EC:ku=\EA:li#25:nd=\E[C:\ :sf=\E[S:sr=\E[T:up=\E[A:bw:nl=\E[B:am:so=\E[7m:se=\E[m:bl=^G:\ :dl=\E[M:us=\E[4m:ue=\E[0m:ic=\E[@: #hack amiga entry sm|amiga-s:\ :al=\E[L:bs:cd=\E[J:ce=\E[K:cl=^L^A:cm=\E[%i%d;%dH:co#80:cr=^M:\ :dc=\E[P:do=\E[B:kd=\EB:kl=\ED:kr=\EC:ku=\EA:li#25:nd=\E[C:\ :sf=\E[S:sr=\E[T:up=\E[A:bw:nl=\E[B:am:so=\E[7m:se=\E[m:bl=^G:\ dl=\E[M:us=\E[4m:ue=\E[0m:ic=\E[@:ho=\E[H^A: SHAR_EOF if test 532 -ne "`wc -c < 'termcap'`" then echo shar: error transmitting "'termcap'" '(should have been 532 characters)' fi fi # end of overwriting check echo shar: extracting "'say.c'" '(527 characters)' if test -f 'say.c' then echo shar: will not over-write existing file "'say.c'" else cat << \SHAR_EOF > 'say.c' # include <stdio.h> main(argc,argv) int argc; char *argv[]; { char x[133]; int i; FILE *in; if (argc == 1) { while (gets(x) != NULL) { printf("%c%s\n",'\001',x); } } else { for (i=1; i<argc; i++) { if (strcmp(argv[i],"-")==0) { in = stdin; } else { if ((in = fopen(argv[i],"r"))==NULL) { fprintf(stderr,"Can't open %s\n", argv[i]); continue; } } while (fgets(x,sizeof(x),in) != NULL) { printf("%c%s",'\001',x); } fclose(in); } } } SHAR_EOF if test 527 -ne "`wc -c < 'say.c'`" then echo shar: error transmitting "'say.c'" '(should have been 527 characters)' fi fi # end of overwriting check # End of shell archive exit 0 -- ------ Lefteris (princeton!tilt!kyrimis) ------
kyrimis@tilt.FUN (Kriton Kyrimis) (04/13/86)
In article <408@tilt.FUN> tilt!ek (Eleftherios Koutsofios) writes: >------ > Lefteris (princeton!tilt!kyrimis) >------ -----------------------------------^ He obviously means princeton!tilt!ek Although I did help by typing parts of the program and by con- stantly nagging until it was perfect, this is Lefteris' work, so I don't think this is the correct place for an acknowledgement. :-) -- Kriton (princeton!tilt!kyrimis) ------ "Is it you, timelord?" "As far as I know, there is no one except you and me here, so it *must* be me!" ------