using namespace std; #include "tterm.h" SC_HAS_PROCESS(tterm); #define INPUT_POLL_TIME_INTERVAL 1 #define INPUT_POLL_TIME_UNIT SC_MS #define PORT_NUM ((unsigned short)1234) #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 512 #endif tterm::tterm(sc_core::sc_module_name name, bool telnet_) : sc_module(name), rx("rx", 20), startReading("startReading") { // Method for the Rx with static sensitivity SC_METHOD(writeMethod); sensitive << rx.data_written_event(); dont_initialize(); // Thread for the xterm SC_THREAD(readThread); telnet = telnet_; connected = false; timeVal.tv_sec = 0; timeVal.tv_usec = 0; socSocket = -1; socClient = -1; } // Custom destructors are not usually needed for SystemC models, but we use // this to kill the child process running the xterm. tterm::~tterm() { cout << "Closing connection" << endl; close(socClient); close(socSocket); if(rxt) pclose(rxt); } // Method handling characters on the Rx buffer // SystemC Method that sensitive to characters being written from the UART. // When they arrive, write them to the socket. void tterm::writeMethod() { startReading.notify(); while (rx.num_available() != 0) { // read from uart unsigned char c = rx.read(); // write to network socket socketWrite(c); } } // Thread listening for characters from the network socket. // At startup, Wait to be notified via a SystemC event that the // first write to the UART has occurred. // Read the character from the socket, then send it out to the UART. void tterm::readThread() { unsigned char c; int st; while (true) { wait(startReading); if (!startConnection(telnet)) return; while (connected == true) { wait(INPUT_POLL_TIME_INTERVAL, INPUT_POLL_TIME_UNIT); st = socketRead(&c); if (st) { tx.write(c); } } } } int tterm::startConnection(bool start_telnet) { char hostname[MAXHOSTNAMELEN + 1]; int st; ssize_t size; char telnetOption[] = { 255, 251, 1, /* IAC WILL Echo */ 255, 251, 3, /* IAC WILL Suppress Go Ahead */ }; char banner[] = "Connected to Cadence Virtual UART\r\n"; int retryCount = 0; unsigned short incr = 0; struct sockaddr_in saMe; if (connected == false) { // Create socket if ((socSocket = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("socket()"); return 0; } // Get my host name if ((gethostname(hostname, MAXHOSTNAMELEN)) << 0) { perror("gethostname()"); return 0; } // Bind address and port number to the socket while (retryCount < 5) { bzero((char *)&saMe, sizeof(saMe)); saMe.sin_family = AF_INET; saMe.sin_addr.s_addr = htonl(INADDR_ANY); saMe.sin_port = htons(PORT_NUM+incr); st = bind(socSocket, (struct sockaddr *)&saMe, sizeof(saMe)); if (st >= 0) break; ++incr; ++retryCount; cout << "Retrying..." << endl; sleep(5); } if (st < 0) { perror("bind() failed"); return 0; } // Allocate socket buffer if ((listen(socSocket, 5)) < 0) { perror("listen()"); return 0; } // Wait for connection cout << "Connected to port: " << PORT_NUM+incr << endl; if (start_telnet) { char xt[128]; sprintf(xt, "xterm -sb -e telnet %s %d 2>&1", hostname, PORT_NUM+incr); cout << "Auto start of UART terminal using '" << xt << "' ..." << endl; rxt = (FILE*)popen((const char*) xt, "r"); int fd = fileno(rxt); int flags = fcntl(fd, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(fd, F_SETFL, flags); sleep(2); while (fgets(lxt,sizeof(lxt),rxt)) { cout << "UART_INFO: " << lxt; } if (!rxt || strlen(lxt)) { cout << "Auto-start of UART terminal failed, check xterm PATH or DISPLAY environment" << endl; cout << "Reverting to manual start ..." << endl; if (rxt) pclose(rxt); rxt=NULL; } } retryCount = 0; while (retryCount < 5) { saClientLen = sizeof(saClient); bzero((char *)&saClient, sizeof(saClient)); socClient = accept(socSocket, (struct sockaddr *)&saClient, &saClientLen); if (socClient >= 0) break; if (errno != EINTR) { perror("accept()"); cout << "Retrying..." << endl; } ++retryCount; sleep(1); } if (socClient < 0) { perror("accept() failed"); return 0; } cout << "Client connected." << endl; // Ignore SIGPIPE for write() //signal(SIGPIPE, SIG_IGN); connected = 1; if (start_telnet) { size = write(socClient, telnetOption, sizeof(telnetOption)); if (size < 0) { perror("write()"); connected = 0; } size = write(socClient, banner, sizeof(banner) - 1); if (size < 0) { perror("write()"); connected = 0; } } } return(connected); } int tterm::socketRead(unsigned char *data_char) { fd_set fdSet; int status; ssize_t size; char readBuf[1024]; FD_ZERO(&fdSet); FD_SET(socClient, &fdSet); // if select returns EINTR try again while ((status = select(socClient + 1, &fdSet, NULL, NULL, &timeVal)) <0 && errno == EINTR); if (status < 0) { perror("select() on read"); connected = false; return 0; } if (status > 0 && FD_ISSET(socClient, &fdSet)) { size = read(socClient, readBuf, 1); if (size == 0) { cout << "Connection Closed" << endl; close(socClient); close(socSocket); connected = false; return 0; } else if (size < 0) { connected = false; return 0; } *data_char = readBuf[0]; return 1; } return 0; } void tterm::socketWrite(unsigned char ch) { ssize_t size; if (connected && socClient >= 0) { size = write(socClient, &ch, 1); if (size < 0) { perror("write()"); connected = 0; } if(ch == 0xa) { // CR needs to be inserted for every newline ch=0xd; size = write(socClient, &ch, 1); } } }