📄 nindy.c
字号:
/* Bad checksum: report, send NAK, and re-receive */ fprintf(stderr, errfmt, cs_recv, cs_calc ); write (nindy_fd, "-", 1); }}/****************************************************************************** * putpkt: * Send a packet to NINDY, checksumming it and converting special * characters to escape sequences. ******************************************************************************//* This macro puts the character 'c' into the buffer pointed at by 'p', * and increments the pointer. If 'c' is one of the 4 special characters * in the transmission protocol, it is converted into a 2-character * escape sequence. */#define PUTBUF(c,p) \ if ( c == DLE || c == ESC || c == XON || c == XOFF ){ \ *p++ = ESC; \ *p++ = c | 0x40; \ } else { \ *p++ = c; \ }staticputpkt( msg, len ) unsigned char *msg; /* Command to be sent, without lead ^P (\020) or checksum */ int len; /* Number of bytes in message */{ static char *buf = NULL;/* Local buffer -- build packet here */ static int maxbuf = 0; /* Current length of buffer */ unsigned char ack; /* Response received from NINDY */ unsigned char checksum; /* Packet checksum */ char *p; /* Pointer into buffer */ int lenhi, lenlo; /* High and low bytes of message length */ int i; /* Make sure local buffer is big enough. Must include space for * packet length, message body, and checksum. And in the worst * case, each character would expand into a 2-character escape * sequence. */ if ( maxbuf < ((2*len)+10) ){ if ( buf ){ free( buf ); } buf = malloc( maxbuf=((2*len)+10) ); } /* Attention, NINDY! */ write( nindy_fd, "\020", 1 ); lenlo = len & 0xff; lenhi = (len>>8) & 0xff; checksum = lenlo + lenhi; p = buf; PUTBUF( lenlo, p ); PUTBUF( lenhi, p ); for ( i=0; i<len; i++ ){ PUTBUF( msg[i], p ); checksum += msg[i]; } PUTBUF( checksum, p ); /* Send checksummed message over and over until we get a positive ack */ write( nindy_fd, buf, p-buf ); while (1){ if ( !rdnin(&ack,1,5) ){ /* timed out */ fprintf(stderr,"ACK timed out; resending\r\n"); write(nindy_fd,"\020",1);/* Attention, NINDY! */ write( nindy_fd, buf, p-buf ); } else if ( ack == '+' ){ return; } else if ( ack == '-' ){ fprintf( stderr, "Remote NAK; resending\r\n" ); write( nindy_fd, buf, p-buf ); } else { fprintf( stderr, "Bad ACK, ignored: <%c>\r\n", ack ); } }}/****************************************************************************** * send: * Send a message to a remote NINDY. Check message status byte * for error responses. If no error, return NINDY reponse (if any). ******************************************************************************/staticsend( out, len, in ) unsigned char *out; /* Message to be sent to NINDY */ int len; /* Number of meaningful bytes in out buffer */ unsigned char *in; /* Where to put response received from NINDY */{ char *fmt; int status; static char *errmsg[] = { "", /* 0 */ "Buffer overflow", /* 1 */ "Unknown command", /* 2 */ "Wrong amount of data to load register(s)", /* 3 */ "Missing command argument(s)", /* 4 */ "Odd number of digits sent to load memory", /* 5 */ "Unknown register name", /* 6 */ "No such memory segment", /* 7 */ "No breakpoint available", /* 8 */ "Can't set requested baud rate", /* 9 */ };# define NUMERRS ( sizeof(errmsg) / sizeof(errmsg[0]) ) static char err1[] = "Unknown error response from NINDY: #%d\r\n"; static char err2[] = "Error response #%d from NINDY: %s\r\n"; while (1){ putpkt(out,len); status = getpkt(in); if ( status == TIMEOUT ){ fprintf( stderr, "Response timed out; resending\r\n" ); } else { break; } } if ( status ){ fmt = status > NUMERRS ? err1 : err2; fprintf( stderr, fmt, status, errmsg[status] ); abort(); }} /************************ * * * BAUD RATE ROUTINES * * * ************************//* Table of baudrates known to be acceptable to NINDY. Each baud rate * appears both as character string and as a Unix baud rate constant. */struct baudrate { char *string; int rate;};static struct baudrate baudtab[] = { "1200", B1200, "2400", B2400, "4800", B4800, "9600", B9600, "19200", B19200, "38400", B38400, NULL, 0 /* End of table */}; /****************************************************************************** * parse_baudrate: * Look up the passed baud rate in the baudrate table. If found, change * our internal record of the current baud rate, but don't do anything * about the tty just now. * * Return pointer to baudrate structure on success, NULL on failure. ******************************************************************************/staticstruct baudrate *parse_baudrate(s) char *s; /* Desired baud rate, as an ASCII (decimal) string */{ int i; for ( i=0; baudtab[i].string != NULL; i++ ){ if ( !strcmp(baudtab[i].string,s) ){ return &baudtab[i]; } } return NULL;}/****************************************************************************** * try_baudrate: * Try speaking to NINDY via the specified file descriptor at the * specified baudrate. Assume success if we can send an empty command * with a bogus checksum and receive a NAK (response of '-') back within * one second. * * Return 1 on success, 0 on failure. ******************************************************************************/static inttry_baudrate( fd, brp ) int fd; struct baudrate *brp;{ TTY_STRUCT tty; unsigned char c; /* Set specified baud rate and flush all pending input */ ioctl( fd, TIOCGETP, &tty ); TTY_REMOTE( tty, brp->rate ); ioctl( fd, TIOCSETP, &tty ); tty_flush( fd ); /* Send empty command with bad checksum, hope for NAK ('-') response */ write( fd, "\020\0\0\001", 4 ); if ( !rdnin(&c,1,1) ){ /* timed out */ return 0; } else { return (c == '-'); }}/****************************************************************************** * autobaud: * Get NINDY talking over the specified file descriptor at the specified * baud rate. First see if NINDY's already talking at 'baudrate'. If * not, run through all the legal baudrates in 'baudtab' until one works, * and then tell NINDY to talk at 'baudrate' instead. ******************************************************************************/staticautobaud( fd, brp ) int fd; struct baudrate *brp;{ int i; TTY_STRUCT tty; int failures; say("NINDY at wrong baud rate? Trying to autobaud...\n"); failures = i = 0; while ( 1 ){ say( "\r%s... ", baudtab[i].string ); if ( try_baudrate(fd, &baudtab[i]) ){ break; } if ( baudtab[++i].string == NULL ){ /* End of table -- wraparound */ i = 0; if ( failures++ ){ say("\nAutobaud failed again. Giving up.\n"); exit(1); } else { say("\nAutobaud failed. Trying again...\n"); } } } /* Found NINDY's current baud rate; now change it. */ say("Changing NINDY baudrate to %s\n", brp->string); ninBaud( brp->string ); /* Change our baud rate back to rate to which we just set NINDY. */ ioctl( fd, TIOCGETP, &tty ); TTY_REMOTE( tty, brp->rate ); ioctl( fd, TIOCSETP, &tty );}/***************************************************************************** * coffstrip: * Passed the name of an executable object file in either b.out or * COFF format. * * If the file is in b.out format, it is converted to little-endian * COFF format (i.e., the format suitable for downloading to NINDY). * In either case, the COFF file is then stripped of all relocation * and symbol information, to speed up its download. * * RETURNS: * pointer to the name of the stripped COFF file (a tmp file that has * been created and closed); NULL on error. *****************************************************************************/#if 0#define STRIP "bfd_strip" /* Name of bfd strip utility */#endif#define NINDY_OBJ "coff-Intel-little"char *coffstrip( fn ) char *fn; /* Name of object file */{ extern char *mktemp(); static char template[] = "/tmp/commXXXXXX"; static char newfile[sizeof template]; char *strip; /* Pointer to full pathname of strip utility */ int success; /* Return value */ int pid; /* Process ID of xmodem transfer utility */ WAITTYPE w; /* xmodem transfer completion status */ int wret; /* Value returned by wait */ char *tempfile; /* Stripped copy of object file */ char buf[400]; strcpy (newfile, template); tempfile = mktemp( newfile );#if 0 /* Make sure the strip utility is findable. */ if ( ((strip = exists("G960BIN",STRIP,NULL,NULL,1)) == NULL) && ((strip = exists("G960BASE","bin",STRIP, NULL,1)) == NULL)#ifdef HOST && ((strip = exists(DEFAULT_BASE,HOST,"bin",STRIP,0)) == NULL)#endif ){ fprintf(stderr,"Can't find '%s' utility\n",STRIP); fprintf(stderr,"Check env variables G960BIN and G960BASE\n"); return NULL; }#endif success = 0; sprintf( buf, "cp %s %s", fn, tempfile ); printf ("%s\n", buf); if ( system(buf) == 0 ){ sprintf(buf, "%s -d %s %s", STRIP, NINDY_OBJ, tempfile); printf ("%s\n", buf); if ( system(buf) == 0 ){ return tempfile; } } return NULL;} /********************************** * * * NINDY INTERFACE ROUTINES * * * * ninConnect *MUST* be the first * * one of these routines called. * **********************************//****************************************************************************** * ninBaud: * Ask NINDY to change the baud rate on its serial port. * Assumes we know the baud rate at which NINDY's currently talking. ******************************************************************************/ninBaud( baudrate ) char *baudrate; /* Desired baud rate, as a string of ASCII decimal * digits. */{ unsigned char msg[100]; if ( old_nindy ){ OninBaud( baudrate ); return; } tty_flush( nindy_fd ); /* Can't use "send" because NINDY reply will be unreadable after * baud rate change. */ sprintf( msg, "z%s", baudrate ); putpkt( msg, strlen(msg)+1 ); /* "+1" to send terminator too */}/****************************************************************************** * ninBptDel: * Ask NINDY to delete the specified type of *hardware* breakpoint at * the specified address. If the 'addr' is -1, all breakpoints of * the specified type are deleted. ******************************************************************************/ninBptDel( addr, type ) long addr; /* Address in 960 memory */ char type; /* 'd' => data bkpt, 'i' => instruction breakpoint */{ unsigned char buf[10]; if ( old_nindy ){ OninBptDel( addr, type == 'd' ? 1 : 0 ); return; } buf[0] = 'b'; buf[1] = type; if ( addr == -1 ){ send( buf, 2, NULL ); } else { put_int( &buf[2], addr ); send( buf, 6, NULL ); }}/****************************************************************************** * ninBptSet: * Ask NINDY to set the specified type of *hardware* breakpoint at * the specified address. ******************************************************************************/ninBptSet( addr, type ) long addr; /* Address in 960 memory */ char type; /* 'd' => data bkpt, 'i' => instruction breakpoint */{ unsigned char buf[10]; if ( old_nindy ){ OninBptSet( addr, type == 'd' ? 1 : 0 ); return; } buf[0] = 'B'; buf[1] = type; put_int( &buf[2], addr ); send( buf, 6, NULL );}/****************************************************************************** * ninConnect: * Open the specified tty. Get communications working at the specified * baud rate. Flush any pending I/O on the tty. * * Return the file descriptor, or -1 on failure. ******************************************************************************/intninConnect( name, baudrate, brk, silent, old_protocol ) char *name; /* "/dev/ttyXX" to be opened */ char *baudrate;/* baud rate: a string of ascii decimal digits (eg,"9600")*/ int brk; /* 1 => send break to tty first thing after opening it*/ int silent; /* 1 => stifle unnecessary messages when talking to * this tty. */ int old_protocol;{ int i; char *p; struct baudrate *brp; /* We will try each of the following paths when trying to open the tty */ static char *prefix[] = { "", "/dev/", "/dev/tty", NULL }; if ( old_protocol ){ old_nindy = 1; return OninConnect( name, baudrate, brk, silent ); } quiet = silent; /* Make global to this file */ for ( i=0; prefix[i] != NULL; i++ ){ p = malloc(strlen(prefix[i]) + strlen(name) + 1 ); strcpy( p, prefix[i] ); strcat( p, name ); nindy_fd = open(p,O_RDWR); if ( nindy_fd >= 0 ){#ifdef TIOCEXCL /* Exclusive use mode (hp9000 does not support it) */ ioctl(nindy_fd,TIOCEXCL,NULL);#endif if ( brk ){ send_break( nindy_fd ); } brp = parse_baudrate( baudrate ); if ( brp == NULL ){ say("Illegal baudrate %s ignored; using 9600\n", baudrate); brp = parse_baudrate( "9600" ); } if ( !try_baudrate(nindy_fd,brp) ){ autobaud(nindy_fd,brp); } tty_flush( nindy_fd ); say( "Connected to %s\n", p ); free(p); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -