/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice * you can do whatever you want with this stuff. If we meet some day, and you * think this stuff is worth it, you can buy me a beer in return. Thomas Buck * ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include "serial.h" #ifndef XON #define XON 0x11 #endif #ifndef XOFF #define XOFF 0x13 #endif #ifndef TIMEOUT #define TIMEOUT 2 #endif int serialOpen(const char *port, unsigned int baud) { struct termios options; int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { fprintf(stderr, "Couldn't open port \"%s\": %s\n", port, strerror(errno)); return -1; } tcgetattr(fd, &options); options.c_lflag = 0; options.c_oflag = 0; options.c_iflag = 0; // Set Baudrate switch (baud) { case 9600: cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); break; case 19200: cfsetispeed(&options, B19200); cfsetospeed(&options, B19200); break; case 38400: cfsetispeed(&options, B38400); cfsetospeed(&options, B38400); break; case 76800: cfsetispeed(&options, B76800); cfsetospeed(&options, B76800); break; case 115200: cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); break; default: fprintf(stderr, "Warning: Baudrate not supported!\n"); serialClose(fd); return -1; } // Input Modes #ifdef XONXOFF options.c_iflag |= IXON; // XON-XOFF Flow Control #endif // Output Modes options.c_oflag |= OPOST; // Post-process output // Control Modes options.c_cflag |= CS8; // 8 data bits options.c_cflag |= CREAD; // Enable Receiver options.c_cflag |= CLOCAL; // Ignore modem status lines // Special characters options.c_cc[VMIN] = 0; // Always return... options.c_cc[VTIME] = 0; // ..immediately from read() #ifdef XONXOFF options.c_cc[VSTOP] = XOFF; options.c_cc[VSTART] = XON; #endif tcsetattr(fd, TCSANOW, &options); tcflush(fd, TCIOFLUSH); return fd; } void serialClose(int fd) { tcflush(fd, TCIOFLUSH); close(fd); } int serialHasChar(int fd) { struct pollfd fds; fds.fd = fd; fds.events = (POLLIN | POLLPRI); // Data may be read if (poll(&fds, 1, 0) > 0) { return 1; } else { return 0; } } void serialWaitUntilSent(int fd) { while (tcdrain(fd) == -1) { fprintf(stderr, "Could not drain data: %s\n", strerror(errno)); } } unsigned int serialWriteRaw(int fd, const char *d, int len) { unsigned int processed = 0; time_t start = time(NULL); while ((processed < len) && (difftime(time(NULL), start) < TIMEOUT)) { int t = write(fd, (d + processed), (len - processed)); if (t == -1) { fprintf(stderr, "Error while writing: %s\n", strerror(errno)); return processed; } else { processed += t; } usleep(1000); } return processed; } unsigned int serialReadRaw(int fd, char *d, int len) { unsigned int processed = 0; time_t start = time(NULL); while ((processed < len) && (difftime(time(NULL), start) < TIMEOUT)) { int t = read(fd, (d + processed), (len - processed)); if (t == -1) { fprintf(stderr, "Error while reading: %s\n", strerror(errno)); return processed; } else { processed += t; } usleep(1000); } return processed; } void serialWriteChar(int fd, char c) { while (serialWriteRaw(fd, &c, 1) != 1); } void serialReadChar(int fd, char *c) { while (serialReadRaw(fd, c, 1) != 1); #ifdef XONXOFF if (*c == XON) { if (tcflow(fd, TCOON) == -1) { fprintf(stderr, "Could not restart flow: %s\n", strerror(errno)); } serialReadChar(fd, c); } else if (*c == XOFF) { if (tcflow(fd, TCOOFF) == -1) { fprintf(stderr, "Could not stop flow: %s\n", strerror(errno)); } serialReadChar(fd, c); } #endif } void serialWriteString(int fd, const char *s) { while (*s) serialWriteChar(fd, *(s++)); } char** getSerialPorts(void) { DIR *dir; struct dirent *ent; int size = 0; dir = opendir("/dev/"); while ((ent = readdir(dir)) != NULL) { #ifdef SEARCH if (strstr(ent->d_name, SEARCH) != NULL) #endif size++; } closedir(dir); char **files = (char **)malloc((size + 1) * sizeof(char *)); int i = 0; dir = opendir("/dev/"); while (((ent = readdir(dir)) != NULL) && (i < size)) { #ifdef SEARCH if (strstr(ent->d_name, SEARCH) != NULL) { #endif int tmp = strlen(ent->d_name) + 6; files[i] = (char *)malloc(tmp * sizeof(char)); strcpy(files[i], "/dev/"); strcpy(files[i] + 5, ent->d_name); files[i][tmp - 1] = '\0'; #ifdef TRY_TO_OPEN_PORTS int fdtmp = serialOpen(files[i], 9600); if (fdtmp != -1) { serialClose(fdtmp); #endif i++; #ifdef TRY_TO_OPEN_PORTS } else { free(files[i]); } #endif #ifdef SEARCH } #endif } closedir(dir); files[i] = NULL; return files; }