Remove TODO file
[remote/remote-mci.git] / diku_mch / SerialControl.cc
blob5bbd2317bf3212056fd60c1ca6d4a724f3bb0966
1 #include "SerialControl.h"
3 namespace remote { namespace diku_mch {
5 SerialControl::SerialControl()
6 : port(-1), isRunning(false), childPid(-1)
10 SerialControl::~SerialControl()
12 endChild(true);
13 if (isOpen())
14 closeTty();
17 result_t SerialControl::openTty()
19 struct termios newsertio;
21 if (isOpen()) {
22 Log::debug("TTY already open for %s", tty.c_str());
23 return FAILURE;
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 FAILURE;
33 tcgetattr(port, &oldsertio); /* save current port settings */
36 * 8 data, no parity, 1 stop bit. Ignore modem control lines. Enable
37 * receive. Set 38400 baud rate. NO HARDWARE FLOW CONTROL!
39 newsertio.c_cflag = B38400 | CS8 | CLOCAL | CREAD;
41 /* Raw input. Ignore errors and breaks. */
42 newsertio.c_iflag = IGNBRK | IGNPAR;
44 /* Raw output. */
45 newsertio.c_oflag = 0;
47 /* No echo and no signals. */
48 newsertio.c_lflag = 0;
50 /* blocking read until 1 char arrives */
51 newsertio.c_cc[VMIN]=1;
52 newsertio.c_cc[VTIME]=0;
54 /* now clean the modem line and activate the settings for modem */
55 tcflush(port, TCIFLUSH);
56 tcsetattr(port, TCSANOW, &newsertio);
58 // open in a stopped state
59 return stop();
62 result_t SerialControl::closeTty()
64 if (!isOpen()) {
65 Log::debug("TTY already closed for %s", tty.c_str());
66 return FAILURE;
68 Log::info("Closing %s", tty.c_str());
69 tcsetattr(port, TCSANOW, &oldsertio);
70 close(port);
71 port = -1;
72 return SUCCESS;
75 bool SerialControl::runChild(char * const args[], char * const envp[])
77 int pfd[2];
79 if (pipe(pfd) < 0)
80 return false;
81 closeTty();
83 if ((childPid = fork())) {
84 /* Only use the reader end if we forked. */
85 if (hasChild())
86 port = pfd[0];
87 else
88 close(pfd[0]);
89 close(pfd[1]);
91 } else {
92 /* Redirect all standard output to the parent's pipe. */
93 if (dup2(pfd[1], STDOUT_FILENO) != -1 &&
94 dup2(pfd[1], STDERR_FILENO) != -1) {
95 close(pfd[0]);
96 close(pfd[1]);
97 execve(args[0], args, envp);
99 /* XXX: Make the failed child exit immediately. */
100 _exit(EXIT_FAILURE);
103 return hasChild();
106 result_t SerialControl::getChildResult()
108 return endChild(false) ? SUCCESS : FAILURE;
111 result_t SerialControl::cancelProgramming()
113 return endChild(true) ? SUCCESS : FAILURE;
116 bool SerialControl::endChild(bool killChild)
118 int status;
120 if (!hasChild())
121 return false;
123 if (killChild)
124 kill(childPid, SIGKILL);
126 waitpid(childPid, &status, 0);
127 close(port);
128 port = childPid = -1;
129 openTty();
131 return killChild || (WIFEXITED(status) && WEXITSTATUS(status) == 0);
134 result_t SerialControl::reset()
136 return power("reset");
139 result_t SerialControl::start()
141 return power("start");
144 result_t SerialControl::stop()
146 return power("stop");
149 result_t SerialControl::power(const std::string cmd)
151 bool resetting = cmd == "reset";
153 if (!isOpen())
154 return FAILURE;
156 if (!resetting || controlDTR(isRunning)) {
157 bool enable = resetting ? !isRunning : cmd == "stop";
159 if (controlDTR(enable)) {
160 isRunning = !enable;
161 return SUCCESS;
164 /* Mirror that the first reset DTR change succeeded. */
165 if (resetting)
166 isRunning = !isRunning;
169 Log::error("Failed to %s %s: %s", cmd.c_str(), tty.c_str(), strerror(errno));
170 closeTty();
171 return FAILURE;
174 bool SerialControl::controlDTR(bool enable)
176 int tmp = TIOCM_DTR;
177 int req = enable ? TIOCMBIS : TIOCMBIC;
179 return ioctl(port, req, &tmp) != -1;
182 ssize_t SerialControl::readBuf(char *buf, size_t len)
184 ssize_t res = read(port, buf, len);
186 if (res <= 0 && !hasChild())
187 closeTty();
189 return res;
192 ssize_t SerialControl::writeBuf(const char* buf, size_t len)
194 return write(port, buf, len);
197 bool SerialControl::hasChild()
199 return childPid != -1;
202 bool SerialControl::isOpen()
204 return port != -1 && !hasChild();
207 const std::string& SerialControl::getTty()
209 return tty;
212 int SerialControl::getFd()
214 return port;
217 status_t SerialControl::getStatus()
219 if (hasChild()) return MOTE_PROGRAMMING;
220 if (!isOpen()) return MOTE_UNAVAILABLE;
221 if (isRunning) return MOTE_RUNNING;
222 return MOTE_STOPPED;