// ttyUSB0 is a serial line coming in to the Pi from a Windows PC
// ttyUSB1 is the serial connection to the GRBL controller...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <libgen.h>
#include <termios.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdarg.h>
#include <signal.h>
#define BUF_SIZE 1024
char USB0_buf[BUF_SIZE+1], USB1_buf[BUF_SIZE+1];
struct termios ttyUSB0Orig, ttyUSB1Orig, t0, t1;
int USB0_Fd, USB1_Fd, file0_fd, file1_fd;
fd_set inFds;
void ttyReset(void) {
(void)tcsetattr (USB0_Fd, TCSANOW, &ttyUSB0Orig); // restore keyboard/stdin
(void)tcsetattr (USB1_Fd, TCSANOW, &ttyUSB1Orig); // restore keyboard/stdin
fprintf(stderr, "\nexit()\n");
_exit(EXIT_SUCCESS);
}
char *progname;
void errExit(char *what) {
exit(EXIT_FAILURE);
}
void INThandler(int sig)
{ // force ^C to go via atexit() handler...
signal(sig, SIG_IGN);
exit(0);
// signal(SIGINT, INThandler);
}
int main(int argc, char **argv) {
size_t numRead;
char *s;
// Get clean version of executable name. Should work on most existing systems (2006)
progname = argv[0];
if ((s = strrchr(progname, '/')) != NULL) progname = s+1; // Unix
if ((s = strrchr(progname, '\\')) != NULL) progname = s+1; // M$
if ((s = strrchr(progname, ']')) != NULL) progname = s+1; // Dec
if ((s = strrchr(progname, ';')) != NULL) *s = '\0'; // Version no's
if (((s = strrchr(progname, '.')) != NULL) && (strcasecmp(s, ".exe") == 0)) *s = '\0';
if (((s = strrchr(progname, '.')) != NULL) && (strcasecmp(s, ".com") == 0)) *s = '\0';
if (tcgetattr (USB0_Fd, &ttyUSB0Orig) == -1)
errExit("tcgetattr");
if (tcgetattr (USB1_Fd, &ttyUSB1Orig) == -1)
errExit("tcgetattr");
system ("stty -F /dev/ttyUSB0 speed 115200 > /dev/null");
system ("stty -F /dev/ttyUSB1 speed 115200 > /dev/null");
USB0_Fd = open ("/dev/ttyUSB0", O_RDWR);
if (USB0_Fd < 0) {
errExit("open");
}
USB1_Fd = open ("/dev/ttyUSB1", O_RDWR);
if (USB1_Fd < 0) {
errExit("open");
}
tcsendbreak(USB0_Fd, 0);
tcsendbreak(USB1_Fd, 0);
/* relay data between both USB serial ports */
if (tcgetattr (USB0_Fd, &t0) == -1) /*return -1*/;
if (tcgetattr (USB1_Fd, &t1) == -1) /*return -1*/;
ttyUSB0Orig = t0;
ttyUSB1Orig = t1;
t0.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO); // COMMENT OUT THIS "| ECHO"
// to cause GRBL commands to
// be echoed on the incoming
// connection
t1.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
/* Noncanonical mode, disable signals, extended input processing, and echoing */
t0.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK | ISTRIP | IXON | PARMRK);
t1.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK | ISTRIP | IXON | PARMRK);
/* Disable special handling of CR, NL, and BREAK. No 8th-bit stripping or parity error handling. Disable START/STOP output flow control. */
// If it weren't for the fact that I might later want to support ^S/^Q, I would probably put these in RAW mode instead:
#ifdef NEVER // RAW:
t?.c_iflag |= IGNBRK;
t?.c_iflag &= ~(INLCR | ICRNL | IXON | IXOFF);
t?.c_lflag &= ~(ICANON | ECHO | ECHOK | ECHOE | ECHONL | ISIG | IEXTEN);
#endif
t0.c_oflag &= ~OPOST; /* Disable all output processing */
t1.c_oflag &= ~OPOST; /* Disable all output processing */
t0.c_cc[VMIN] = 1; /* Character-at-a-time input */
t1.c_cc[VMIN] = 1; /* Character-at-a-time input */
t0.c_cc[VTIME] = 0; /* with blocking */
t1.c_cc[VTIME] = 0; /* with blocking */
(void)tcsetattr (USB0_Fd, TCSAFLUSH, &t0);
(void)tcsetattr (USB1_Fd, TCSAFLUSH, &t1); // TCSANOW perhaps?
if (atexit(ttyReset) != 0)
errExit("atexit");
/* everything that comes from USB0 is forwarded to USB1, and vice-versa */
signal(SIGINT, INThandler);
file0_fd = open("USBLOG0-to-CNC.bin", O_WRONLY|O_CREAT, 0755);
file1_fd = open("USBLOG1-from-CNC.bin", O_WRONLY|O_CREAT, 0755);
for (;;) {
FD_ZERO (&inFds);
FD_SET (USB0_Fd, &inFds);
FD_SET (USB1_Fd, &inFds);
(void)select (USB1_Fd + 1, &inFds, NULL, NULL, NULL);
if (FD_ISSET (USB0_Fd, &inFds)) { /* USB0 -> USB1 */
numRead = read (USB0_Fd, USB0_buf, BUF_SIZE);
if (numRead > 0) {
(void)write(USB1_Fd, USB0_buf, numRead); // for now assume all writes succeed.
(void)write(2, USB0_buf, numRead);
(void)write(file0_fd, USB0_buf, numRead);
}
}
if (FD_ISSET (USB1_Fd, &inFds)) { /* USB1 -> USB0 */
numRead = read (USB1_Fd, USB1_buf, BUF_SIZE);
if (numRead > 0) {
(void)write(USB0_Fd, USB1_buf, numRead);
(void)write(2, "\033[7m", 4); // Reversed
(void)write(2, USB1_buf, numRead);
(void)write(2, "\033[m", 3); // Normal
(void)write(file1_fd, USB1_buf, numRead);
}
}
}
return(EXIT_FAILURE); // killing is the only expected exit
}