00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "mitkSerialCommunication.h"
00019
00020
00021 #ifdef WIN32
00022
00023 #include <itksys/SystemTools.hxx>
00024 #else // Posix
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <sys/time.h>
00028 #include <sys/ioctl.h>
00029 #include <fcntl.h>
00030 #include <unistd.h>
00031 #include <termios.h>
00032 #include <errno.h>
00033
00034 #define INVALID_HANDLE_VALUE -1
00035 #endif
00036
00037 #define OK 1
00038 #define ERROR_VALUE 0
00039
00040
00041 mitk::SerialCommunication::SerialCommunication() : itk::Object(),
00042 m_DeviceName(""), m_PortNumber(COM1), m_BaudRate(BaudRate9600),
00043 m_DataBits(DataBits8), m_Parity(None), m_StopBits(StopBits1),
00044 m_HardwareHandshake(HardwareHandshakeOff),
00045 m_ReceiveTimeout(500), m_SendTimeout(500), m_Connected(false)
00046 {
00047 #ifdef WIN32 // Windows
00048 m_ComPortHandle = INVALID_HANDLE_VALUE;
00049 #else // Posix
00050 m_FileDescriptor = INVALID_HANDLE_VALUE;
00051 #endif
00052 }
00053
00054
00055 mitk::SerialCommunication::~SerialCommunication()
00056 {
00057 CloseConnection();
00058 }
00059
00060
00061 int mitk::SerialCommunication::OpenConnection()
00062 {
00063 if (m_Connected)
00064 return ERROR_VALUE;
00065
00066 #ifdef WIN32
00067 std::stringstream ss;
00068 if (m_DeviceName.empty())
00069 ss << "COM" << static_cast<unsigned int>(m_PortNumber);
00070 else
00071 ss << m_DeviceName;
00072
00073 m_ComPortHandle = CreateFile(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE,
00074 NULL,
00075 NULL,
00076 OPEN_EXISTING,
00077 NULL,
00078 NULL);
00079 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
00080 return ERROR_VALUE;
00081
00082 GetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock);
00083 GetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout);
00084 GetCommMask(m_ComPortHandle, &m_PreviousMask);
00085
00086 if (this->ApplyConfiguration() != OK)
00087 {
00088 CloseHandle(m_ComPortHandle);
00089 m_ComPortHandle = INVALID_HANDLE_VALUE;
00090 return ERROR_VALUE;
00091 }
00092 m_Connected = true;
00093 return OK;
00094
00095 #else // Posix
00096 std::stringstream ss;
00097 if (m_DeviceName.empty())
00098 ss << "/dev/ttyS" << static_cast<unsigned int>(m_PortNumber) - 1;
00099 else
00100 ss << m_DeviceName;
00101
00102
00103 m_FileDescriptor = open(ss.str().c_str(), O_RDWR|O_NONBLOCK|O_EXCL);
00104 if (m_FileDescriptor < 0)
00105 return ERROR_VALUE;
00106
00107 fcntl(m_FileDescriptor, F_SETFL, 0);
00108 tcflush(m_FileDescriptor, TCIOFLUSH);
00109 if (this->ApplyConfiguration() != OK)
00110 {
00111 close(m_FileDescriptor);
00112 m_FileDescriptor = INVALID_HANDLE_VALUE;
00113 return ERROR_VALUE;
00114 }
00115 m_Connected = true;
00116 return OK;
00117 #endif
00118 }
00119
00120
00121 void mitk::SerialCommunication::CloseConnection()
00122 {
00123 #ifdef WIN32
00124 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
00125 return;
00126 ClearReceiveBuffer();
00127 ClearSendBuffer();
00128 SetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock);
00129 SetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout);
00130 SetCommMask(m_ComPortHandle, m_PreviousMask);
00131 PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
00132 CloseHandle(m_ComPortHandle);
00133 m_ComPortHandle = INVALID_HANDLE_VALUE;
00134 m_Connected = false;
00135 return;
00136
00137 #else // Posix
00138 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
00139 return;
00140 ClearReceiveBuffer();
00141 ClearSendBuffer();
00142 close(m_FileDescriptor);
00143 m_FileDescriptor = INVALID_HANDLE_VALUE;
00144 m_Connected = false;
00145 return;
00146 #endif
00147 }
00148
00149
00150 int mitk::SerialCommunication::Receive(std::string& answer, unsigned int numberOfBytes)
00151 {
00152 if (numberOfBytes == 0)
00153 return OK;
00154 if (m_Connected == false)
00155 return ERROR_VALUE;
00156
00157 #ifdef WIN32
00158 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
00159 return ERROR_VALUE;
00160
00161 DWORD numberOfBytesRead = 0;
00162 char* buffer = new char[numberOfBytes];
00163 if (ReadFile(m_ComPortHandle, buffer, numberOfBytes, &numberOfBytesRead, NULL) != 0)
00164 {
00165 if (numberOfBytesRead > 0)
00166 {
00167 answer.assign(buffer, numberOfBytesRead);
00168 if (numberOfBytesRead == numberOfBytes)
00169 return OK;
00170 else
00171 return ERROR_VALUE;
00172 }
00173 else
00174 {
00175 answer = "";
00176 return ERROR_VALUE;
00177 }
00178 }
00179 delete buffer;
00180 return OK;
00181
00182
00183 #else // Posix
00184 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
00185 return ERROR_VALUE;
00186
00187 unsigned long bytesRead = 0;
00188 unsigned long bytesLeft = numberOfBytes;
00189 char* buffer = new char[numberOfBytes];
00190
00191 while ((bytesLeft > 0) && (bytesRead < numberOfBytes))
00192 {
00193 int num = read(m_FileDescriptor, &buffer[bytesRead], 1);
00194 if (num == -1)
00195 {
00196 if (errno == EAGAIN)
00197 continue;
00198 else
00199 break;
00200 }
00201 if (num == 0)
00202 break;
00203
00204 bytesLeft -= num;
00205 bytesRead += num;
00206 }
00207 if (bytesRead > 0)
00208 answer.assign(buffer, bytesRead);
00209 delete buffer;
00210 if (bytesRead == numberOfBytes)
00211 return OK;
00212 else
00213 return ERROR_VALUE;
00214 #endif
00215 }
00216
00217
00218 int mitk::SerialCommunication::Send(const std::string& input)
00219 {
00220
00221 if (input.empty())
00222 return OK;
00223 if (m_Connected == false)
00224 return ERROR_VALUE;
00225
00226 #ifdef WIN32
00227 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
00228 return ERROR_VALUE;
00229
00230 DWORD bytesWritten = 0;
00231 if (WriteFile(m_ComPortHandle, input.data(), static_cast<DWORD>(input.size()), &bytesWritten, NULL) == TRUE)
00232 return OK;
00233 else
00234 return GetLastError();
00235
00236 #else // Posix
00237 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
00238 return ERROR_VALUE;
00239
00240 long bytesWritten = 0;
00241 long bytesLeft = input.size();
00242
00243 while (bytesLeft > 0)
00244 {
00245 bytesWritten = write(m_FileDescriptor, input.data() + bytesWritten, bytesLeft);
00246 if (bytesWritten <= 0)
00247 return ERROR_VALUE;
00248 bytesLeft -= bytesWritten;
00249 }
00250 return OK;
00251 #endif
00252 }
00253
00254
00255 int mitk::SerialCommunication::ApplyConfiguration()
00256 {
00257 #ifdef WIN32 // Windows implementation
00258 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
00259 return ERROR_VALUE;
00260
00261 DCB controlSettings;
00262 if (GetCommState(m_ComPortHandle, &controlSettings) == 0)
00263 {
00264 return ERROR_VALUE;
00265 }
00266
00267 std::ostringstream o;
00268 o << "baud=" << m_BaudRate << " parity=" << static_cast<char>(m_Parity) << " data=" << m_DataBits << " stop=" << m_StopBits;
00269 if (BuildCommDCBA(o.str().c_str(), &controlSettings) == 0)
00270 return ERROR_VALUE;
00271
00272 if (m_HardwareHandshake == HardwareHandshakeOn)
00273 {
00274 controlSettings.fDtrControl = DTR_CONTROL_ENABLE;
00275 controlSettings.fRtsControl = RTS_CONTROL_ENABLE;
00276 controlSettings.fOutxCtsFlow = TRUE;
00277 controlSettings.fRtsControl = RTS_CONTROL_HANDSHAKE;
00278 }
00279 else
00280 {
00281 controlSettings.fDtrControl = DTR_CONTROL_DISABLE;
00282 controlSettings.fRtsControl = RTS_CONTROL_DISABLE;
00283 controlSettings.fOutxCtsFlow = FALSE;
00284 controlSettings.fRtsControl = RTS_CONTROL_DISABLE;
00285 }
00286 if (SetCommState(m_ComPortHandle, &controlSettings) == FALSE)
00287 return GetLastError();
00288
00289 COMMTIMEOUTS timeouts;
00290
00291
00292 timeouts.ReadIntervalTimeout = m_ReceiveTimeout;
00293 timeouts.ReadTotalTimeoutMultiplier = 0;
00294 timeouts.ReadTotalTimeoutConstant = m_ReceiveTimeout;
00295 timeouts.WriteTotalTimeoutMultiplier = 0;
00296 timeouts.WriteTotalTimeoutConstant = m_SendTimeout;
00297 if (SetCommTimeouts(m_ComPortHandle, &timeouts) == FALSE)
00298 return GetLastError();
00299
00300 PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
00301 return OK;
00302
00303 #else // Posix
00304
00305 if ( m_FileDescriptor == INVALID_HANDLE_VALUE )
00306 return ERROR_VALUE;
00307
00308 struct termios termIOStructure;
00309 if ( tcgetattr(m_FileDescriptor, &termIOStructure) != 0 )
00310 return ERROR_VALUE;
00311
00312 cfmakeraw(&termIOStructure);
00313 termIOStructure.c_cflag |= CLOCAL;
00314 if (m_HardwareHandshake == HardwareHandshakeOn)
00315 {
00316 termIOStructure.c_cflag |= CRTSCTS;
00317 termIOStructure.c_iflag &= ~(IXON|IXOFF);
00318 }
00319 else
00320 {
00321 termIOStructure.c_cflag &= ~CRTSCTS;
00322 termIOStructure.c_iflag &= ~(IXON|IXOFF);
00323 }
00324 termIOStructure.c_cflag &= ~CSIZE;
00325 switch (m_DataBits)
00326 {
00327 case DataBits7:
00328 termIOStructure.c_cflag |= CS7;
00329 break;
00330 case DataBits8:
00331 default:
00332 termIOStructure.c_cflag |= CS8;
00333 }
00334 switch (m_StopBits)
00335 {
00336 case StopBits2:
00337 termIOStructure.c_cflag |= CSTOPB;
00338 break;
00339 case StopBits1:
00340 default:
00341 termIOStructure.c_cflag &= ~CSTOPB;
00342 }
00343 switch (m_Parity)
00344 {
00345 case Odd:
00346 termIOStructure.c_cflag |= (PARENB|PARODD);
00347 break;
00348 case Even:
00349 termIOStructure.c_cflag |= PARENB;
00350 termIOStructure.c_cflag &= ~PARODD;
00351 case None:
00352 default:
00353 termIOStructure.c_cflag &= ~PARENB;
00354 break;
00355 }
00356 speed_t baudrate;
00357 switch (m_BaudRate)
00358 {
00359 case BaudRate9600:
00360 baudrate = B9600;
00361 break;
00362 case BaudRate14400:
00363 baudrate = B9600;
00364 break;
00365 case BaudRate19200:
00366 baudrate = B19200;
00367 break;
00368 case BaudRate38400:
00369 baudrate = B38400;
00370 break;
00371 case BaudRate57600:
00372 baudrate = B57600;
00373 break;
00374 case BaudRate115200:
00375 baudrate = B115200;
00376 break;
00377 default:
00378 baudrate = B9600;
00379 break;
00380 }
00381 cfsetispeed(&termIOStructure, baudrate);
00382 cfsetospeed(&termIOStructure, baudrate);
00383
00384 termIOStructure.c_cc[VMIN] = 0;
00385 termIOStructure.c_cc[VTIME] = m_ReceiveTimeout / 100;
00386
00387 if (tcsetattr(m_FileDescriptor, TCSANOW, &termIOStructure) == 0)
00388 return OK;
00389 else
00390 return ERROR_VALUE;
00391 #endif
00392 }
00393
00394
00395 void mitk::SerialCommunication::SendBreak(unsigned int ms)
00396 {
00397 #ifdef WIN32
00398 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
00399 return;
00400 SetCommBreak(m_ComPortHandle);
00401 itksys::SystemTools::Delay(ms);
00402 ClearCommBreak(m_ComPortHandle);
00403 return;
00404
00405 #else // Posix
00406
00407 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
00408 return;
00409 tcsendbreak(m_FileDescriptor, ms);
00410 return;
00411 #endif
00412 }
00413
00414
00415 void mitk::SerialCommunication::ClearReceiveBuffer()
00416 {
00417 #ifdef WIN32
00418 if (m_ComPortHandle != INVALID_HANDLE_VALUE)
00419 PurgeComm(m_ComPortHandle, PURGE_RXCLEAR);
00420 #else // Posix
00421 if (m_FileDescriptor != INVALID_HANDLE_VALUE)
00422 tcflush(m_FileDescriptor, TCIFLUSH);
00423 #endif
00424 }
00425
00426
00427 void mitk::SerialCommunication::ClearSendBuffer()
00428 {
00429 #ifdef WIN32
00430 if ( m_ComPortHandle != INVALID_HANDLE_VALUE )
00431 PurgeComm(m_ComPortHandle, PURGE_TXCLEAR);
00432 #else // Posix
00433 if ( m_FileDescriptor != INVALID_HANDLE_VALUE )
00434 tcflush(m_FileDescriptor, TCOFLUSH);
00435 #endif
00436 }