diff --git a/src/Makefile.am b/src/Makefile.am index 21c81ae..b358312 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,4 +5,4 @@ rvdb_SOURCES = \ cli.c cli.h data.c data.h \ debug.c debug.h file_io.c file_io.h \ main.c serial.c serial.h types.h \ - util.c util.h + util.c util.h pollLib.c pollLib.h diff --git a/src/cli.c b/src/cli.c index 1fc7bea..4f54bc2 100644 --- a/src/cli.c +++ b/src/cli.c @@ -3,15 +3,16 @@ #include "debug.h" #include "types.h" #include "util.h" +#include "pollLib.h" +#include "serial.h" #include -#include -#include #include #include #include #include #include #include +#include // DESCRIPTION: takes the command as a string, and applies it to the serial port // RETURNS: 0 for success, non-zero for error @@ -305,10 +306,33 @@ int parse_cmd(char *line, target_t *tg) { return EXIT_FAILURE; } +void receive_otter_input(int serial_port) { + char buffer[MAX_RECEIVE_LEN]; + + if (read_string(serial_port, buffer) != 0) { + return; + } + + printf("OTTER: %s\n", buffer); +} + +void readFromStdin(char *buffer) { + int len; + + if (fgets(buffer, MAX_INPUT_LEN, stdin) == NULL) { + perror("fgets"); + exit(-1); + } + + // remove \n + len = strlen(buffer); + buffer[len-1] = '\0'; +} + // DESCRIPTION: launches a debugger command line interface (a la GDB) // on the device at the designated serial port void debug_cli(char *path, int serial_port) { - char *line; + char line[MAX_INPUT_LEN]; int err = 0; // create and populate a hash table of variables @@ -346,9 +370,14 @@ void debug_cli(char *path, int serial_port) { tg.bp_cap = MAX_BREAK_PTS; tg.pipe = 0; - printf("\n" CYAN "UART Debugger\n" RESET); + printf("\n" CYAN "UART Debugger/Receiver\n" RESET); printf("Enter 'h' for usage details.\n"); + // create a pollset to poll stdin and the serial port + setupPollSet(); + addToPollSet(STDIN_FILENO); + addToPollSet(serial_port); + // run until EOD is read while (1) { // prompt @@ -357,39 +386,45 @@ void debug_cli(char *path, int serial_port) { printf(" (paused)\n"); else printf("\n"); - line = (err) ? readline(RED "$ " RESET) : readline(GREEN "$ " RESET); - if (line[0] == '!') { - err = 0; - system(line + 1); - } + if (err) + printf(RED "$ " RESET); + else + printf(GREEN "$ " RESET); + fflush(stdout); // flush stdout to display the prompt + memset(line, 0, MAX_INPUT_LEN); - // help message - else if (match_strs(line, "h")) { - HELP_MSG; - err = 0; - } + if (pollCall(-1) == STDIN_FILENO) { + // User has entered input + readFromStdin(line); + + if (line[0] == '!') { + err = 0; + system(line + 1); + } - // quit/exit - else if (match_strs(line, "q")) { - free(line); - ht_destroy(vars_ht, keys, vc); - return; - } else if (match_strs(line, "exit")) { - free(line); - ht_destroy(vars_ht, keys, vc); - return; - } else if (!line) { - free(line); - ht_destroy(vars_ht, keys, vc); - return; - } else if (*line) { - add_history(line); - err = parse_cmd(line, &tg); + // help message + else if (match_strs(line, "h")) { + HELP_MSG; + err = 0; + } + + // quit/exit + else if (match_strs(line, "q")) { + ht_destroy(vars_ht, keys, vc); + return; + } else if (match_strs(line, "exit")) { + ht_destroy(vars_ht, keys, vc); + return; + } else { + err = parse_cmd(line, &tg); + } + + } else { + // Otter is talking + receive_otter_input(serial_port); } - // don't forget to free! - free(line); - line = (char *)NULL; + } } diff --git a/src/cli.h b/src/cli.h index 2949581..27289bf 100644 --- a/src/cli.h +++ b/src/cli.h @@ -12,6 +12,10 @@ #define MAX_BREAK_PTS 8 #define MAX_VAR_COUNT 256 +#define MAX_RECEIVE_LEN 1024 + +#define MAX_INPUT_LEN 1024 + #define REL_CONFIG_PATH "/.config/rvdb/config" #define CTEST_TOKEN "t" diff --git a/src/pollLib.c b/src/pollLib.c new file mode 100755 index 0000000..d6fca00 --- /dev/null +++ b/src/pollLib.c @@ -0,0 +1,119 @@ +// +// Written Hugh Smith, Updated: April 2020 +// Use at your own risk. Feel free to copy, just leave my name in it. +// + +#include +#include +#include + +#include "pollLib.h" + + +// Poll global variables +static struct pollfd * pollFileDescriptors; +static int maxFileDescriptor = 0; +static int currentPollSetSize = 0; + +static void growPollSet(int newSetSize); + +// Poll functions (setup, add, remove, call) +void setupPollSet() +{ + currentPollSetSize = POLL_SET_SIZE; + pollFileDescriptors = (struct pollfd *) calloc(POLL_SET_SIZE, sizeof(struct pollfd)); +} + + +void addToPollSet(int socketNumber) +{ + + if (socketNumber >= currentPollSetSize) + { + // needs to increase off of the biggest socket number since + // the file desc. may grow with files open or sockets + // so socketNumber could be much bigger than currentPollSetSize + growPollSet(socketNumber + POLL_SET_SIZE); + } + + if (socketNumber + 1 >= maxFileDescriptor) + { + maxFileDescriptor = socketNumber + 1; + } + + pollFileDescriptors[socketNumber].fd = socketNumber; + pollFileDescriptors[socketNumber].events = POLLIN; +} + +void removeFromPollSet(int socketNumber) +{ + pollFileDescriptors[socketNumber].fd = 0; + pollFileDescriptors[socketNumber].events = 0; +} + +int pollCall(int timeInMilliSeconds) +{ + // returns the socket number if one is ready for read + // returns -1 if timeout occurred + // if timeInMilliSeconds == -1 blocks forever (until a socket ready) + // (this -1 is a feature of poll) + + int i = 0; + int returnValue = -1; + int pollValue = 0; + + if ((pollValue = poll(pollFileDescriptors, maxFileDescriptor, timeInMilliSeconds)) < 0) + { + perror("pollCall"); + exit(-1); + } + + // check to see if timeout occurred (poll returned 0) + if (pollValue > 0) + { + // see which socket is ready + for (i = 0; i < maxFileDescriptor; i++) + { + //if(pollFileDescriptors[i].revents & (POLLIN|POLLHUP|POLLNVAL)) + //Could just check for some revents, but want to catch any of them + //Otherwise, this could mask an error (eat the error condition) + if(pollFileDescriptors[i].revents > 0) + { + //printf("for socket %d poll revents: %d\n", i, pollFileDescriptors[i].revents); + returnValue = i; + break; + } + } + + } + + // Ready socket # or -1 if timeout/none + return returnValue; +} +static void growPollSet(int newSetSize) +{ + int i = 0; + + // just check to see if someone screwed up + if (newSetSize <= currentPollSetSize) + { + printf("Error - current poll set size: %d newSetSize is not greater: %d\n", + currentPollSetSize, newSetSize); + exit(-1); + } + + printf("Increasing poll set from: %d to %d\n", currentPollSetSize, newSetSize); + pollFileDescriptors = realloc(pollFileDescriptors, newSetSize * sizeof(struct pollfd)); + + // zero out the new poll set elements + for (i = currentPollSetSize; i < newSetSize; i++) + { + pollFileDescriptors[i].fd = 0; + pollFileDescriptors[i].events = 0; + } + + currentPollSetSize = newSetSize; +} + + + diff --git a/src/pollLib.h b/src/pollLib.h new file mode 100755 index 0000000..b35edff --- /dev/null +++ b/src/pollLib.h @@ -0,0 +1,21 @@ +// +// Writen by Hugh Smith, April 2020 +// +// Provides an interface to the poll() library. Allows for +// adding a file descriptor to the set, removing one and calling poll. +// Feel free to copy, just leave my name in it, use at your own risk. +// + + +#ifndef __POLLLIB_H__ +#define __POLLLIB_H__ + +#define POLL_SET_SIZE 10 +#define POLL_WAIT_FOREVER -1 + +void setupPollSet(); +void addToPollSet(int socketNumber); +void removeFromPollSet(int socketNumber); +int pollCall(int timeInMilliSeconds); + +#endif \ No newline at end of file diff --git a/src/serial.c b/src/serial.c index cf61834..6b6e036 100644 --- a/src/serial.c +++ b/src/serial.c @@ -107,6 +107,23 @@ int send_word(int serial_port, word_t w) { return 0; } +// read a byte from thhe device and return 0 if successful +int recv_byte(int serial_port, byte_t *byte) { + ssize_t br; + + br = read(serial_port, byte, 1); + + if (br == -1) { + perror("read(serial_port)"); + exit(-1); + } + if (br == 0) { + fprintf(stderr, "Error: read 0 bytes from serial_port\n"); + return 1; + } + return 0; +} + // read a word from the device and return 0 if successful int recv_word(int serial_port, word_t *word) { word_t w; @@ -162,3 +179,21 @@ int read_word(int serial_port, word_t *word) { } return 1; } + +// reads bytes from the serial port until it reaches a null terminator +// this depends on the otter programmer sending a 0 to not get stuck, could be improved to timeout +// returns 0 on success +int read_string(int serial_port, char *data) { + int i; + byte_t byte; + i = 0; + + do { + if (recv_byte(serial_port, &byte) != 0) { + return 1; + } + data[i++] = (char)byte; + } while(byte != '\0'); + + return 0; +} diff --git a/src/serial.h b/src/serial.h index 9a1105d..a67c40e 100644 --- a/src/serial.h +++ b/src/serial.h @@ -21,5 +21,6 @@ typedef struct termios term_sa; int open_serial(char *path, int *serial_port); int send_word(int serial_port, word_t w); int read_word(int serial_port, word_t *w); +int read_string(int serial_port, char *data); #endif