term.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
00003  *
00004  * This file is part of rob08
00005  *
00006  * rob08 is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * any later version.
00010  *
00011  * rob08 is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with rob08.  If not, see <http://www.gnu.org/licenses/>.
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     // check if given file is valid
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     // check for permissions
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     // open terminal
00091     // FIXME: use appropriate flags
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;                                       // maybe not necessary for unsigned char
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                 // write interrupted by signal
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             // FIXME: this should not be here
00203             // way to hell
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 }

Generated on Fri Jul 10 22:42:01 2009 for rob08 by  doxygen 1.5.4