00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "config.h"
00021 #include "term.h"
00022
00023 #include "core.h"
00024 #include "robIO.h"
00025 #include "scanner.h"
00026
00027 #ifndef BUILDING_DOX
00028 # include <assert.h>
00029 # include <errno.h>
00030 # include <fcntl.h>
00031 # include <fstream>
00032 # include <iomanip>
00033 # include <poll.h>
00034 # include <signal.h>
00035 # include <sstream>
00036 # include <string>
00037 # include <sys/types.h>
00038 # include <sys/stat.h>
00039 # include <unistd.h>
00040 #endif
00041
00042 volatile sig_atomic_t bSignal = 0;
00043
00044 using namespace StreamDecorator;
00045 using std::string;
00046
00047 class Term: public ITerm {
00048 public:
00049 Term(int fd, const string &fileName);
00050 ~Term();
00051 virtual bool hasError() const { return hasError_; }
00052 virtual bool writeAck();
00053 virtual bool writeByte(unsigned char data);
00054 virtual bool writeWord(unsigned int data);
00055 virtual bool writeText(const std::string &data);
00056 virtual bool getChar(char &c);
00057 virtual bool hasInput(int timeout);
00058
00059 private:
00060 int fd_;
00061 string fileName_;
00062 bool hasError_;
00063
00064 bool write(const std::string &data);
00065 };
00066
00067 ITerm* TermFactory::createTerm(const std::string &fileName) {
00068
00069 const char *const szFileName = fileName.c_str();
00070 struct stat statBuff;
00071 if (0 != stat(szFileName, &statBuff)) {
00072 std::cerr << Error(E_ERROR, fileName, "file does not exist") << std::endl;
00073 return 0;
00074 }
00075 if (! S_ISCHR(statBuff.st_mode)) {
00076 std::cerr << Error(E_ERROR, fileName, "file is not character device") << std::endl;
00077 return 0;
00078 }
00079
00080
00081 if (0!= euidaccess(szFileName, R_OK)) {
00082 std::cerr << Error(E_ERROR, fileName, "insufficient permissions to read from device") << std::endl;
00083 return 0;
00084 }
00085 if (0!= euidaccess(szFileName, W_OK)) {
00086 std::cerr << Error(E_ERROR, fileName, "insufficient permissions to write to device") << std::endl;
00087 return 0;
00088 }
00089
00090
00091
00092 int fd = ::open(szFileName, O_RDWR|O_SYNC|O_NOCTTY);
00093 if (0 > fd) {
00094 std::cerr << Error(E_ERROR, fileName, "open = ") << fd << std::endl;
00095 std::cerr << Error(E_NOTE, fileName, "errno = ") << errno << std::endl;
00096 return 0;
00097 }
00098
00099 return new Term(fd, fileName);
00100 }
00101
00102 Term::Term(int fd, const string &fileName):
00103 fd_(fd),
00104 fileName_(fileName),
00105 hasError_(false)
00106 {
00107 assert(0 <= fd);
00108 }
00109
00110 Term::~Term() {
00111 ::close(fd_);
00112 }
00113
00114 bool Term::writeAck() {
00115 return writeText("A");
00116 }
00117
00118 bool Term::writeByte(unsigned char data) {
00119 data &= 0xFF;
00120
00121 #if DEBUG_TERM_OUTPUT
00122 std::cerr << Color(C_LIGHT_GREEN) << "TERM" << Color(C_NO_COLOR) << " <-- "
00123 << Color(C_LIGHT_CYAN) << "0x" << PrintHex(data, 2) << Color(C_NO_COLOR) << std::endl;
00124 #endif
00125
00126 std::ostringstream out;
00127 out << PrintHex(data, 2) << std::flush;
00128 return write(out.str());
00129 }
00130
00131 bool Term::writeWord(unsigned int data) {
00132 data &= 0xFFFF;
00133
00134 #if DEBUG_TERM_OUTPUT
00135 std::cerr << Color(C_LIGHT_GREEN) << "TERM" << Color(C_NO_COLOR) << " <-- "
00136 << Color(C_LIGHT_CYAN) << "0x" << PrintHex(data, 4) << Color(C_NO_COLOR) << std::endl;
00137 #endif
00138
00139 std::stringstream out;
00140 out << PrintHex(data, 4) << std::flush;
00141 return write(out.str());
00142 }
00143
00144 bool Term::writeText(const std::string &data) {
00145 #if DEBUG_TERM_OUTPUT
00146 std::cerr << Color(C_LIGHT_GREEN) << "TERM" << Color(C_NO_COLOR) << " <-- "
00147 << Color(C_LIGHT_PURPLE) << data << Color(C_NO_COLOR) << std::endl;
00148 #endif
00149
00150 return write(data);
00151 }
00152
00153 bool Term::write(const std::string &data) {
00154 const char *buff = data.c_str();
00155 int toWrite = data.size();
00156 while (0 < toWrite) {
00157 int ret = ::write(fd_, buff, toWrite);
00158 if (ret <= 0) {
00159 if (errno == EINTR)
00160
00161 continue;
00162
00163 hasError_ = false;
00164 std::cerr << Error(E_ERROR, fileName_, "write = ") << ret << std::endl;
00165 std::cerr << Error(E_NOTE, fileName_, "errno = ") << errno << std::endl;
00166 return false;
00167 }
00168 assert (ret <= toWrite);
00169 toWrite -= ret;
00170 buff += ret;
00171 }
00172 return true;
00173 }
00174
00175 bool Term::getChar(char &c) {
00176 for(;;) {
00177 int ret = ::read(fd_, &c, 1);
00178 if (ret == 1)
00179 return true;
00180
00181 switch (errno) {
00182 case EIO:
00183 case EINTR:
00184 break;
00185 default:
00186 std::cerr << Error(E_ERROR, fileName_, "read = ") << ret << std::endl;
00187 std::cerr << Error(E_NOTE, fileName_, "errno = ") << errno << std::endl;
00188 return false;
00189 }
00190
00191 #if DEBUG_TERM_POLL
00192 std::cerr << Error(E_WARNING, fileName_, "calling poll") << std::endl;
00193 #endif
00194 struct pollfd fds;
00195 fds.fd = fd_;
00196 fds.events = POLLIN;
00197 do {
00198 if (bSignal) {
00199 std::cerr << Error(E_NOTE, fileName_, "signal caught") << std::endl;
00200 return false;
00201 }
00202
00203
00204 usleep(10);
00205 } while (1 == poll(&fds, 1, -1) && !(fds.revents & POLLIN));
00206 }
00207 }
00208
00209 bool Term::hasInput(int timeout) {
00210 struct pollfd fds;
00211 fds.fd = fd_;
00212 fds.events = POLLIN;
00213 return (1 == poll(&fds, 1, timeout) && (fds.revents & POLLIN));
00214 }