MITK-IGT
IGT Extension of MITK
Loading...
Searching...
No Matches
mitkSerialCommunication.cpp
Go to the documentation of this file.
1/*============================================================================
2
3The Medical Imaging Interaction Toolkit (MITK)
4
5Copyright (c) German Cancer Research Center (DKFZ)
6All rights reserved.
7
8Use of this source code is governed by a 3-clause BSD license that can be
9found in the LICENSE file.
10
11============================================================================*/
12
14
15#ifdef WIN32
16//#include <atlstr.h>
17#include <itksys/SystemTools.hxx>
18#else // Posix
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <sys/time.h>
22#include <sys/ioctl.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <termios.h>
26#include <cerrno>
27
28#define INVALID_HANDLE_VALUE -1
29#endif
30
31#define OK 1
32#define ERROR_VALUE 0
33
35 m_DeviceName(""), m_PortNumber(COM1), m_BaudRate(BaudRate9600),
36 m_DataBits(DataBits8), m_Parity(None), m_StopBits(StopBits1),
37 m_HardwareHandshake(HardwareHandshakeOff),
38 m_ReceiveTimeout(500), m_SendTimeout(500), m_Connected(false)
39{
40#ifdef WIN32 // Windows
41 m_ComPortHandle = INVALID_HANDLE_VALUE;
42#else // Posix
44#endif
45}
46
51
53{
54 return m_Connected;
55}
56
58{
59 if (m_Connected)
60 return ERROR_VALUE;
61
62#ifdef WIN32
63 std::stringstream ss;
64 if (m_DeviceName.empty())
65 ss << "\\\\.\\COM" << static_cast<unsigned int>(m_PortNumber); // use m_PortNumber
66 else
67 ss << "\\\\.\\" << m_DeviceName; // use m_DeviceName
68
69 m_ComPortHandle = CreateFileA(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE,
70 0, // no sharing
71 0, // no security flags
72 OPEN_EXISTING, // open com port, don't create it
73 0, // no flags
74 0); // no template
75 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
76 return ERROR_VALUE;
77
78 GetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock);
79 GetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout);
80 GetCommMask(m_ComPortHandle, &m_PreviousMask);
81
82 if (this->ApplyConfiguration() != OK) // set interface parameters
83 {
84 CloseHandle(m_ComPortHandle);
85 m_ComPortHandle = INVALID_HANDLE_VALUE;
86 return ERROR_VALUE;
87 }
88 m_Connected = true;
89 return OK;
90
91#else // Posix
92 std::stringstream ss;
93 if (m_DeviceName.empty())
94 ss << "/dev/ttyS" << static_cast<unsigned int>(m_PortNumber) - 1; // use m_PortNumber, COM1 = ttyS0
95 else
96 ss << m_DeviceName; // use m_DeviceName
97
98 //m_FileDescriptor = open(ss.str().c_str(), O_RDWR | O_NONBLOCK | O_NDELAY | O_NOCTTY | O_EXCL); // open device file
99 m_FileDescriptor = open(ss.str().c_str(), O_RDWR|O_NONBLOCK|O_EXCL); // open device file
100 if (m_FileDescriptor < 0)
101 return ERROR_VALUE;
102
103 fcntl(m_FileDescriptor, F_SETFL, 0); // change to blocking mode
104 tcflush(m_FileDescriptor, TCIOFLUSH); // flush buffers
105 if (this->ApplyConfiguration() != OK) // set interface parameters
106 {
107 close(m_FileDescriptor);
108 m_FileDescriptor = INVALID_HANDLE_VALUE;
109 return ERROR_VALUE;
110 }
111 m_Connected = true;
112 return OK;
113#endif
114}
115
117{
118#ifdef WIN32
119 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
120 return;
121 ClearReceiveBuffer();
122 ClearSendBuffer();
123 SetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); // restore previous settings
124 SetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); // restore previous timeout values
125 SetCommMask(m_ComPortHandle, m_PreviousMask); // restore previous mask value
126 PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // empty buffers
127 CloseHandle(m_ComPortHandle); // close handle
128 m_ComPortHandle = INVALID_HANDLE_VALUE;
129 m_Connected = false;
130 return;
131
132#else // Posix
133 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
134 return;
135 ClearReceiveBuffer();
136 ClearSendBuffer();
137 close(m_FileDescriptor);
138 m_FileDescriptor = INVALID_HANDLE_VALUE;
139 m_Connected = false;
140 return;
141#endif
142}
143
144int mitk::SerialCommunication::Receive(std::string& answer, unsigned int numberOfBytes, const char *eol)
145{
146 if (numberOfBytes == 0)
147 return OK;
148 if (m_Connected == false)
149 return ERROR_VALUE;
150
151#ifdef WIN32
152 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
153 return ERROR_VALUE;
154
155 DWORD numberOfBytesRead = 0;
156 char* buffer = new char[numberOfBytes];
157 if (ReadFile(m_ComPortHandle, buffer, numberOfBytes, &numberOfBytesRead, nullptr) != 0)
158 {
159 if (numberOfBytesRead > 0) // data read
160 {
161 answer.assign(buffer, numberOfBytesRead); // copy buffer to answer
162 delete buffer;
163 if (numberOfBytesRead == numberOfBytes)
164 {
165 return OK; // everything was received
166 }
167 else
168 {
169 return ERROR_VALUE; // some data was received, but not as much as expected
170 }
171 }
172 else // error
173 {
174 answer = "";
175 delete buffer;
176 return ERROR_VALUE;
177 }
178 }
179 delete buffer;
180 return OK;
181
182#else // Posix
183 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
184 return ERROR_VALUE;
185
186 unsigned long bytesRead = 0;
187 unsigned long bytesLeft = numberOfBytes;
188 auto buffer = new char[numberOfBytes];
189
190 while ((bytesLeft > 0) && (bytesRead < numberOfBytes))
191 {
192 int num = read(m_FileDescriptor, &buffer[bytesRead], 1); // read one byte
193 if (num == -1) // ERROR_VALUE
194 {
195 if (errno == EAGAIN) // nonblocking, no byte there right now, but maybe next time
196 continue;
197 else
198 break; // ERROR_VALUE, stop trying to read
199 }
200 if (num == 0) // timeout or eof(?)
201 break;
202
203 bytesLeft -= num; // n is number of chars left to read
204 bytesRead += num; // i is the number of chars read
205
206 if (eol && *eol == buffer[bytesRead-1]) // end of line char reached
207 break;
208 }
209 if (bytesRead > 0)
210 answer.assign(buffer, bytesRead); // copy buffer to answer
211
212 delete[] buffer;
213
214 if ( bytesRead == numberOfBytes || // everything was received
215 (eol && answer.size() > 0 && *eol == answer.at(answer.size()-1)) ) // end of line char reached
216 return OK;
217 else
218 return ERROR_VALUE; // some data was received, but not as much as expected
219#endif
220}
221
222int mitk::SerialCommunication::Send(const std::string& input, bool block)
223{
224 //long retval = E2ERR_OPENFAILED;
225 if (input.empty())
226 return OK;
227 if (m_Connected == false)
228 return ERROR_VALUE;
229
230#ifdef WIN32
231 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
232 return ERROR_VALUE;
233
234 DWORD bytesWritten = 0;
235 if (WriteFile(m_ComPortHandle, input.data(), static_cast<DWORD>(input.size()), &bytesWritten, nullptr) == TRUE)
236 return OK;
237 else
238 return ERROR_VALUE;
239
240#else // Posix
241 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
242 return ERROR_VALUE;
243
244 long bytesWritten = 0;
245 long bytesLeft = input.size();
246
247 while (bytesLeft > 0)
248 {
249 bytesWritten = write(m_FileDescriptor, input.data() + bytesWritten, bytesLeft);
250 if (bytesWritten <= 0)
251 return ERROR_VALUE; //return ERROR_VALUE
252 bytesLeft -= bytesWritten;
253 }
254 if (block)
255 {
256 // wait for output to be physically sent
257 if (tcdrain(m_FileDescriptor) == -1)
258 return ERROR_VALUE;
259 }
260 return OK;
261#endif
262}
263
265{
266#ifdef WIN32 // Windows implementation
267 return ApplyConfigurationWin();
268#else // Posix
269 return ApplyConfigurationUnix();
270#endif
271}
272
277#ifdef WIN32
278int mitk::SerialCommunication::ApplyConfigurationWin()
279{
280 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
281 return ERROR_VALUE;
282
283 DCB controlSettings;
284 if (GetCommState(m_ComPortHandle, &controlSettings) == 0)
285 {
286 return ERROR_VALUE;
287 }
288
289 std::ostringstream o;
290 o << "baud=" << m_BaudRate << " parity=" << static_cast<char>(m_Parity) << " data=" << m_DataBits << " stop=" << m_StopBits;
291 if (BuildCommDCBA(o.str().c_str(), &controlSettings) == 0) // Build device-control block
292 return ERROR_VALUE;
293
294 if (m_HardwareHandshake == HardwareHandshakeOn) // Modify hardware handshake values
295 {
296 controlSettings.fDtrControl = DTR_CONTROL_ENABLE;
297 controlSettings.fRtsControl = RTS_CONTROL_ENABLE;
298 controlSettings.fOutxCtsFlow = TRUE;
299 controlSettings.fRtsControl = RTS_CONTROL_HANDSHAKE;
300 }
301 else
302 {
303 controlSettings.fDtrControl = DTR_CONTROL_DISABLE;
304 controlSettings.fRtsControl = RTS_CONTROL_DISABLE;
305 controlSettings.fOutxCtsFlow = FALSE;
306 controlSettings.fRtsControl = RTS_CONTROL_DISABLE;
307 }
308 if (SetCommState(m_ComPortHandle, &controlSettings) == FALSE) // Configure com port
309 return ERROR_VALUE;
310
311 COMMTIMEOUTS timeouts;
312
313 timeouts.ReadIntervalTimeout = m_ReceiveTimeout;
314 timeouts.ReadTotalTimeoutMultiplier = 0;
315 timeouts.ReadTotalTimeoutConstant = m_ReceiveTimeout;
316 timeouts.WriteTotalTimeoutMultiplier = 0;
317 timeouts.WriteTotalTimeoutConstant = m_SendTimeout;
318 if (SetCommTimeouts(m_ComPortHandle, &timeouts) == FALSE) // set timeout values
319 return ERROR_VALUE;
320
321 PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // clear read and write buffers
322 return OK;
323}
324
325#else
330{
331 if ( m_FileDescriptor == INVALID_HANDLE_VALUE )
332 return ERROR_VALUE;
333
334 struct termios termIOStructure;
335 if ( tcgetattr(m_FileDescriptor, &termIOStructure) != 0 ) // retrieve parameters from com port
336 return ERROR_VALUE;
337
338 cfmakeraw(&termIOStructure); // set flags to raw mode
339 termIOStructure.c_cflag |= CLOCAL;
340 if (m_HardwareHandshake == HardwareHandshakeOn)
341 { // enable
342 termIOStructure.c_cflag |= CRTSCTS;
343 termIOStructure.c_iflag &= ~(IXON|IXOFF);
344 }
345 else
346 { // disable
347 termIOStructure.c_cflag &= ~CRTSCTS;
348 termIOStructure.c_iflag &= ~(IXON|IXOFF);
349 }
350 termIOStructure.c_cflag &= ~CSIZE; // set number of data bits
351 switch (m_DataBits)
352 {
353 case DataBits7:
354 termIOStructure.c_cflag |= CS7;
355 break;
356 case DataBits8:
357 default:
358 termIOStructure.c_cflag |= CS8;
359 }
360 switch (m_StopBits) // set number of stop bits
361 {
362 case StopBits2:
363 termIOStructure.c_cflag |= CSTOPB;
364 break;
365 case StopBits1:
366 default:
367 termIOStructure.c_cflag &= ~CSTOPB;
368 }
369 switch (m_Parity) // set parity
370 {
371 case Odd:
372 termIOStructure.c_cflag |= (PARENB|PARODD);
373 break;
374 case Even:
375 termIOStructure.c_cflag |= PARENB;
376 termIOStructure.c_cflag &= ~PARODD;
377 // TODO: check if this is intended
378 // FALLTHRU
379 case None:
380 // FALLTHRU
381 default:
382 termIOStructure.c_cflag &= ~PARENB;
383 break;
384 }
385 speed_t baudrate; // set baudrate
386 switch (m_BaudRate)
387 {
388 case BaudRate9600:
389 baudrate = B9600;
390 break;
391 case BaudRate14400:
392 baudrate = B9600; //14400 is not defined for posix, use 9600 instead
393 break;
394 case BaudRate19200:
395 baudrate = B19200;
396 break;
397 case BaudRate38400:
398 baudrate = B38400;
399 break;
400 case BaudRate57600:
401 baudrate = B57600;
402 break;
403 case BaudRate115200:
404 baudrate = B115200;
405 break;
406 case BaudRate230400:
407 baudrate = B230400;
408 break;
409 // the following baud rates do not work for apple
410 #ifndef __APPLE__
411 case BaudRate460800:
412 baudrate = B460800;
413 break;
414 case BaudRate500000:
415 baudrate = B500000;
416 break;
417 case BaudRate576000:
418 baudrate = B576000;
419 break;
420 case BaudRate921600:
421 baudrate = B921600;
422 break;
423 case BaudRate1000000:
424 baudrate = B1000000;
425 break;
426 case BaudRate1152000:
427 baudrate = B1152000;
428 break;
429 //case BaudRate1228739:
430 //baudrate = B1228739;
431 //break;
432 case BaudRate1500000:
433 baudrate = B1500000;
434 break;
435 case BaudRate2000000:
436 baudrate = B2000000;
437 break;
438 case BaudRate2500000:
439 baudrate = B2500000;
440 break;
441 case BaudRate3000000:
442 baudrate = B3000000;
443 break;
444 case BaudRate3500000:
445 baudrate = B3500000;
446 break;
447 case BaudRate4000000:
448 baudrate = B4000000;
449 break;
450 #endif
451 default:
452 MITK_WARN("mitk::SerialCommunication") << "Baud rate not recognized, using default of 9600 Baud.";
453 baudrate = B9600;
454 break;
455 }
456 cfsetispeed(&termIOStructure, baudrate);
457 cfsetospeed(&termIOStructure, baudrate);
458
459 termIOStructure.c_cc[VMIN] = 0;
460 termIOStructure.c_cc[VTIME] = m_ReceiveTimeout / 100; // timeout in 1/10 sec, not in ms. Rounded down.
461
462 if (tcsetattr(m_FileDescriptor, TCSANOW, &termIOStructure) == 0)
463 return OK;
464 else
465 return ERROR_VALUE;
466}
467
468#endif
469
470
472{
473#ifdef WIN32
474 if (m_ComPortHandle == INVALID_HANDLE_VALUE)
475 return;
476 SetCommBreak(m_ComPortHandle);
477 itksys::SystemTools::Delay(ms);
478 ClearCommBreak(m_ComPortHandle);
479 return;
480
481#else // Posix
482
483 if (m_FileDescriptor == INVALID_HANDLE_VALUE)
484 return;
485 tcsendbreak(m_FileDescriptor, ms);
486 return;
487#endif
488}
489
491{
492#ifdef WIN32
493 if (m_ComPortHandle != INVALID_HANDLE_VALUE)
494 PurgeComm(m_ComPortHandle, PURGE_RXCLEAR);
495#else // Posix
496 if (m_FileDescriptor != INVALID_HANDLE_VALUE)
497 tcflush(m_FileDescriptor, TCIFLUSH);
498#endif
499}
500
502{
503#ifdef WIN32
504 if ( m_ComPortHandle != INVALID_HANDLE_VALUE )
505 PurgeComm(m_ComPortHandle, PURGE_TXCLEAR);
506#else // Posix
507 if ( m_FileDescriptor != INVALID_HANDLE_VALUE )
508 tcflush(m_FileDescriptor, TCOFLUSH);
509#endif
510}
void ClearSendBuffer()
erase the send buffer of the serial interface
int ApplyConfigurationUnix()
Applies the configuration for Linux.
void SendBreak(unsigned int ms=400)
Send the break signal for ms milliseconds.
int OpenConnection()
Opens connection to the COM port with port number m_PortNumber or the device name m_DeviceName and al...
bool IsConnected()
Returns m_Connected.
int Send(const std::string &input, bool block=false)
Send the string input.
void CloseConnection()
Closes the connection.
int Receive(std::string &answer, unsigned int numberOfBytes, const char *eol=nullptr)
Read numberOfBytes characters from the serial interface.
int ApplyConfiguration()
configures the serial interface with all parameters
void ClearReceiveBuffer()
erase the receive buffer of the serial interface
#define ERROR_VALUE
#define INVALID_HANDLE_VALUE
int open(const char *, int)
Opens a file descriptor.
int read(int, char *, size_t)
Read bytes from a file descriptor.
int errno
Contains the last error code.
Definition structcmd.h:53
int close(int)
Closes the file descriptor fd.
size_t write(int, const char *, size_t)
Writes count bytes from buf to the filedescriptor fd.