static void main_loop(struct serial_port *port) { int nfds; struct pollfd pollfds[4]; #ifdef _DEBUG char dbgmsg[256]; #endif int serial_fd = ((struct serial_posix*)(port->chan))->fd; int i; while (1) { nfds = 0; DBG_LOG(strcpy(dbgmsg, "main_loop: wait for")); if (serial_port_watch_ertsr(port)) { pollfds[nfds++] = pipe_os_readable(port->erts); DBG_LOG(strcat(dbgmsg, " ertsr")); } if (serial_port_watch_ertsw(port)) { pollfds[nfds++] = pipe_os_writeable(port->erts); DBG_LOG(strcat(dbgmsg, " ertsw")); } if (serial_port_watch_serialr(port)) { pollfds[nfds++] = serial_os_readable(port->chan); DBG_LOG(strcat(dbgmsg, " serialr")); } if (serial_port_watch_serialw(port)) { pollfds[nfds++] = serial_os_writeable(port->chan); DBG_LOG(strcat(dbgmsg, " serialw")); } DBG_LOG(fprintf(debug_log_file, "%s\n", dbgmsg)); /* If no events are enabled, we are really up a creek. Shutdown the * process right now. */ if (0 == nfds) { serial_port_destroy(port); exit(1); } /* Wait for any of the above events to become true. Break out * as soon as one of them is in fact true. */ if (poll(pollfds, nfds, -1) < 0) { port->isDead = 1; } for (i = 0; i < nfds; i++) { if (pollfds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) { port->isDead = 1; } if ((pollfds[i].fd == STDIN_FILENO) && (pollfds[i].revents & POLLIN)) { serial_port_ertsr(port); } else if ((pollfds[i].fd == STDOUT_FILENO) && (pollfds[i].revents & POLLOUT)) { serial_port_ertsw(port); } else if (pollfds[i].fd == serial_fd) { if (pollfds[i].revents & POLLIN) { serial_port_serialr(port); } else if (pollfds[i].revents & POLLOUT) { serial_port_serialw(port); } } } /* If something went horribly wrong, the generic code should * have sent a message to Erlang indicating the error. It * also flagged the port dead, so we know to terminate the * process. */ if (serial_port_isdead(port)) { serial_port_destroy(port); exit(1); } } }
struct serial_port_t* serial_port_create(struct event_base *_base, const char* _dev_name, unsigned int _baudrate) { struct termios options; struct serial_port_t* sp = NULL; do { if(!(sp = (struct serial_port_t*)malloc(sizeof(struct serial_port_t)))) break; memset(sp, 0, sizeof(struct serial_port_t)); sp->fd = open(_dev_name, O_RDWR | O_NOCTTY | O_NDELAY); if(sp->fd < 0) { fprintf(stderr, "%s: Error while open \"%s\" serial port: %m\n", __FUNCTION__, _dev_name); fflush(stderr); break; } tcgetattr(sp->fd, &options); // ****** c_cflag field setup (Управляющие опции) // Поле c_cflag содержит две опции, которые всегда // должны быть разрешены: CLOCAL и CREAD. options.c_cflag |= (CLOCAL | CREAD); //options.c_cflag &= ~(ICANON | IEXTEN | FLUSHO | PENDIN | TOSTOP); //options.c_cflag |= (NOFLSH); options.c_cflag &= ~PARENB; // Disable parity bit options.c_cflag &= ~CSTOPB; // 1 stop bit options.c_cflag &= ~CSIZE; // Маскирование битов размера символов (CS5,CS8...) options.c_cflag |= CS8; // 8 data bits // Disable hardware flow control #ifdef CRTSCTS options.c_cflag &= ~CRTSCTS; #elif defined CNEW_RTSCTS options.c_cflag &= ~CNEW_RTSCTS; #endif // ****** c_lflag field setup (Локальные опции) // Выбор неканонического (Raw) ввода: options.c_lflag &= ~( // Next flags will disabled: ICANON | // Разрешить канонический ввод (иначе неканонический) ECHO | // Разрешить эхо вводимых символов ECHOE | // Символ эхо стирания как BS-SP-BS ISIG); // Разрешить SIGINTR, SIGSUSP, SIGDSUSP, и SIGQUIT сигналы // ****** c_iflag field setup (Опции ввода) options.c_iflag &= ~( // Next flags will disabled: IXON | // Enable software flow control (outgoing) IXOFF | // Enable software flow control (incoming) IXANY | // Allow any character to start flow again INPCK | // Enable parity check // IGNPAR | // Ignore parity errors PARMRK | // Mark parity errors ISTRIP | // Strip parity bits // IGNBRK | // Ignore break condition IMAXBEL | // Echo BEL on input line too long INLCR | // Map CR to NL IGNCR | // Ignore CR ICRNL); // Map CR to NL // ****** c_oflag field setup (Опции вывода) // Когда опция OPOST сброшена, все остальные биты опций в поле c_oflag игнорируются. options.c_oflag &= ~OPOST; tcsetattr(sp->fd, TCSANOW, &options); if(serial_port_set_baudrate(sp, _baudrate)) { fprintf(stderr, "%s: Error with serial_port_set_baudrate() call: %m\n", __FUNCTION__); fflush(stderr); break; } sp->read_event = event_new(_base, sp->fd, EV_READ | EV_PERSIST, fd_event, sp); if(!sp->read_event) { fprintf(stderr, "%s: Error with event_new() call: %m\n", __FUNCTION__); fflush(stderr); break; } sp->write_event = event_new(_base, sp->fd, EV_WRITE | EV_PERSIST, fd_event, sp); if(!sp->write_event) { fprintf(stderr, "%s: Error with event_new() call: %m\n", __FUNCTION__); fflush(stderr); break; } if(event_add(sp->read_event, NULL)) { fprintf(stderr, "%s: Error with event_add() call: %m\n", __FUNCTION__); fflush(stderr); break; } return sp; } while(0); serial_port_destroy(sp); return NULL; }
static void main_loop (struct serial_port* port) { DWORD wres; DWORD nEvents; HANDLE theEvent; HANDLE wEvents[8]; #ifdef _DEBUG char dbgmsg[256]; #endif for (;;) { nEvents = 0; DBG_LOG(strcpy(dbgmsg, "main_loop: wait for")); if (serial_port_watch_ertsr(port)) { wEvents[nEvents++] = pipe_os_readable(port->erts); DBG_LOG(strcat(dbgmsg, " ertsr")); } if (serial_port_watch_ertsw(port)) { wEvents[nEvents++] = pipe_os_writeable(port->erts); DBG_LOG(strcat(dbgmsg, " ertsw")); } if (serial_port_watch_serialr(port)) { wEvents[nEvents++] = serial_os_readable(port->chan); DBG_LOG(strcat(dbgmsg, " serialr")); } if (serial_port_watch_serialw(port)) { wEvents[nEvents++] = serial_os_writeable(port->chan); DBG_LOG(strcat(dbgmsg, " serialw")); } DBG_LOG(fprintf(debug_log_file, "%s\n", dbgmsg)); /* If no events are enabled, we are really up a creek. Shutdown the * process right now. */ if (0 == nEvents) { serial_port_destroy(port); ExitProcess(1); } /* Wait for any of the above events to become true. Break out * as soon as one of them is in fact true. */ wres = WaitForMultipleObjects(nEvents, wEvents, FALSE, INFINITE); if (wres < WAIT_OBJECT_0) { continue; } /* Determine the event which triggered this wakeup. Unlike on * UNIX, we only know that one event in fact occurred, all of * the others require us to go wait for them again. */ theEvent = wEvents[wres - WAIT_OBJECT_0]; if (theEvent == pipe_os_readable(port->erts)) { serial_port_ertsr(port); } else if (theEvent == pipe_os_writeable(port->erts)) { serial_port_ertsw(port); } else if (theEvent == serial_os_readable(port->chan)) { serial_port_serialr(port); } else if (theEvent == serial_os_writeable(port->chan)) { serial_port_serialw(port); } /* If something went horribly wrong, the generic code should * have sent a message to Erlang indicating the error. It * also flagged the port dead, so we know to terminate the * process. */ if (serial_port_isdead(port)) { serial_port_destroy(port); ExitProcess(1); } } }