Move protocols/types.h content to remote.h
[remote/remote-mci.git] / mch / SerialControl.cc
blob0c8ac4903c380e480ee92e337fda463f9b729fb9
1 #include "SerialControl.h"
3 namespace remote { namespace mch {
5 SerialControl::SerialControl()
6 : port(-1), childPid(-1)
10 SerialControl::~SerialControl()
12 endChild(true);
13 if (isOpen())
14 closeTty();
17 bool SerialControl::openTty(const std::string platform, const std::string tty)
19 struct termios newsertio;
21 if (isOpen()) {
22 Log::debug("TTY already open for %s", tty.c_str());
23 return false;
26 Log::info("Opening TTY %s", tty.c_str());
27 port = open(tty.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
28 if (port == -1) {
29 Log::error("Failed to open %s: %s", tty.c_str(), strerror(errno));
30 return false;
33 tcgetattr(port, &oldsertio); /* save current port settings */
36 * 8 data, no parity, 1 stop bit. Ignore modem control lines. Enable
37 * receive. NO HARDWARE FLOW CONTROL!
39 newsertio.c_cflag = CS8 | CLOCAL | CREAD;
41 /* Set baud rate. */
42 if (platform == "dig528-2")
43 newsertio.c_cflag |= B38400;
44 else if(platform == "TMoteSky")
45 newsertio.c_cflag = B115200;
46 else if (platform == "MicaZ")
47 newsertio.c_cflag = B57600;
48 else
49 Log::error("Unknown platform '%s'", platform.c_str());
51 /* Raw input. Ignore errors and breaks. */
52 newsertio.c_iflag = IGNBRK | IGNPAR;
54 /* Raw output. */
55 newsertio.c_oflag = 0;
57 /* No echo and no signals. */
58 newsertio.c_lflag = 0;
60 /* blocking read until 1 char arrives */
61 newsertio.c_cc[VMIN]=1;
62 newsertio.c_cc[VTIME]=0;
64 /* now clean the modem line and activate the settings for modem */
65 tcflush(port, TCIFLUSH);
66 tcsetattr(port, TCSANOW, &newsertio);
68 return true;
71 void SerialControl::closeTty()
73 if (!isOpen())
74 return;
76 tcsetattr(port, TCSANOW, &oldsertio);
77 close(port);
78 port = -1;
81 bool SerialControl::runChild(char * const args[], char * const envp[])
83 int pfd[2];
85 if (pipe(pfd) < 0)
86 return false;
87 closeTty();
89 if ((childPid = fork())) {
90 /* Only use the reader end if we forked. */
91 if (hasChild())
92 port = pfd[0];
93 else
94 close(pfd[0]);
95 close(pfd[1]);
97 } else {
98 /* Redirect all standard output to the parent's pipe. */
99 if (dup2(pfd[1], STDOUT_FILENO) != -1 &&
100 dup2(pfd[1], STDERR_FILENO) != -1) {
101 close(pfd[0]);
102 close(pfd[1]);
103 execve(args[0], args, envp);
105 /* XXX: Make the failed child exit immediately. */
106 _exit(EXIT_FAILURE);
109 return hasChild();
112 bool SerialControl::endChild(bool killChild)
114 int status;
116 if (!hasChild())
117 return false;
119 if (killChild)
120 kill(childPid, SIGKILL);
122 waitpid(childPid, &status, 0);
123 close(port);
124 port = childPid = -1;
126 return killChild || (WIFEXITED(status) && WEXITSTATUS(status) == 0);
129 bool SerialControl::controlDTR(bool enable)
131 int tmp = TIOCM_DTR;
132 int req = enable ? TIOCMBIS : TIOCMBIC;
134 return ioctl(port, req, &tmp) != -1;
137 ssize_t SerialControl::readBuf(char *buf, size_t len)
139 ssize_t res = read(port, buf, len);
141 if (res <= 0 && !hasChild())
142 closeTty();
144 return res;
147 ssize_t SerialControl::writeBuf(const char* buf, size_t len)
149 return write(port, buf, len);
152 bool SerialControl::hasChild()
154 return childPid != -1;
157 bool SerialControl::isOpen()
159 return port != -1 && !hasChild();
162 int SerialControl::getFd()
164 return port;