MOOS 0.2375
|
00001 00002 // 00003 // MOOS - Mission Oriented Operating Suite 00004 // 00005 // A suit of Applications and Libraries for Mobile Robotics Research 00006 // Copyright (C) 2001-2005 Massachusetts Institute of Technology and 00007 // Oxford University. 00008 // 00009 // This software was written by Paul Newman at MIT 2001-2002 and Oxford 00010 // University 2003-2005. email: pnewman@robots.ox.ac.uk. 00011 // 00012 // This file is part of a MOOS Core Component. 00013 // 00014 // This program is free software; you can redistribute it and/or 00015 // modify it under the terms of the GNU General Public License as 00016 // published by the Free Software Foundation; either version 2 of the 00017 // License, or (at your option) any later version. 00018 // 00019 // This program is distributed in the hope that it will be useful, 00020 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00022 // General Public License for more details. 00023 // 00024 // You should have received a copy of the GNU General Public License 00025 // along with this program; if not, write to the Free Software 00026 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00027 // 02111-1307, USA. 00028 // 00030 // MOOSSerialPort.cpp: implementation of the CMOOSSerialPort class. 00031 // 00033 #ifdef _WIN32 00034 #pragma warning(disable : 4786) 00035 #endif 00036 00037 #include <cstring> 00038 00039 #ifdef _WIN32 00040 #include <winsock2.h> 00041 #include "windows.h" 00042 #include "winbase.h" 00043 #include "winnt.h" 00044 #else 00045 #include <pthread.h> 00046 #endif 00047 00048 #define DEFAULT_COMMS_SPACE 1000 00049 #define MOOS_SERIAL_INBOX_MAX_SIZE 1000 00050 00051 00052 #include "MOOSGenLibGlobalHelper.h" 00053 #include "MOOSSerialPort.h" 00054 00055 00056 00058 // Construction/Destruction 00060 00061 00062 00063 00064 #ifdef _WIN32 00065 00066 DWORD WINAPI CommsLoopProc( LPVOID lpParameter) 00067 { 00068 00069 CMOOSSerialPort* pMe = (CMOOSSerialPort*)lpParameter; 00070 00071 return pMe->CommsLoop(); 00072 } 00073 00074 00075 #else 00076 00077 void * CommsLoopProc( void * lpParameter) 00078 { 00079 00080 MOOSTrace("starting comms thread in linux\n"); 00081 CMOOSSerialPort* pMe = (CMOOSSerialPort*)lpParameter; 00082 00083 pMe->CommsLoop(); 00084 00085 return NULL; 00086 } 00087 00088 #endif 00089 00090 00091 00092 00093 bool CMOOSSerialPort::StartThreads() 00094 { 00095 m_bQuit = false; 00096 00097 #ifdef _WIN32 00098 //this is the main listen thread 00099 m_hCommsThread = ::CreateThread( NULL, 00100 0, 00101 CommsLoopProc, 00102 this, 00103 CREATE_SUSPENDED, 00104 &m_nCommsThreadID); 00105 ResumeThread(m_hCommsThread); 00106 #else 00107 00108 MOOSTrace("In start thread\n"); 00109 int Status = pthread_create(& m_nCommsThreadID,NULL,CommsLoopProc,this); 00110 00111 if(Status!=0) 00112 { 00113 return false; 00114 } 00115 00116 00117 #endif 00118 00119 return true; 00120 } 00121 00122 CMOOSSerialPort::CMOOSSerialPort() 00123 { 00124 m_sPort = DEFAULT_PORT; 00125 m_nBaudRate = DEFAULT_BAUDRATE; 00126 m_bHandShaking = false; 00127 m_bStreaming = false; 00128 m_bVerbose = false; 00129 m_bQuit = false; 00130 m_pfnUserIsCompleteReplyCallBack = NULL; 00131 m_cTermCharacter = '\r'; 00132 00133 // ARH 14/05/2005 500kBaud CSM PCMCIA serial card setting 00134 m_bUseCsmExt = false; 00135 } 00136 00137 CMOOSSerialPort::~CMOOSSerialPort() 00138 { 00139 00140 } 00141 00142 bool CMOOSSerialPort::Configure(STRING_LIST sParams) 00143 { 00144 MOOSTrace("CMOOSSerialPort::Configure() : "); 00145 00146 STRING_LIST::iterator p; 00147 00148 for(p=sParams.begin();p!=sParams.end();p++) 00149 { 00150 std::string sLine = *p; 00151 00152 std::string sTok = MOOSChomp(sLine,"="); 00153 00154 std::string sVal = sLine; 00155 00156 00157 if(MOOSStrCmp(sTok,"PORT")) 00158 { 00159 m_sPort = sVal; 00160 MOOSTrace("%s,",m_sPort.c_str()); 00161 } 00162 else if(MOOSStrCmp(sTok,"BAUDRATE")) 00163 { 00164 m_nBaudRate = atoi(sVal.c_str()); 00165 00166 if(m_nBaudRate==0) 00167 { 00168 m_nBaudRate = DEFAULT_BAUDRATE; 00169 } 00170 MOOSTrace("%d,",m_nBaudRate); 00171 00172 } 00173 else if(MOOSStrCmp(sTok,"HANDSHAKING")) 00174 { 00175 if(MOOSStrCmp(sVal,"TRUE")) 00176 { 00177 m_bHandShaking = true; 00178 } 00179 else 00180 { 00181 m_bHandShaking = false; 00182 } 00183 } 00184 else if(MOOSStrCmp(sTok,"VERBOSE")) 00185 { 00186 00187 if(MOOSStrCmp(sVal,"TRUE")) 00188 { 00189 m_bVerbose = true; 00190 } 00191 else 00192 { 00193 m_bVerbose = false; 00194 } 00195 } 00196 else if(MOOSStrCmp(sTok,"STREAMING")) 00197 { 00198 00199 if(MOOSStrCmp(sVal,"TRUE")) 00200 { 00201 m_bStreaming = true; 00202 } 00203 else 00204 { 00205 m_bStreaming = false; 00206 } 00207 MOOSTrace("%s,",m_bStreaming?"streaming":"standard"); 00208 00209 } 00210 00211 // ARH 14/05/2005 Added to allow use of the 500kbaud CSM PCMCIA card 00212 else if (MOOSStrCmp(sTok, "USECSMEXT")) 00213 { 00214 if (MOOSStrCmp(sVal, "TRUE")) 00215 { 00216 m_bUseCsmExt = true; 00217 } 00218 else 00219 { 00220 m_bUseCsmExt = false; 00221 } 00222 } 00223 } 00224 00225 00226 bool bSuccess = Create(m_sPort.c_str(),m_nBaudRate); 00227 00228 if(bSuccess) 00229 { 00230 Flush(); 00231 if(m_bStreaming) 00232 { 00233 bSuccess = StartThreads(); 00234 } 00235 } 00236 00237 MOOSTrace("%s\n",bSuccess?"OK":"FAILED"); 00238 00239 return bSuccess; 00240 00241 00242 00243 } 00244 00245 void CMOOSSerialPort::Break() 00246 { 00247 00248 } 00249 00250 00251 bool CMOOSSerialPort::IsCompleteReply(char *pData, int nLen, int nRead) 00252 { 00253 00254 00255 if(m_pfnUserIsCompleteReplyCallBack!=NULL) 00256 { 00257 return (*m_pfnUserIsCompleteReplyCallBack)(pData,nLen,nRead); 00258 } 00259 else 00260 { 00261 return (nRead>0 && pData[nRead-1]==GetTermCharacter()); 00262 //return memchr(pData,GetTermCharacter(),nRead)!=NULL; 00263 } 00264 00265 } 00266 00267 void CMOOSSerialPort::SetIsCompleteReplyCallBack(bool (*pfn)(char *pData, int nLen, int nRead) ) 00268 { 00269 m_pfnUserIsCompleteReplyCallBack = pfn; 00270 } 00271 00272 00273 00274 bool CMOOSSerialPort::CommsLoop() 00275 { 00276 00277 00278 char pTmp[DEFAULT_COMMS_SPACE]; 00279 char pAccumulator[2*DEFAULT_COMMS_SPACE]; 00280 int nInStore = 0; 00281 00282 double dfTimeOut = 0.1; 00283 00284 while(!m_bQuit) 00285 { 00286 int nRead = ReadNWithTimeOut(pTmp,DEFAULT_COMMS_SPACE,dfTimeOut); 00287 00288 if(nRead!=-1) 00289 { 00290 00291 if((nInStore+nRead)>int(sizeof(pAccumulator))) 00292 { 00293 //oops... 00294 MOOSTrace("Comms Loop Accumulator Overflow, reseting\n"); 00295 nInStore = 0; 00296 continue; 00297 } 00298 00299 //append to the accumulator 00300 memcpy(pAccumulator+nInStore,pTmp,nRead); 00301 00302 //we have more in the cupboard! 00303 nInStore+=nRead; 00304 00305 //lock 00306 m_InBoxLock.Lock(); 00307 00308 char * pTelegramEnd = NULL; 00309 00310 do 00311 { 00312 00313 00314 //A device will by default use the termination character <CR> 00315 //But we now allow for setting of a termination character 00316 //to allow for flexibility in a reply. 00317 pTelegramEnd = (char*)memchr(pAccumulator,GetTermCharacter(),nInStore); 00318 00319 if(pTelegramEnd!=NULL) 00320 { 00321 //how long is the telegram? 00322 int nTelegramLength = pTelegramEnd - pAccumulator + 1; 00323 00324 //make a buffer that is one larger to preserve the last character 00325 //in case we are interested in it. 00326 char bBiggerBuff[2*DEFAULT_COMMS_SPACE+1]; 00327 00328 00329 //copy the telegram to a buffer size that is 1 larger 00330 memcpy(bBiggerBuff, pAccumulator, nTelegramLength); 00331 00332 //terminate it as a string 00333 //*pTelegramEnd = '\0'; 00334 bBiggerBuff[nTelegramLength] = '\0'; 00335 00336 00337 //copy it 00338 //std::string sTelegram((char*)pAccumulator); 00339 std::string sTelegram((char*)bBiggerBuff); 00340 00341 MOOSRemoveChars(sTelegram,"\r\n"); 00342 00343 if(IsVerbose()) 00344 { 00345 MOOSTrace("Telegram = %s\n",sTelegram.c_str()); 00346 } 00347 00348 //shuffle accumulator 00349 memmove(pAccumulator, 00350 pAccumulator+nTelegramLength, 00351 sizeof(pAccumulator)-nTelegramLength); 00352 00353 //we have less in our store now! 00354 nInStore-=nTelegramLength; 00355 00356 //make a telegram 00357 CMOOSSerialTelegram Tg(sTelegram,MOOSTime()); 00358 00359 //stuff it 00360 m_InBox.push_front(Tg); 00361 } 00362 }while(pTelegramEnd !=NULL); 00363 00364 00365 //whatch we don't exhibit disgraceful behaviour! 00366 while(m_InBox.size()>MOOS_SERIAL_INBOX_MAX_SIZE) 00367 { 00368 m_InBox.pop_back(); 00369 } 00370 00371 //and unlock 00372 00373 m_InBoxLock.UnLock(); 00374 00375 } 00376 else 00377 { 00378 } 00379 00380 } 00381 return true; 00382 } 00383 00384 bool CMOOSSerialPort::GetLatest(std::string &sWhat, double &dfWhen) 00385 { 00386 bool bSomethingFound = false; 00387 00388 00389 m_InBoxLock.Lock(); 00390 if(!m_InBox.empty()) 00391 { 00392 sWhat = m_InBox.front().m_sTelegram; 00393 dfWhen = m_InBox.front().m_dfTime; 00394 00395 m_InBox.pop_front(); 00396 00397 bSomethingFound =true; 00398 } 00399 m_InBoxLock.UnLock(); 00400 00401 return bSomethingFound; 00402 } 00403 00404 bool CMOOSSerialPort::GetEarliest(std::string &sWhat, double &dfWhen) 00405 { 00406 bool bSomethingFound = false; 00407 00408 00409 m_InBoxLock.Lock(); 00410 if(!m_InBox.empty()) 00411 { 00412 sWhat = m_InBox.back().m_sTelegram; 00413 dfWhen = m_InBox.back().m_dfTime; 00414 00415 m_InBox.pop_back(); 00416 00417 bSomethingFound =true; 00418 } 00419 m_InBoxLock.UnLock(); 00420 00421 return bSomethingFound; 00422 } 00423 00424 00425 00426 bool CMOOSSerialPort::IsStreaming() 00427 { 00428 return m_bStreaming; 00429 } 00430 00431 00437 void CMOOSSerialPort::SetTermCharacter(char cTermChar) 00438 { 00439 m_cTermCharacter = cTermChar; 00440 } 00441 00442 /* 00443 *@return the termination character being used by the serial port. 00444 */ 00445 char CMOOSSerialPort::GetTermCharacter() 00446 { 00447 return m_cTermCharacter; 00448 } 00449 00450 00451 00452 00453 int CMOOSSerialPort::ReadNWithTimeOut(char *pData, int nLen, double dfTimeOut,double * pTime ) 00454 { 00455 00456 00457 int nSpace = nLen; //space left in buffer 00458 int nRead = 0; //total number of chars read 00459 bool bQuit = false; // exit flag on complete message 00460 int nGrabbed = 0; 00461 00462 double dfStopTime=MOOSLocalTime()+dfTimeOut; 00463 00464 00465 while (MOOSLocalTime()<dfStopTime && !bQuit) 00466 { 00467 00468 00469 //try the read 00470 nGrabbed = GrabN(pData+nRead,nSpace); 00471 00472 if (nGrabbed == 0) 00473 { 00474 // wait a while...maybe it is on its way! 00475 MOOSPause(10); 00476 } 00477 else if(nGrabbed<0) 00478 { 00479 MOOSTrace("Grab FAILED %s\n",MOOSHERE); 00480 MOOSPause(10); 00481 } 00482 else 00483 { 00484 if(nRead==0 && pTime!=NULL) 00485 { 00486 //grab the time.. 00487 *pTime = MOOSTime(); 00488 } 00489 00490 nSpace-=nGrabbed; 00491 nRead+=nGrabbed; 00492 00493 if(nSpace<=0) 00494 bQuit = true; 00495 } 00496 } 00497 00498 return nRead; 00499 00500 } 00501 00502 00503 00504 int CMOOSSerialPort::ReadNWithTimeOut2(char *pData, int nLen, double dfTimeOut, double * pTime ) 00505 { 00506 00507 00508 int nSpace = nLen; //space left in buffer 00509 int nRead = 0; //total number of chars read 00510 bool bQuit = false; //exit flag on complete message 00511 int nGrabbed = 0; 00512 00513 double dfStopTime=MOOSLocalTime()+dfTimeOut; 00514 00515 00516 while (MOOSLocalTime()<dfStopTime && !bQuit) 00517 { 00518 00519 00520 //try the read 00521 nGrabbed = GrabN(pData+nRead,nSpace); 00522 00523 if (nGrabbed == 0) 00524 { 00525 // wait a while...maybe it is on its way! 00526 MOOSPause(10); 00527 } 00528 else if(nGrabbed<0) 00529 { 00530 return -1; // Signal error 00531 } 00532 else 00533 { 00534 // Ensures that we only grab the time for the first byte. 00535 if(nRead==0 && pTime!=NULL) 00536 { 00537 //grab the time.. 00538 *pTime = MOOSTime(); 00539 } 00540 00541 //great, so increment out buffer pointer 00542 //and check to see if this is a complete 00543 // nomad reply 00544 nSpace-=nGrabbed; 00545 nRead+=nGrabbed; 00546 00547 if(nSpace<=0) 00548 bQuit = true; 00549 } 00550 } 00551 00552 return nRead; 00553 00554 } 00555 00556 00557 00558 bool CMOOSSerialPort::GetTelegram(std::string &sTelegram,double dfTimeOut,double *pTime) 00559 { 00560 if(IsStreaming()) 00561 { 00562 MOOSTrace("don't call GetTelgram on a streaming device!\n"); 00563 return false; 00564 } 00565 00566 char pData[TELEGRAM_LEN]; 00567 double dfTimeWaited = 0.0; //haven't waited any tiome yet 00568 double dfInterval = 0.01; //10ms 00569 int nRead = 0; //total number of chars read 00570 00571 00572 while ((dfTimeWaited<dfTimeOut) && nRead<TELEGRAM_LEN) 00573 { 00574 int nGrabbed = 0; 00575 00576 //try the read 00577 nGrabbed = GrabN(pData+nRead,1); 00578 00579 if (nGrabbed == 0) 00580 { 00581 //OK wait a while...maybe it is on its way! 00582 dfTimeWaited+=dfInterval; 00583 00584 MOOSPause((int)(dfInterval*1000.0)); 00585 } 00586 else 00587 { 00588 if(nRead==0 && pTime!=NULL) 00589 { 00590 //grab the time.. 00591 *pTime = MOOSTime(); 00592 } 00593 00594 00595 nRead+=nGrabbed; 00596 00597 //have we reached the end of the message? 00598 if(IsCompleteReply(pData,TELEGRAM_LEN,nRead)) 00599 { 00600 pData[nRead]='\0'; 00601 sTelegram = pData; 00602 MOOSRemoveChars(sTelegram,"\r\n"); 00603 00604 if(IsVerbose()) 00605 { 00606 MOOSTrace("Telegram = %s\n",sTelegram.c_str()); 00607 } 00608 //MOOSTrace("Required %d retries and %d accumulates\n",nRetries,nAccumulates); 00609 return true; 00610 } 00611 } 00612 } 00613 00614 return false; 00615 } 00616 00617 00618 bool CMOOSSerialPort::GetTelegramOrAccumulate(std::string &sTelegram,double dfTimeOut,double *pTime) 00619 { 00620 if(IsStreaming()) 00621 { 00622 MOOSTrace("don't call GetTelegram on a streaming device!\n"); 00623 return false; 00624 } 00625 00626 static char telegramBuffer[TELEGRAM_LEN]; 00627 static int nTelegramBufferRead = 0; //total number of chars read 00628 00629 double dfTimeWaited = 0.0; //haven't waited any time yet 00630 double dfInterval = 0.01; //10ms 00631 00632 00633 while ((dfTimeWaited<dfTimeOut) && nTelegramBufferRead<TELEGRAM_LEN) 00634 { 00635 int nGrabbed = 0; 00636 00637 //try the read 00638 nGrabbed = GrabN(telegramBuffer+nTelegramBufferRead,1); 00639 00640 if (nGrabbed == 0) 00641 { 00642 //OK wait a while...maybe it is on its way! 00643 dfTimeWaited+=dfInterval; 00644 00645 MOOSPause((int)(dfInterval*1000.0)); 00646 } 00647 else 00648 { 00649 if(nTelegramBufferRead==0 && pTime!=NULL) 00650 { 00651 //grab the time.. 00652 *pTime = MOOSTime(); 00653 } 00654 00655 00656 nTelegramBufferRead+=nGrabbed; 00657 00658 //have we reached the end of the message? 00659 if(IsCompleteReply(telegramBuffer,TELEGRAM_LEN,nTelegramBufferRead)) 00660 { 00661 telegramBuffer[nTelegramBufferRead]='\0'; 00662 nTelegramBufferRead = 0; 00663 sTelegram = telegramBuffer; 00664 MOOSRemoveChars(sTelegram,"\r\n"); 00665 00666 if(IsVerbose()) 00667 { 00668 MOOSTrace("Telegram = %s\n",sTelegram.c_str()); 00669 } 00670 //MOOSTrace("Required %d retries and %d accumulates\n",nRetries,nAccumulates); 00671 return true; 00672 } 00673 } 00674 } 00675 00676 return false; 00677 } 00678 00679 bool CMOOSSerialPort::Close() 00680 { 00681 00682 m_bQuit = true; 00683 00684 if(m_bStreaming) 00685 { 00686 #ifdef _WIN32 00687 WaitForSingleObject(m_hCommsThread,INFINITE); 00688 #else 00689 void * Result; 00690 pthread_join(m_nCommsThreadID,&Result); 00691 #endif 00692 } 00693 return true; 00694 00695 00696 } 00697 00698 std::string CMOOSSerialPort::GetPortName() 00699 { 00700 return m_sPort; 00701 } 00702