MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Core/MOOSGenLib/MOOSSerialPort.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines