00001
00009
00010
00011
00012
00013 #include <ecl/config/ecl.hpp>
00014 #ifdef ECL_IS_POSIX
00015
00016
00017
00018
00019
00020 #include <fcntl.h>
00021 #include <sys/ioctl.h>
00022 #include <termios.h>
00023 #include <cstdlib>
00024 #include <unistd.h>
00025 #include <ecl/exceptions/standard_exception.hpp>
00026 #include <ecl/exceptions/macros.hpp>
00027 #include "../../include/ecl/devices/serial_pos.hpp"
00028 #include "../../include/ecl/devices/detail/error_handler.hpp"
00029
00030
00031
00032
00033
00034 namespace ecl
00035 {
00036
00037
00038
00039
00040
00041 using std::string;
00042 using ecl::InvalidInputError;
00043 using ecl::OpenError;
00044 using ecl::StandardException;
00045
00046
00047
00048
00049
00050 Serial::Serial(const std::string& port_name, const BaudRate &baud_rate, const DataBits &data_bits,
00051 const StopBits &stop_bits, const Parity &parity) ecl_throw_decl(StandardException) :
00052 port(port_name), read_timeout_ms(5000), error_handler(NoError)
00053 {
00054 ecl_try
00055 {
00056 open(port_name, baud_rate, data_bits, stop_bits, parity);
00057 } ecl_catch( const StandardException &e ) {
00058 ecl_throw(StandardException(LOC,e));
00059 }
00060 }
00061
00062 Serial::~Serial()
00063 {
00064 close();
00065 }
00066
00067
00068
00069
00070
00071 bool Serial::open(const std::string& port_name, const BaudRate &baud_rate, const DataBits &data_bits,
00072 const StopBits &stop_bits, const Parity &parity) ecl_throw_decl(StandardException)
00073 {
00074
00075
00076
00077
00078 if (stop_bits == StopBits_15)
00079 {
00080 ecl_throw(
00081 StandardException(LOC,ConfigurationError,"Standard serial device does not accept StopBits_15 as valid (used in ftdi)."));
00082 error_handler = InvalidArgError;
00083 is_open = false;
00084 return false;
00085 }
00086
00087 if (open())
00088 {
00089 close();
00090 }
00091 port = port_name;
00092
00093
00094
00095 file_descriptor = ::open(port_name.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
00096 if (file_descriptor == -1)
00097 {
00098 ecl_throw(devices::open_exception(LOC,port_name));
00099 error_handler = devices::open_error();
00100 is_open = false;
00101 return false;
00102 }
00103
00104 static const int baud_rate_flags[] = {B110, B300, B600, B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200,
00105 B921600};
00106 static const int data_bits_flags[] = {CS5, CS6, CS7, CS8};
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 fcntl(file_descriptor, F_SETFL, 0);
00119
00120
00121 struct flock file_lock;
00122 file_lock.l_type = F_WRLCK;
00123 file_lock.l_whence = SEEK_SET;
00124 file_lock.l_start = 0;
00125 file_lock.l_len = 0;
00126 file_lock.l_pid = getpid();
00127 if (fcntl(file_descriptor, F_SETLK, &file_lock) != 0)
00128 {
00129 ecl_throw_decl(
00130 StandardException(LOC,OpenError,std::string("Device is already locked. Try 'lsof | grep ") + port + std::string("' to find other processes that currently have the port open (if the device is a symbolic link you may need to replace the device name with the device that it is pointing to).")));
00131 error_handler = IsLockedError;
00132 is_open = false;
00133 return false;
00134 }
00135
00136
00137
00138
00139 options.c_cflag = 0;
00140 options.c_iflag = 0;
00141 options.c_lflag = 0;
00142 options.c_oflag = 0;
00143
00144
00145
00146
00147 cfsetispeed(&options, baud_rate_flags[baud_rate]);
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 options.c_cflag |= CLOCAL;
00158 options.c_cflag |= CREAD;
00159
00160
00161
00162
00163 #if defined(CRTSCTS)
00164 options.c_cflag &= ~CRTSCTS;
00165 #elif defined (CNEW_RTSCTS)
00166 options.c_cflag &= ~CNEW_RTSCTS;
00167 #endif
00168
00169
00170
00171
00172 if (stop_bits == StopBits_1)
00173 {
00174 options.c_cflag &= ~CSTOPB;
00175 }
00176 else
00177 {
00178 options.c_cflag |= CSTOPB;
00179 }
00180
00181
00182
00183
00184 options.c_cflag &= ~CSIZE;
00185 options.c_cflag |= data_bits_flags[data_bits];
00186
00187
00188
00189
00190 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
00191
00192
00193
00194
00195
00196 options.c_iflag &= ~(IXON | IXOFF | IXANY);
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206 if (parity == NoParity)
00207 {
00208 options.c_cflag &= ~PARENB;
00209 }
00210 else if (parity == EvenParity)
00211 {
00212 options.c_iflag |= (INPCK | ISTRIP);
00213 options.c_cflag |= PARENB;
00214 options.c_cflag &= ~PARODD;
00215 }
00216 else
00217 {
00218 options.c_iflag |= (INPCK | ISTRIP);
00219 options.c_cflag |= PARENB;
00220 options.c_cflag |= PARODD;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230 tcsetattr(file_descriptor, TCSAFLUSH, &options);
00231
00232
00233
00234
00235 if ( read_timeout_ms == NonBlocking ) {
00236 unblock();
00237 } else {
00238 block(read_timeout_ms);
00239 }
00240 clear();
00241
00242 is_open = true;
00243 error_handler = NoError;
00244 return true;
00245 }
00246
00247 void Serial::close()
00248 {
00249 if (is_open)
00250 {
00251
00252 ::close(file_descriptor);
00253 is_open = false;
00254 }
00255 }
00256
00257 bool Serial::open()
00258 {
00259 if ( is_open ) {
00260 if ( access(port.c_str(), F_OK ) == -1 ) {
00261 close();
00262 }
00263 }
00264 return is_open;
00265 }
00266
00267
00268
00269
00270
00271 void Serial::block(const unsigned long &timeout)
00272 {
00273 if (timeout < 100)
00274 {
00275 if (timeout < 5)
00276 {
00277 fake_snooze.period(ecl::Duration(0.001));
00278 fake_loop_count = timeout;
00279 }
00280 else if (timeout < 20)
00281 {
00282 fake_snooze.period(ecl::Duration(0.002));
00283 div_t d = div(timeout, 2);
00284 if (d.rem == 0)
00285 {
00286 fake_loop_count = d.quot;
00287 }
00288 else
00289 {
00290 fake_loop_count = d.quot + 1;
00291 }
00292 }
00293 else
00294 {
00295 fake_snooze.period(ecl::Duration(0.005));
00296 div_t d = div(timeout, 5);
00297 if (d.rem == 0)
00298 {
00299 fake_loop_count = d.quot;
00300 }
00301 else
00302 {
00303 fake_loop_count = d.quot + 1;
00304 }
00305 }
00306 this->unblock();
00307 }
00308 else
00309 {
00310 options.c_cc[VMIN] = 0;
00311
00312 if (timeout < 100)
00313 {
00314 options.c_cc[VTIME] = static_cast<unsigned char>(1);
00315 }
00316 else
00317 {
00318 options.c_cc[VTIME] = static_cast<unsigned char>(timeout / 100);
00319 }
00320 tcsetattr(file_descriptor, TCSAFLUSH, &options);
00321 }
00322 read_timeout_ms = timeout;
00323 }
00324
00325 void Serial::unblock()
00326 {
00327 options.c_cc[VMIN] = 0;
00328 options.c_cc[VTIME] = 0;
00329 tcsetattr(file_descriptor, TCSAFLUSH, &options);
00330 read_timeout_ms = NonBlocking;
00331 }
00332
00333
00334
00335
00336 long Serial::remaining()
00337 {
00338 long bytes = 0;
00339 ioctl(file_descriptor, FIONREAD, &bytes);
00340 return bytes;
00341 }
00342
00343 }
00344 #endif