1 #include "SerialControl.h"
3 namespace remote
{ namespace diku_mch
{
5 SerialControl::SerialControl()
6 : port(-1), isRunning(false), childPid(-1)
10 SerialControl::~SerialControl()
17 result_t
SerialControl::openTty()
19 struct termios newsertio
;
22 Log::debug("TTY already open for %s", tty
.c_str());
26 Log::info("Opening TTY %s", tty
.c_str());
27 port
= open(tty
.c_str(), O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
29 Log::error("Failed to open %s: %s", tty
.c_str(), strerror(errno
));
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
;
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
62 result_t
SerialControl::closeTty()
65 Log::debug("TTY already closed for %s", tty
.c_str());
68 Log::info("Closing %s", tty
.c_str());
69 tcsetattr(port
, TCSANOW
, &oldsertio
);
75 bool SerialControl::runChild(char * const args
[], char * const envp
[])
83 if ((childPid
= fork())) {
84 /* Only use the reader end if we forked. */
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) {
97 execve(args
[0], args
, envp
);
99 /* XXX: Make the failed child exit immediately. */
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
)
124 kill(childPid
, SIGKILL
);
126 waitpid(childPid
, &status
, 0);
128 port
= childPid
= -1;
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";
156 if (!resetting
|| controlDTR(isRunning
)) {
157 bool enable
= resetting
? !isRunning
: cmd
== "stop";
159 if (controlDTR(enable
)) {
164 /* Mirror that the first reset DTR change succeeded. */
166 isRunning
= !isRunning
;
169 Log::error("Failed to %s %s: %s", cmd
.c_str(), tty
.c_str(), strerror(errno
));
174 bool SerialControl::controlDTR(bool enable
)
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())
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()
212 int SerialControl::getFd()
217 status_t
SerialControl::getStatus()
219 if (hasChild()) return MOTE_PROGRAMMING
;
220 if (!isOpen()) return MOTE_UNAVAILABLE
;
221 if (isRunning
) return MOTE_RUNNING
;