hti/PC_Tools/DataGateway/SRC/SerialComm.cpp
branchRCL_3
changeset 59 8ad140f3dd41
parent 0 a03f92240627
equal deleted inserted replaced
49:7fdc9a71d314 59:8ad140f3dd41
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 * 
       
    14 * Description:
       
    15 *   This file contains implementation of SerialComm communication channel plugin objects. These classes are SerialComm, SerialCommPlugin and
       
    16 *	SerialCommIoThread classes.
       
    17 */
       
    18 
       
    19 // INCLUDES
       
    20 #include "SerialCommPlugin.h"
       
    21 #include "util.h"
       
    22 
       
    23 #define HIGH_COM_PORT "\\\\.\\"
       
    24 const static int g_SerialMaxResendNumber = 2;
       
    25 
       
    26 //**********************************************************************************
       
    27 // Class SerialCommPlugin
       
    28 //
       
    29 // This class implements a CommChannelPlugin used in serial communication with device
       
    30 //**********************************************************************************
       
    31 
       
    32 SerialCommPlugin::SerialCommPlugin(const CommChannelPluginObserver* observer)
       
    33     : CommChannelPlugin(observer),
       
    34       m_TxQueue(),
       
    35       m_RxQueue(),
       
    36       m_PropertySerialCommTimeout(g_SerialCommDefaultTimeout),
       
    37 	  m_PropertySerialMaxSendSize(0),
       
    38 	  m_ProperySerialSendPause(0),
       
    39 	  m_PropertySerialHwFlowControl(false)
       
    40 {
       
    41     m_IoThread = NULL;
       
    42 }
       
    43 
       
    44 SerialCommPlugin::~SerialCommPlugin()
       
    45 {
       
    46     Util::Debug("SerialCommPlugin::~SerialCommPlugin()");
       
    47     if ( m_Open )
       
    48     {
       
    49         Close();
       
    50     }
       
    51     if ( m_IoThread != NULL )
       
    52     {
       
    53         delete m_IoThread;
       
    54         m_IoThread = NULL;
       
    55     }
       
    56 }
       
    57 
       
    58 /*
       
    59  * This method initializes SerialCommPlugin and starts SerialCommPluginIoThread
       
    60  */
       
    61 DWORD SerialCommPlugin::Init()
       
    62 {
       
    63     Util::Debug("SerialCommPlugin::Init()");
       
    64 
       
    65     std::string filename = SERIAL_INI_FILE_NAME;
       
    66 	//read properties from serialplugin.ini file
       
    67 	Util::ReadProperties(filename.c_str(), m_SerialCommPluginProperties);
       
    68     
       
    69 	CheckProperties(m_SerialCommPluginProperties);
       
    70 
       
    71     CommChannelPlugin::Init();
       
    72 
       
    73     m_IoThread = new SerialCommIoThread(
       
    74 						&m_RxQueue,
       
    75 						&m_TxQueue,
       
    76                         m_PropertySerialCommInitString,
       
    77 						m_PropertySerialCommPort,
       
    78 						m_PropertySerialCommTimeout,
       
    79 						m_PropertySerialHwFlowControl,
       
    80 						m_ProperySerialSendPause,
       
    81 						m_PropertySerialMaxSendSize);
       
    82 
       
    83     m_IoThread->SetTimeout(m_PropertySerialCommTimeout);
       
    84 
       
    85 	m_IoThread->Start();
       
    86 
       
    87 	Event e = m_IoThread->GetOpenedEvent();
       
    88     if ( e.Wait(m_PropertySerialCommTimeout) == WAIT_TIMEOUT )
       
    89     {
       
    90         Util::Debug("SerialCommPlugin::Init()   SerialComm opening timed out");
       
    91         m_Open = false;
       
    92         return ERR_DG_COMM_OPEN_TIMEOUT;
       
    93     }
       
    94     Util::Debug("SerialCommPlugin::Init() SerialComm opened");
       
    95     m_Open = true;
       
    96     Util::Debug("SerialCommPlugin::Init() OK");
       
    97     return NO_ERRORS;
       
    98 }
       
    99 
       
   100 /*
       
   101  * This method initializes class member variables from values in map
       
   102  */
       
   103 void SerialCommPlugin::CheckProperties(map<string, string>& props)
       
   104 {
       
   105     char tmp[256];
       
   106 
       
   107     // Init values for connection
       
   108     m_PropertySerialCommInitString = props[SERIAL_INI_INIT_PARAM];
       
   109 	Util::CheckCommandlineParam( PARAM_SWITCH_INIT_PARAM, m_PropertySerialCommInitString );
       
   110     if ( m_PropertySerialCommInitString.empty() )
       
   111     {
       
   112         m_PropertySerialCommInitString = SERIAL_DEFAULT_INIT_STRING;
       
   113     }
       
   114     sprintf(tmp, "Connection Init : '%s'", m_PropertySerialCommInitString.c_str());
       
   115     string s(tmp);
       
   116     Util::Debug(s);
       
   117 
       
   118     // comm port
       
   119     m_PropertySerialCommPort = props[SERIAL_INI_COMPORT_PARAM];
       
   120 	Util::CheckCommandlineParam( PARAM_SWITCH_COMPORT_PARAM, m_PropertySerialCommPort );
       
   121     if ( m_PropertySerialCommPort.empty() )
       
   122     {
       
   123         m_PropertySerialCommPort = SERIAL_DEFAULT_COMPORT;
       
   124     }
       
   125     sprintf(tmp, "Connection port : '%s'", m_PropertySerialCommPort.c_str());
       
   126     s = tmp;
       
   127     Util::Debug(s);
       
   128 
       
   129     // Serial operations timeout
       
   130     string val = props[SERIAL_INI_COMPORT_TIMEOUT];
       
   131 	Util::CheckCommandlineParam( PARAM_SWITCH_COMPORT_TIMEOUT, val );
       
   132 	m_PropertySerialCommTimeout = 0;
       
   133     if ( !val.empty() )
       
   134     {
       
   135         m_PropertySerialCommTimeout = atol(val.c_str());
       
   136     }
       
   137 
       
   138     if ( m_PropertySerialCommTimeout <= 0 )
       
   139     {
       
   140         m_PropertySerialCommTimeout = g_SerialCommDefaultTimeout;
       
   141     }
       
   142 	sprintf(tmp, "Timeout: '%d'", m_PropertySerialCommTimeout);
       
   143     s = tmp;
       
   144     Util::Debug(s);
       
   145 
       
   146 	// flow control
       
   147 	m_PropertySerialHwFlowControl = false;
       
   148 	val = props[SERIAL_INI_USE_HW_FLOW_CONTROL];
       
   149 	Util::CheckCommandlineParam( PARAM_SWITCH_USE_HW_FLOW_CONTROL, val );
       
   150 	if ( !val.empty() && val == "1" )
       
   151 	{
       
   152 		m_PropertySerialHwFlowControl = true;
       
   153 		Util::Debug("Use serial HW flow control");
       
   154 	}
       
   155 	else
       
   156 	{
       
   157 		Util::Debug("Do not use serial HW flow control");
       
   158 	}
       
   159 
       
   160 	// send pause
       
   161 	val = props[SERIAL_INI_SEND_SLEEP_PAUSE];
       
   162 	Util::CheckCommandlineParam( PARAM_SWITCH_SEND_SLEEP_PAUSE, val );
       
   163     if ( !val.empty() )
       
   164     {
       
   165         m_ProperySerialSendPause = atol(val.c_str());
       
   166     }
       
   167     if ( m_ProperySerialSendPause <= 0 )
       
   168     {
       
   169         m_ProperySerialSendPause = g_SerialCommDefaultSendPause;
       
   170     }
       
   171 	sprintf(tmp, "Send pause: '%d'", m_ProperySerialSendPause);
       
   172     s = tmp;
       
   173     Util::Debug(s);
       
   174 
       
   175 	// send size
       
   176 	val = props[SERIAL_INI_SEND_SIZE];
       
   177 	Util::CheckCommandlineParam( PARAM_SWITCH_SEND_SIZE, val );
       
   178     if ( !val.empty() )
       
   179     {
       
   180         m_PropertySerialMaxSendSize = atol(val.c_str());
       
   181     }
       
   182     if ( m_PropertySerialMaxSendSize <= 0 )
       
   183     {
       
   184         m_PropertySerialMaxSendSize = 0;
       
   185     }
       
   186 	sprintf(tmp, "Send max size: '%d'", m_PropertySerialMaxSendSize);
       
   187     s = tmp;
       
   188     Util::Debug(s);
       
   189 }
       
   190 
       
   191 /*
       
   192  * This method checks if data is available on incoming queue
       
   193  */
       
   194 bool SerialCommPlugin::IsDataAvailable()
       
   195 {
       
   196     return ( !m_RxQueue.empty() );
       
   197 }
       
   198 
       
   199 /*
       
   200  * This method is used to:
       
   201  * -push given data to outgoing queue
       
   202  * -wait for data to become available in incoming queue
       
   203  * -pop the first Data object from queue and store it to the Data object given as parameter
       
   204  */
       
   205 DWORD SerialCommPlugin::SendReceive(Data* data_in, Data** data_out, long timeout)
       
   206 {
       
   207     DWORD res;
       
   208     if ( ( res = Send(data_in, timeout)) == NO_ERRORS &&
       
   209          ( res = ReceiveWait(data_out, timeout)) == NO_ERRORS )
       
   210     {
       
   211         return NO_ERRORS;
       
   212     }
       
   213     cout << "SerialCommPlugin::SendReceive: error" << endl;
       
   214     return res;
       
   215 }
       
   216 
       
   217 /*
       
   218  * This method pushes the given Data object(of type Data::EData) to outgoing queue
       
   219  */
       
   220 DWORD SerialCommPlugin::Send(Data* data_in, long timeout)
       
   221 {
       
   222     Data::DataType type = data_in->GetType();
       
   223     if ( type == Data::EData )
       
   224     {
       
   225         DWORD length = data_in->GetLength();
       
   226         m_TxQueue.push(data_in);
       
   227         return NO_ERRORS;
       
   228     }
       
   229     else if ( type == Data::EControl )
       
   230     {
       
   231 		Util::Debug("SerialCommPlugin::Send: Control Message Received");
       
   232         return NO_ERRORS;
       
   233     }
       
   234     return ERR_DG_COMM_DATA_SEND;
       
   235 }
       
   236 
       
   237 /*
       
   238  * This method is used to wait for data to become available in incoming queue 
       
   239  * and then pop the first Data object from the queue and and store it to Data object given as parameter.
       
   240  */
       
   241 DWORD SerialCommPlugin::ReceiveWait(Data** data_out, long timeout)
       
   242 {
       
   243     long elapsed = 0;
       
   244     while (elapsed < timeout && !IsDataAvailable())
       
   245     {
       
   246         elapsed += 25;
       
   247         Sleep(25);
       
   248     }
       
   249     if ( elapsed >= timeout )
       
   250     {
       
   251         return ERR_DG_COMM_DATA_RECV_TIMEOUT;
       
   252     }
       
   253     return Receive(data_out, timeout);
       
   254 }
       
   255 
       
   256 /*
       
   257  * This method is used to pop the first data object from incoming queue and store it to data object given as parameter
       
   258  */
       
   259 DWORD SerialCommPlugin::Receive(Data** data_out, long timeout)
       
   260 {
       
   261     if ( !m_RxQueue.empty() )
       
   262     {
       
   263         *data_out = m_RxQueue.front();
       
   264         m_RxQueue.pop();
       
   265         return NO_ERRORS;
       
   266     }
       
   267     return ERR_DG_COMM_DATA_RECV;
       
   268 }
       
   269 
       
   270 
       
   271 DWORD SerialCommPlugin::Open()
       
   272 {
       
   273     return ( m_Open ? NO_ERRORS : ERR_DG_COMM_OPEN );
       
   274 }
       
   275 
       
   276 /*
       
   277  * This method stops SerialCommIoThread and waits for it to be in signaled state
       
   278  */
       
   279 DWORD SerialCommPlugin::Close()
       
   280 {
       
   281     m_IoThread->Stop();
       
   282     WaitForSingleObject( m_IoThread->ThreadHandle(), g_MaximumShutdownWaitTime );
       
   283     return NO_ERRORS;
       
   284 }
       
   285 
       
   286 //**********************************************************************************
       
   287 // Class SerialComm
       
   288 //
       
   289 // This class implements the actual serial communication using Windows API
       
   290 //**********************************************************************************
       
   291 
       
   292 SerialComm::SerialComm()
       
   293     : m_Open(false),
       
   294 	m_SendPause(0),
       
   295 	m_SendMaxSize(0)
       
   296 {
       
   297 
       
   298 }
       
   299 
       
   300 SerialComm::~SerialComm()
       
   301 {
       
   302     Util::Debug("SerialComm::~SerialComm()");
       
   303     if ( m_Open )
       
   304     {
       
   305         Close();
       
   306     }
       
   307 }
       
   308 /*
       
   309  * This method opens a communication device that uses serial communication and
       
   310  * configures it according initialization parameters
       
   311  */
       
   312 WORD SerialComm::Open( const string& commPort, const string& initParameters,
       
   313 					   long timeout,
       
   314 					   bool hwFlowControl, long sendPause, long sendMaxSize)
       
   315 {
       
   316     Util::Debug("SerialComm::Open()");
       
   317 
       
   318 	m_SendPause = sendPause;
       
   319 
       
   320 	if ( sendMaxSize>0 )
       
   321 	{
       
   322 		m_SendMaxSize = sendMaxSize;
       
   323 	}
       
   324 
       
   325 	DWORD err;
       
   326 	//check commPort and add "\\.\" prefix if port is larger than 9
       
   327 	string localCommPort(commPort);
       
   328 	static const basic_string <char>::size_type npos = -1;
       
   329 	if ( localCommPort.find(HIGH_COM_PORT) == npos &&
       
   330 		 localCommPort.find("COM") == 0 &&
       
   331 		 localCommPort.length() > 4 //two digit port number
       
   332 	   )
       
   333 	{
       
   334 		localCommPort.insert(0, HIGH_COM_PORT);
       
   335 	}
       
   336 	Util::Debug(localCommPort.c_str());
       
   337 
       
   338     // If COM-port opening fails, it's retried until DataGateway is killed.
       
   339     m_Com = INVALID_HANDLE_VALUE;
       
   340     while ( m_Com == INVALID_HANDLE_VALUE )
       
   341     {
       
   342 	    // Open file (COM port)
       
   343 	    m_Com = CreateFile( localCommPort.c_str(),
       
   344 					    GENERIC_READ | GENERIC_WRITE,
       
   345 					    0, //excusive access
       
   346 					    NULL, //no security
       
   347 					    OPEN_EXISTING, //must use
       
   348 					    0, //not overlapped i/o
       
   349 					    NULL // must be NULL for comm
       
   350 					    );
       
   351 	    if ( m_Com == INVALID_HANDLE_VALUE )
       
   352 	    {
       
   353 		    err = GetLastError();
       
   354             Util::Error("[SerialComm] Failed to open COM port", err);
       
   355             Util::Info("[SerialComm] Retrying...");
       
   356             Sleep(5000);
       
   357         }
       
   358     }
       
   359 
       
   360     // Serial port cfg
       
   361 	Util::Debug(initParameters.c_str());
       
   362 	DCB dcb;
       
   363 
       
   364 	FillMemory(&dcb, sizeof(dcb), 0);
       
   365 	dcb.DCBlength = sizeof(dcb);
       
   366 	if ( !BuildCommDCB(initParameters.c_str(), &dcb) )
       
   367 	{
       
   368 		err = GetLastError();
       
   369 		Util::Error("[SerialComm] Failed to build port settings ", err);
       
   370 		return ERR_DG_COM_INIT;
       
   371 	}
       
   372 
       
   373 	dcb.fBinary = TRUE ; 
       
   374 
       
   375 	//set hw handshaking
       
   376 	dcb.fOutX  = FALSE;
       
   377     dcb.fInX   = FALSE;
       
   378     dcb.fNull   = FALSE;
       
   379     dcb.fAbortOnError = TRUE;
       
   380 	
       
   381 	dcb.fOutxDsrFlow = FALSE;
       
   382 	dcb.fDtrControl = DTR_CONTROL_DISABLE;
       
   383 	dcb.fDsrSensitivity= FALSE;
       
   384 
       
   385 	if ( hwFlowControl )
       
   386 	{
       
   387 		dcb.fOutxCtsFlow = TRUE;
       
   388 		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
       
   389 	}
       
   390 	else
       
   391 	{
       
   392 		dcb.fOutxCtsFlow = FALSE;
       
   393 		dcb.fRtsControl = RTS_CONTROL_ENABLE;
       
   394 	}
       
   395     //Configure communication device according to the specifications in a device-control block (a DCB structure)
       
   396 	if ( !SetCommState(m_Com, &dcb) )
       
   397 	{
       
   398 		err = GetLastError();
       
   399 		Util::Error("[SerialComm] Failed to set port settings ", err);
       
   400 		return ERR_DG_COM_INIT;
       
   401 	}
       
   402 
       
   403 	COMMTIMEOUTS timeouts;
       
   404 
       
   405 	timeouts.ReadIntervalTimeout = MAXDWORD; 
       
   406 
       
   407 	timeouts.ReadTotalTimeoutMultiplier = timeout;
       
   408 	timeouts.ReadTotalTimeoutConstant = 1;
       
   409 	timeouts.WriteTotalTimeoutMultiplier = 1;
       
   410 	timeouts.WriteTotalTimeoutConstant = timeout;
       
   411 
       
   412 	//Set the time-out parameters for all read and write operations on communications device
       
   413 	if ( !SetCommTimeouts(m_Com, &timeouts) )
       
   414 	{
       
   415 		// Error setting time-outs.
       
   416 		err = GetLastError();
       
   417 		Util::Error("[SerialComm] Failed to set port timeouts ", err);
       
   418 		return ERR_DG_COM_INIT;
       
   419 	}
       
   420 
       
   421 	m_Open = true;
       
   422     Util::Debug("SerialComm::Open() OK");
       
   423     Util::Info("[SerialComm] COM port open");
       
   424     return NO_ERRORS;
       
   425 }
       
   426 
       
   427 /*
       
   428  * This method is used to send Data object using serial communication
       
   429  */
       
   430 DWORD SerialComm::Send(const Data& data_in)
       
   431 {
       
   432     Util::Debug("SerialComm::Send()");
       
   433 
       
   434 	if ( data_in.GetLength() > 0 )
       
   435 	{
       
   436 		DWORD sentBytes = 0;
       
   437 		void* data = data_in.GetData();
       
   438 		int numOfTries = 0;
       
   439 		//loop until whole Data object is sent
       
   440 		while ( sentBytes < data_in.GetLength() )
       
   441 		{
       
   442 			//Util::Debug("while");
       
   443 			DWORD sent;
       
   444 			BOOL r;
       
   445 			if ( m_SendMaxSize>0 )
       
   446 			{
       
   447 				//Write data to the communication device
       
   448 				r = WriteFile(m_Com,
       
   449 						((char*)data) + sentBytes,
       
   450 						//data_in.GetLength() - sentBytes,
       
   451 						min(data_in.GetLength() - sentBytes, m_SendMaxSize),
       
   452 						&sent,
       
   453 						NULL);
       
   454 			}
       
   455 			else
       
   456 			{
       
   457 				r = WriteFile(m_Com,
       
   458 						((char*)data) + sentBytes,
       
   459 						data_in.GetLength() - sentBytes,
       
   460 						&sent,
       
   461 						NULL);
       
   462 			}
       
   463 
       
   464 			if ( r && sent > 0 )
       
   465 			{
       
   466 				if (Util::GetVerboseLevel() == Util::debug)
       
   467 				{
       
   468 					printf("Send %d bytes\r\n", sent);
       
   469 					Util::Hex(((char*)data) + sentBytes, min(sent,16));
       
   470 				}
       
   471 				sentBytes+=sent;
       
   472 			}
       
   473 			else
       
   474 			{
       
   475 				if ( !r )
       
   476 				{
       
   477 					DWORD err = GetLastError();
       
   478 					Util::Error("[SerialComm] Send error", err);
       
   479 				}
       
   480 				else
       
   481 				{
       
   482 					Util::Error("[SerialComm] Send failed");
       
   483 				}
       
   484 				if ( numOfTries++==g_SerialMaxResendNumber )
       
   485 				{
       
   486 					return ERR_DG_COMM_DATA_RECV;
       
   487 				}
       
   488 			}
       
   489 			//used to "solve" overflow problem
       
   490 			if ( m_SendPause > 0 )
       
   491 			{
       
   492 				Sleep(m_SendPause);
       
   493 			}
       
   494 		}
       
   495 	}
       
   496 
       
   497     Util::Debug("SerialComm::Send() OK");
       
   498     return NO_ERRORS;
       
   499 }
       
   500 
       
   501 /*
       
   502  * This method reads all available data from communication media 
       
   503  * and returns it in the Data object given as parameter
       
   504  */
       
   505 DWORD SerialComm::Receive(Data* data_out)
       
   506 {
       
   507     Util::Debug("SerialComm::Receive()");
       
   508 
       
   509 	//get available bytes in incoming communication channel
       
   510 	DWORD rxBytes = GetRxBytesAvailable();
       
   511 	//printf("Rx bytes: %d \r\n", rxBytes);
       
   512 
       
   513 	if ( rxBytes > 0 )
       
   514 	{
       
   515 		char* data = new char[rxBytes];
       
   516 		DWORD readBytes = 0;
       
   517 		//read data until all available bytes have been red
       
   518 		do
       
   519 		{
       
   520 			DWORD reallyRead;
       
   521 			if ( ReadFile(m_Com,
       
   522 					 data + readBytes,
       
   523 					 rxBytes - readBytes,
       
   524 					 &reallyRead,
       
   525 					 NULL) )
       
   526 			{
       
   527 				if (Util::GetVerboseLevel() == Util::debug)
       
   528 				{
       
   529 					printf("Received %d bytes\r\n", reallyRead);
       
   530 					Util::Hex(data + readBytes, min(16,reallyRead));
       
   531 				}
       
   532 				readBytes += reallyRead;
       
   533 			}
       
   534 			else
       
   535 			{
       
   536 				delete[] data;
       
   537 				DWORD err = GetLastError();
       
   538 				Util::Error("[SerialComm] Error %d", err);
       
   539 				return ERR_DG_COMM_DATA_RECV;
       
   540 			}
       
   541 			if ( readBytes > rxBytes )
       
   542 			{
       
   543 				Util::Error("[SerialComm] !!! readBytes > rxBytes !!!");
       
   544 			}
       
   545 		}
       
   546 		while( readBytes < rxBytes );
       
   547 
       
   548 		data_out->SetData( data, rxBytes, Data::EData);
       
   549 		delete[] data;
       
   550 	}
       
   551 	else if ( rxBytes<0 ) //err
       
   552 	{
       
   553         return ERR_DG_COMM_DATA_RECV;
       
   554 	}
       
   555 	return NO_ERRORS;
       
   556 }
       
   557 
       
   558 /*
       
   559  * This method returns number of bytes available in incoming queue or
       
   560  * -1 if communication error has occurred
       
   561  */
       
   562 LONG SerialComm::GetRxBytesAvailable()
       
   563 {
       
   564     COMSTAT res;
       
   565 	DWORD err;
       
   566 
       
   567 	if ( ClearCommError(m_Com, &err, &res ) )
       
   568 	{
       
   569 		return res.cbInQue;
       
   570 	}
       
   571 	else
       
   572     {
       
   573 		DWORD err = GetLastError();
       
   574         Util::Error("[SerialComm] Error getting Rx bytes %d", err);
       
   575         return -1;
       
   576     }
       
   577 }
       
   578 
       
   579 DWORD SerialComm::Close()
       
   580 {
       
   581     Util::Debug("SerialComm::Close()");
       
   582     m_Open = false;
       
   583 
       
   584 	if ( m_Com != INVALID_HANDLE_VALUE )
       
   585 	{
       
   586 		CloseHandle(m_Com);
       
   587 		m_Com = INVALID_HANDLE_VALUE;
       
   588 	}
       
   589 
       
   590     Util::Debug("SerialComm::Close() OK");
       
   591     return NO_ERRORS;
       
   592 }
       
   593 
       
   594 //**********************************************************************************
       
   595 // Class SerialCommIoThread
       
   596 //
       
   597 // This thread is used to send data from outgoing queue to serial port
       
   598 // and read bytes from serial port and push it to incoming queue 
       
   599 //**********************************************************************************
       
   600 
       
   601 SerialCommIoThread::SerialCommIoThread(SafeQueue<Data*>* in,
       
   602                            SafeQueue<Data*>* out,
       
   603                            const string& init,  const string& commPort, long timeout,
       
   604 						   bool hwFlowControl, long sendPause, long sendMaxSize)
       
   605     : m_InitString(init),
       
   606 	  m_CommPort( commPort ),
       
   607 	  m_PropertySerialCommTimeout( timeout ),
       
   608 	  m_PropertySerialHwFlowControl( hwFlowControl ),
       
   609 	  m_ProperySerialSendPause(sendPause),
       
   610 	  m_PropertySerialMaxSendSize(sendMaxSize)
       
   611 {
       
   612     m_InQueue = in;
       
   613     m_OutQueue = out;
       
   614     m_Running = true;
       
   615     m_PropertySerialCommTimeout = g_SerialCommDefaultTimeout;
       
   616     m_OpenedEvent.Reset();
       
   617 }
       
   618 
       
   619 /*
       
   620  * Main execution loop which is used to send Data from outgoing queue to serial port
       
   621  * and read bytes from serial port, encapsulate it to Data objects and push them to incoming queue 
       
   622  */
       
   623 void SerialCommIoThread::Run()
       
   624 {
       
   625     while ( m_Running )
       
   626     {
       
   627 	    Util::Debug("SerialCommIoThread::Run()");
       
   628         SerialComm m_SerialComm;
       
   629 
       
   630         if ( m_SerialComm.Open(m_CommPort, m_InitString, m_PropertySerialCommTimeout,
       
   631 							    m_PropertySerialHwFlowControl, m_ProperySerialSendPause,
       
   632 							    m_PropertySerialMaxSendSize) != NO_ERRORS )
       
   633         {
       
   634             m_Running = false;
       
   635             return;
       
   636         }
       
   637         m_OpenedEvent.Set();
       
   638 
       
   639 	    Util::Debug("SerialCommIoThread::Run() start loop");
       
   640         while ( m_Running )
       
   641         {
       
   642             // Sending data
       
   643             try
       
   644             {
       
   645 				Data* out = m_OutQueue->front(30);
       
   646                 if ( m_SerialComm.Send(*out) != NO_ERRORS )
       
   647                 {
       
   648                     Data* d = new Data("Error sending data", 19, Data::EControl);
       
   649                     m_InQueue->push(d);
       
   650                     d = NULL;
       
   651                 }
       
   652                 m_OutQueue->pop();
       
   653                 delete out;
       
   654                 out = NULL;
       
   655             } catch (TimeoutException te) {}
       
   656 
       
   657 		    // Receiving data
       
   658 		    LONG rxBytes = 0;
       
   659             while ( ( rxBytes = m_SerialComm.GetRxBytesAvailable() ) > 0 )
       
   660             {
       
   661 			    //printf("rx %d\r\n", rxBytes);
       
   662                 Data* in = new Data;
       
   663                 if ( m_SerialComm.Receive(in) == NO_ERRORS )
       
   664                 {
       
   665 				    m_InQueue->push(in);
       
   666 				    in = NULL;
       
   667                 }
       
   668                 else
       
   669                 {
       
   670                     delete in;
       
   671                     in = NULL;
       
   672                 }
       
   673             }
       
   674             if ( rxBytes < 0 )
       
   675             {
       
   676                 Util::Info("[SerialCommIoThread] COM-port lost. Trying to close & reopen");
       
   677                 break; // break out but keep the outermost while loop running
       
   678             }
       
   679         }
       
   680         m_OpenedEvent.Reset();
       
   681         m_SerialComm.Close();
       
   682     }
       
   683     Util::Debug("SerialCommIoThread::Run() exiting");
       
   684 }
       
   685 
       
   686 void SerialCommIoThread::Stop()
       
   687 {
       
   688     Util::Debug("SerialCommIoThread::Stop()");
       
   689     m_Running = false;
       
   690 }
       
   691 
       
   692 Event SerialCommIoThread::GetOpenedEvent()
       
   693 {
       
   694     return m_OpenedEvent;
       
   695 }
       
   696 
       
   697 void SerialCommIoThread::SetTimeout(long timeout)
       
   698 {
       
   699     if ( timeout > 0 )
       
   700     {
       
   701         m_PropertySerialCommTimeout = timeout;
       
   702     }
       
   703     else
       
   704     {
       
   705         m_PropertySerialCommTimeout = g_SerialCommDefaultTimeout;
       
   706     }
       
   707 }
       
   708 
       
   709 long SerialCommIoThread::GetTimeout() const
       
   710 {
       
   711     return m_PropertySerialCommTimeout;
       
   712 }
       
   713 
       
   714 // End of the file