00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "cxutils/serial.h"
00041 #include <iostream>
00042 #include <string.h>
00043
00044 #ifdef WIN32
00045 #include <winsock.h>
00046 #include <windows.h>
00047 #ifndef MINGW
00048 #include <atlbase.h>
00049 #else
00050 #define USES_CONVERSION
00051 #define A2W(x) (x)
00052 #define W2A(x) (x)
00053 #endif
00054 #else
00055 #include <sys/types.h>
00056 #include <sys/ioctl.h>
00057 #include <fcntl.h>
00058 #include <termios.h>
00059 #include <unistd.h>
00060 #endif
00061
00062 using namespace CxUtils;
00063
00069 Serial::Serial()
00070 {
00071 mConnected = false;
00072 mBaudRate = 9600;
00073 mDataBits = 8;
00074 mStopBits = 1;
00075 mParity = 'N';
00076 mPortName = "";
00077 #ifdef WIN32
00078 mCom = NULL;
00079 #else
00080 mCom = 0;
00081 #endif
00082 }
00083
00084
00092 Serial::~Serial()
00093 {
00094 if(mConnected)
00095 Disconnect();
00096 }
00097
00098
00115 int Serial::Connect(const std::string& port,
00116 const unsigned int baud,
00117 const unsigned int bits,
00118 const unsigned int parity,
00119 const unsigned int stop)
00120 {
00121 int result = 0;
00122
00123 if(mConnected)
00124 Disconnect();
00125
00126 if(parity > (unsigned int)(CX_SERIAL_ODD_PARITY) || port.empty())
00127 return 0;
00128
00129 mBaudRate = baud;
00130 mParity = parity;
00131 mStopBits = stop;
00132 mDataBits = bits;
00133
00134 #ifdef WIN32
00135
00136 DCB comDCB;
00137 mLastError = ERROR_SUCCESS;
00138
00139
00140
00141 COMMTIMEOUTS timeouts;
00142
00143 mPortName = "\\\\.\\";
00144 mPortName += port;
00145
00146 mCom = CreateFileA( mPortName.c_str(),
00147 GENERIC_READ | GENERIC_WRITE,
00148 0,
00149 0,
00150 OPEN_EXISTING,
00151 FILE_FLAG_OVERLAPPED,
00152 0);
00153
00154 if(mCom == NULL || mCom == INVALID_HANDLE_VALUE)
00155 {
00156 mLastError = GetLastError();
00157 return result;
00158 }
00159
00160 ZeroMemory(&comDCB, sizeof(DCB));
00161
00162 comDCB.DCBlength = sizeof(DCB);
00163
00164 GetCommState(mCom, &comDCB);
00165
00166 comDCB.BaudRate = mBaudRate;
00167 comDCB.ByteSize = mDataBits;
00168 comDCB.fBinary = TRUE;
00169 comDCB.fDsrSensitivity = false;
00170 comDCB.fAbortOnError = TRUE;
00171 comDCB.fOutxCtsFlow = FALSE;
00172 comDCB.fOutxDsrFlow = FALSE;
00173 comDCB.fOutX = FALSE;
00174 comDCB.fInX = FALSE;
00175 comDCB.ByteSize = mDataBits;
00176 comDCB.fRtsControl = RTS_CONTROL_DISABLE;
00177 comDCB.fDtrControl = DTR_CONTROL_DISABLE;
00178
00179 switch(mStopBits)
00180 {
00181 case 1:
00182 comDCB.StopBits = ONESTOPBIT;
00183 break;
00184 case 2:
00185 comDCB.StopBits = ONE5STOPBITS;
00186 break;
00187 case 3:
00188 comDCB.StopBits = TWOSTOPBITS;
00189 break;
00190 default:
00191 comDCB.StopBits = ONESTOPBIT;
00192 break;
00193 };
00194
00195 comDCB.fParity = TRUE;
00196 switch(mParity)
00197 {
00198 case 0:
00199 comDCB.Parity = NOPARITY;
00200 break;
00201 case 1:
00202 comDCB.Parity = EVENPARITY;
00203 break;
00204 case 2:
00205 comDCB.Parity = ODDPARITY;
00206 break;
00207 default:
00208 comDCB.Parity = NOPARITY;
00209 break;
00210 };
00211
00212 SetCommState(mCom, &comDCB);
00213
00214
00215
00216 GetCommTimeouts(mCom, &timeouts);
00217
00218
00219 timeouts.ReadIntervalTimeout = 4294967295UL;
00220 timeouts.ReadTotalTimeoutConstant = 4294967295UL;
00221 timeouts.ReadTotalTimeoutMultiplier = 500;
00222 timeouts.WriteTotalTimeoutConstant = 1;
00223 timeouts.WriteTotalTimeoutMultiplier = 500;
00224
00225
00226 SetCommTimeouts(mCom, &timeouts);
00227
00228 mConnected = true;
00229
00230 result = 1;
00231
00232 #else
00233
00234 struct termios options;
00235
00236 bzero(&options, sizeof(struct termios));
00237
00238 mPortName = port;
00239
00240 mCom = open(mPortName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
00241 if(mCom == -1)
00242 {
00243 std::cout << "Error: Could not open port " << mPortName << std::endl;
00244 return 0;
00245 }
00246 else
00247 {
00248 fcntl(mCom, F_SETOWN, getpid());
00249
00250 }
00251
00252 options.c_cflag |= (CLOCAL | CREAD);
00253
00254
00255
00256
00257
00258
00259
00260 switch(mBaudRate)
00261 {
00262 case 9600:
00263 cfsetispeed(&options, B9600);
00264 cfsetospeed(&options, B9600);
00265 break;
00266 case 19200:
00267 cfsetispeed(&options, B19200);
00268 cfsetospeed(&options, B19200);
00269 break;
00270 case 38400:
00271 cfsetispeed(&options, B38400);
00272 cfsetospeed(&options, B38400);
00273 break;
00274 case 57600:
00275 cfsetispeed(&options, B57600);
00276 cfsetospeed(&options, B57600);
00277 break;
00278
00279 case 115200:
00280 cfsetispeed(&options, B115200);
00281 cfsetospeed(&options, B115200);
00282 break;
00283 case 230400:
00284 cfsetispeed(&options, B230400);
00285 cfsetospeed(&options, B230400);
00286 break;
00287 case 460800:
00288 cfsetispeed(&options, B460800);
00289 cfsetospeed(&options, B460800);
00290 break;
00291 case 921600:
00292 cfsetispeed(&options, B921600);
00293 cfsetospeed(&options, B921600);
00294 break;
00295 default:
00296 cfsetispeed(&options, mBaudRate);
00297 cfsetospeed(&options, mBaudRate);
00298 break;
00299 }
00300
00301
00302 options.c_cflag &= ~CRTSCTS;
00303
00304
00305 options.c_cflag &= ~CSIZE;
00306 switch(mDataBits)
00307 {
00308 case 8:
00309 options.c_cflag |= CS8;
00310 break;
00311 case 7:
00312 options.c_cflag |= CS7;
00313 break;
00314 case 6:
00315 options.c_cflag |= CS6;
00316 break;
00317 case 5:
00318 options.c_cflag |= CS5;
00319 break;
00320 default:
00321 options.c_cflag |= CS8;
00322 break;
00323 }
00324
00325 if(mParity)
00326 {
00327 if(mParity == CX_SERIAL_EVEN_PARITY)
00328 {
00329 options.c_cflag |= PARENB;
00330 options.c_cflag &= ~PARODD;
00331
00332 }
00333 else
00334 {
00335 options.c_cflag |= PARENB;
00336 options.c_cflag |= PARODD;
00337
00338 }
00339 }
00340 else
00341 {
00342 options.c_cflag &= ~PARENB;
00343 options.c_iflag |= IGNPAR;
00344 }
00345
00346
00347 if(mStopBits == 2)
00348 {
00349 options.c_cflag |= CSTOPB;
00350 }
00351 else
00352 {
00353 options.c_cflag &= ~CSTOPB;
00354 }
00355
00356 tcflush(mCom, TCIFLUSH);
00357 if(tcsetattr(mCom, TCSANOW, &options) >= 0)
00358 {
00359 mConnected = true;
00360 result = 1;
00361 }
00362
00363
00364
00365 int status;
00366 ioctl(mCom, TIOCMGET, &status);
00367 status &= ~TIOCM_DTR;
00368
00369
00370 status &= ~TIOCM_RTS;
00371
00372
00373 ioctl(mCom, TIOCMSET, &status);
00374
00375 #endif
00376 return result;
00377 }
00378
00379
00387 int Serial::Disconnect()
00388 {
00389 #ifdef WIN32
00390 PurgeComm(mCom, PURGE_RXABORT);
00391 CloseHandle(mCom);
00392 mConnected = false;
00393 mCom = NULL;
00394 mPortName = "";
00395 return 1;
00396 #else
00397 if(mCom != 0)
00398 {
00399 close(mCom);
00400 }
00401 mConnected = false;
00402 mCom = 0;
00403 mPortName = "";
00404 return 1;
00405 #endif
00406 }
00407
00408
00417 int Serial::Reconnect()
00418 {
00419 return Connect(mPortName.c_str(), mBaudRate, mDataBits, mParity, mStopBits);
00420 }
00421
00422
00433 int Serial::Send(const char *buff, const unsigned int size)
00434 {
00435 Mutex::ScopedLock lock(&mSerialMutex);
00436 #ifdef WIN32
00437 OVERLAPPED osWrite = {0};
00438 DWORD dwWritten = 0;
00439 DWORD dwRes = WAIT_TIMEOUT;
00440 BOOL fRes;
00441
00442
00443 osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
00444 if (osWrite.hEvent == NULL)
00445 {
00446
00447 return 0;
00448 }
00449
00450 if (!WriteFile(mCom, buff, size, &dwWritten, &osWrite))
00451 {
00452 if (GetLastError() != ERROR_IO_PENDING)
00453 {
00454
00455 fRes = FALSE;
00456 }
00457 else
00458 {
00459
00460 dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
00461 switch(dwRes)
00462 {
00463
00464 case WAIT_OBJECT_0:
00465 if (!GetOverlappedResult(mCom, &osWrite, &dwWritten, FALSE))
00466 {
00467 fRes = FALSE;
00468 }
00469 else
00470 {
00471
00472 fRes = TRUE;
00473 }
00474 break;
00475 default:
00476
00477
00478
00479 fRes = FALSE;
00480 break;
00481 }
00482 }
00483 }
00484 else
00485 {
00486
00487 fRes = TRUE;
00488 }
00489
00490 CloseHandle(osWrite.hEvent);
00491 return (int)dwWritten;
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 #else
00510
00511 if(mConnected)
00512 {
00513 int sum;
00514 sum = write(mCom, buff, size);
00515
00516 if( sum < 0 )
00517 return 0;
00518 return (int)sum;
00519 }
00520
00521 #endif
00522 return 0;
00523 }
00524
00525
00535 int Serial::Send(const Packet& p)
00536 {
00537 Mutex::ScopedLock lock(&mSerialMutex);
00538 return Send((const char *)p.Ptr(), (unsigned int)p.Length());
00539 }
00540
00541
00551 int Serial::Send(const std::string& message)
00552 {
00553 Mutex::ScopedLock lock(&mSerialMutex);
00554 return Send(message.c_str(), ((unsigned int)message.size()));
00555 }
00556
00557
00571 int Serial::Recv(char *buff, unsigned int size, const unsigned int waitTimeMs)
00572 {
00573 #ifdef WIN32
00574 DWORD sum = 0;
00575 BOOL readOK = FALSE;
00576 if(mConnected)
00577 {
00578 char* ptr = buff;
00579 unsigned int totalRead = 0;
00580
00581 Time::Stamp startTimeMs = Time::GetUtcTimeMs();
00582 for(totalRead = 0; totalRead < size && Time::GetUtcTimeMs() - startTimeMs <= waitTimeMs;)
00583 {
00584 sum = 0;
00585 DWORD dwRead = 0;
00586 BOOL fWaitingOnRead = FALSE;
00587 OVERLAPPED osReader = {0};
00588 char temp[5];
00589
00590
00591
00592 osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
00593
00594 if (osReader.hEvent == NULL)
00595 {
00596 }
00597
00598 if (!fWaitingOnRead)
00599 {
00600
00601 if (!ReadFile(mCom, temp, 1, &dwRead, &osReader))
00602 {
00603 if (GetLastError() != ERROR_IO_PENDING)
00604 {
00605
00606 }
00607 else
00608 {
00609 fWaitingOnRead = TRUE;
00610 }
00611 }
00612 else
00613 {
00614 sum = dwRead;
00615 }
00616 }
00617
00618
00619 DWORD dwRes = WAIT_TIMEOUT;
00620
00621 if (fWaitingOnRead)
00622 {
00623 dwRes = WaitForSingleObject(osReader.hEvent, waitTimeMs);
00624 switch(dwRes)
00625 {
00626
00627 case WAIT_OBJECT_0:
00628 if (!GetOverlappedResult(mCom, &osReader, &dwRead, FALSE))
00629 {
00630
00631 }
00632 else
00633 {
00634 sum = dwRead;
00635
00636 }
00637
00638
00639 fWaitingOnRead = FALSE;
00640 break;
00641 case WAIT_TIMEOUT:
00642
00643
00644
00645
00646 break;
00647 default:
00648
00649
00650
00651 break;
00652 }
00653 }
00654
00655 if(sum > 0)
00656 {
00657 memcpy(&buff[totalRead], temp, sum);
00658 totalRead += (unsigned int)sum;
00659
00660 }
00661 }
00662
00663 return (int)totalRead;
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 #else
00678 if(mConnected)
00679 {
00680 int sum;
00681
00682 sum = read(mCom, buff, size);
00683
00684 if( sum < 0 )
00685 return 0;
00686 return sum;
00687 }
00688 #endif
00689 return 0;
00690 }
00691
00692
00706 int Serial::Recv(Packet& p, unsigned int len, const unsigned int waitTimeMs)
00707 {
00708 p.Clear();
00709 #ifdef WIN32
00710 p.Reserve(len + 256);
00711 int bytesRead = 0;
00712 if( (bytesRead = Recv((char *)p.Ptr(), len, waitTimeMs)) > 0)
00713 {
00714 p.SetWritePos(0);
00715 p.SetReadPos(0);
00716 p.SetLength((unsigned int)bytesRead);
00717
00718 return bytesRead;
00719 }
00720 #else
00721
00722 if(mConnected)
00723 {
00724 int sum;
00725 p.Reserve(len);
00726
00727 sum = read(mCom, (char*)p.Ptr(), len);
00728 if(sum > 0)
00729 {
00730 p.SetWritePos(0);
00731 p.SetReadPos(0);
00732 p.SetLength(sum);
00733 }
00734 else
00735 p.Clear();
00736
00737 if( sum < 0 )
00738 return 0;
00739 return sum;
00740 }
00741 #endif
00742
00743 return 0;
00744 }
00745
00746
00752 void Serial::Flush()
00753 {
00754 #ifdef WIN32
00755 FlushReadBuffer();
00756 FlushWriteBuffer();
00757
00758
00759
00760
00761
00762
00763 #else
00764 if(mCom)
00765 {
00766 tcflush(mCom, TCIOFLUSH );
00767 }
00768 #endif
00769 }
00770
00771
00778 void Serial::FlushReadBuffer()
00779 {
00780 #ifdef WIN32
00781 if( mCom)
00782 {
00783 PurgeComm(mCom, PURGE_RXCLEAR);
00784 }
00785 #else
00786 if(mCom)
00787 {
00788 tcflush(mCom, TCIFLUSH);
00789 }
00790 #endif
00791 }
00792
00793
00800 void Serial::FlushWriteBuffer()
00801 {
00802 #ifdef WIN32
00803 if( mCom)
00804 {
00805 PurgeComm(mCom, PURGE_TXCLEAR);
00806 }
00807 #else
00808 if(mCom)
00809 {
00810 tcflush(mCom, TCIOFLUSH );
00811 }
00812 #endif
00813 }
00814
00821 void Serial::Reset()
00822 {
00823 #ifdef WIN32
00824 if( mCom)
00825 {
00826 PurgeComm(mCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
00827 }
00828 #else
00829 if(mCom)
00830 {
00831 tcflush(mCom, TCIOFLUSH);
00832 }
00833 #endif
00834 }
00835
00843 unsigned int Serial::ReadBytesAvailable(void)
00844 {
00845 #ifdef WIN32
00846 COMSTAT comStat;
00847 if (ClearCommError(mCom, &mErrors, &comStat))
00848 {
00849 return comStat.cbInQue;
00850 }
00851 #else
00852 int bytes = 0;
00853 ioctl(mCom, FIONREAD, &bytes);
00854 return (unsigned int)bytes;
00855 #endif
00856 return 0;
00857 }
00858
00866 unsigned int Serial::WriteBytesPending(void)
00867 {
00868 #ifdef WIN32
00869 COMSTAT comStat;
00870 if (ClearCommError(mCom, &mErrors, &comStat))
00871 {
00872 return comStat.cbOutQue;
00873 }
00874 #else
00875 int bytes = 0;
00876
00877 return (unsigned int)bytes;
00878 #endif
00879 return 0;
00880 }
00881
00882