/*---------------------------------------------------------------------------- * kb.c * * Gets keyboard events asynchronously and passes their ASCII code equivalents to a * child process that is running a verilog simulation via "vvp a.out", where * a.out is a iverilog compilation of some verilog .v source code. * Single ascii chars are passed to the child process via a pair of files in a * handshaking protocol, one file for data and the other for control. * The parent process writes a single ascii code to the data file and writes an * end-of-text signal to the control file. The child process polls the control file, * reads the data file, and overwrites the end-of-text signal with an * acknowledgement signal. The parent exits on receiving an key event, which * also kills the child process. * * Termios is used to set keyboard read()s to 1-char blocking, which returns a key * event as a single ASCII byte (but see below for non-printing and other key events). * The ascii byte is translated to a string giving the byte's value in hex; * eg., '4' becomes "34" in C parlance. The string is written to the handshake data * file and an ascii ETX data-ready signal is written as the string "03" * to the handshake control file. (These strings are new-line terminated). * * The parent does not poll the handshake control file to see if the data is * consumed by the downstream process. Nevertheless, the child signals consumption * by converting the ETX line to the hex representation of ascii ACK, "06". * * The parent handles only those key events that termios translates to standard, * aka 7-bit, ASCII. Key events that termios returns as multiple bytes (such as * key sequences) or as extended ASCII codes are ignored. key events * translate to ASCII control codes: a = 0x01, b = x02, ..., m = 0x0D * (aka CR), and so forth. However, some do not, eg., q returns nothing. (In * unix parlance these ascii control codes are denoted "^A", "^B", ... "^M", etc.) * * Ref for termios code: * http://www.cs.usfca.edu/~cruse/cs635/noncanon.cpp ----------------------------------------------------------------------------*/ /*----------------------------------------------- *-------- STANDARD ASCII, 8-bits, x00-x7F ------ *------- (Partial Listing, in hex) ------ *-------- (extended ASCII goes up to xFF) ------ *----------------------------------------------- *---Printable------------------ * 20 -- SP, Space * 21-2F -- Punctuation and symbols * 30-39 -- numerals 0-9 * 3A-40 -- Punctuation and symbols * 41-5A -- 'A'-'Z' * 5B-60 -- Punctuation and symbols * 61-7A -- 'a'-'z' * 7B-7E -- Punctuation and symbols * 7F -- Delete * ------------------------------ * ---Non-Printable-------------- * 00-1F -- Control signals: * 00 -- NUL, Null char * 08 -- BS, Back Space * 09 -- HT, Tab (horizontal) * 0A -- LF, Line Feed * 0D -- CR, Carriage Return * 1B -- ESC, Escape * 03 -- ETX, End of Text * 04 -- EOT, End Of Transmission * 06 -- ACK, Acknowledgement * -----------------------------*/ #define ETX 0x03 #define EOT 0x04 #define ACK 0x06 #define ESC 0x1B #include #include /*-- printf(), perror() --*/ #include /*-- exit() --*/ #include /*-- STDIN_FILENO, usleep --*/ #include /*-- tcgetattr(), tcsetattr() --*/ #include /*-- kill() --*/ #include int ch; struct termios tty, tty_old; FILE *fd_data, *fd_hs; char line[5]; pid_t pid; int status; int fd[2] pipe(fd); if(childpid == 0) { /* Close stdout, duplicate the output side of pipe to stdout */ dup2(1, fd[1]); /* Child process closes up input side of pipe */ close(fd[0]); } else { /* Parent process closes up output side of pipe */ close(fd[1]); /* Read in a string from the pipe */ nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); printf("Received string: %s", readbuffer); } int main(void) { /*-- Create/Open handshake and data channels, and initialize them. --*/ fd_hs = fopen("kbHS.txt", "w"); /*-- Open HS channel. --*/ if( fd_hs == NULL ) { /*-- if fopen() error: --*/ perror("kb can't open handshake:"); /*-- report, --*/ exit(1); /*-- and EXIT(1). --*/ } fd_data = fopen("kbData.txt", "w"); /*-- Open data channel. --*/ if( fd_data == NULL ) { /*-- if fopen() error: --*/ perror("kb can't open data:"); /*-- report, --*/ exit(1); /*-- and EXIT(1). --*/ } fprintf(fd_hs, "%0.2x\n", ETX); /*-- Write ready hs sig. --*/ fprintf(fd_data, "%0.2x\n", 0x31); /*-- Write dummy data '1'. --*/ fclose( fd_hs ); fclose( fd_data ); /*-- Close HS and data channels. --*/ /*-- Start child for verilog simulaton. -------------------------*/ pid = fork(); if(pid == -1) { perror("kb can't fork: "); exit(1); } if (pid == 0) { status = execlp("vvp", "vvp", "a.out", 0); if (status == -1) { perror("kb child can't exec: "); exit(1); } } /*-- Set keyboard to raw, ---------------------------------------------*/ /*-- Change kb tty settings. fd = 0 for kb. ---------------------------*/ status = tcgetattr( 0, &tty_old); /*-- get current tty settings, --*/ if (status < 0) { perror("kb can't tcget: "); kill(pid,SIGTERM); exit(1); } tty = tty_old; /*-- save them for restore. Set --*/ tty.c_cc[VMIN] = 1; /*-- read() min bytes returned, --*/ tty.c_cc[VTIME] = 0; /*-- read() does not time out, --*/ tty.c_lflag &= ~ECHO; /*-- no kb echo to screen, --*/ tty.c_lflag &= ~ICANON; /*-- no buffering, --*/ tty.c_lflag &= ~ISIG; /*-- no -c exit. Write tty: --*/ status = tcsetattr( 0, TCSAFLUSH, &tty ); if (status < 0) { perror("kb can't tcset: "); kill(pid,SIGTERM); exit(1); } /*-- MAIN LOOP: ------------------------------------------------*/ /*-- Get ascii code per key event, translate ascii to string, --*/ /*-- write string to data file, write ETX string to hs file. --*/ /*-- Exit on ESC. --*/ while(1) { read( 0, &ch, sizeof(ch) ); /*-- Wait for key event. --*/ if( ch == ESC ) { /*-- if ESC then EXIT: --*/ tcsetattr( 0, TCSAFLUSH, &tty_old ); /*-- restore tty, and --*/ if(status < 0) perror("kb can't reset: "); /*-- if can't, report, --*/ kill(pid,SIGTERM); /*-- end child, --*/ exit(0); /*-- and EXIT(0). --*/ } if (!(0 <= ch <= 0x7F)) { continue; } /*-- Ignore non-standard ASCII. --*/ fd_data = fopen("kbData.txt", "r+"); /*-- Open data channel. --*/ if( fd_data == NULL ) { /*-- if fopen() error: --*/ perror("kb can't open handshake:"); /*-- report, --*/ tcsetattr( 0, TCSAFLUSH, &tty_old ); /*-- restore tty, --*/ if(status < 0) perror("kb can't reset: "); /*-- if can't, report, --*/ kill(pid, SIGTERM); exit(1); /*-- and EXIT(1). --*/ } rewind(fd_data); fprintf(fd_data, "%0.2x\n", ch); /*-- Write char as string. --*/ fclose(fd_data); /*-- Close data channel. --*/ fd_hs = fopen("kbHS.txt", "r+"); /*-- Open HS channel. --*/ if( fd_hs == NULL ) { /*-- if fopen() error: --*/ perror("kb can't open handshake:"); /*-- report, --*/ tcsetattr( 0, TCSAFLUSH, &tty_old ); /*-- restore tty, --*/ if(status < 0) perror("kb can't reset: "); /*-- if can't, report, --*/ kill(pid, SIGTERM); exit(1); /*-- and EXIT(1). --*/ } rewind(fd_hs); fprintf(fd_hs, "%0.2x\n", ETX); /*-- Write handshake signal. --*/ fclose(fd_hs); /*-- Close HS channel. --*/ }/*--while(1)--*/ }/*--main--*/