--- a/hti/PC_Tools/HTIGateway/HtiGateway/src/SerialComm.cpp Tue Jul 06 16:05:13 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,714 +0,0 @@
-/*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of "Eclipse Public License v1.0"
-* which accompanies this distribution, and is available
-* at the URL "http://www.eclipse.org/legal/epl-v10.html".
-*
-* Initial Contributors:
-* Nokia Corporation - initial contribution.
-*
-* Contributors:
-*
-* Description:
-* This file contains implementation of SerialComm communication channel plugin objects. These classes are SerialComm, SerialCommPlugin and
-* SerialCommIoThread classes.
-*/
-
-// INCLUDES
-#include "SerialCommPlugin.h"
-#include "util.h"
-
-#define HIGH_COM_PORT "\\\\.\\"
-const static int g_SerialMaxResendNumber = 2;
-
-//**********************************************************************************
-// Class SerialCommPlugin
-//
-// This class implements a CommChannelPlugin used in serial communication with device
-//**********************************************************************************
-
-SerialCommPlugin::SerialCommPlugin(const CommChannelPluginObserver* observer)
- : CommChannelPlugin(observer),
- m_TxQueue(),
- m_RxQueue(),
- m_PropertySerialCommTimeout(g_SerialCommDefaultTimeout),
- m_PropertySerialMaxSendSize(0),
- m_ProperySerialSendPause(0),
- m_PropertySerialHwFlowControl(false)
-{
- m_IoThread = NULL;
-}
-
-SerialCommPlugin::~SerialCommPlugin()
-{
- Util::Debug("SerialCommPlugin::~SerialCommPlugin()");
- if ( m_Open )
- {
- Close();
- }
- if ( m_IoThread != NULL )
- {
- delete m_IoThread;
- m_IoThread = NULL;
- }
-}
-
-/*
- * This method initializes SerialCommPlugin and starts SerialCommPluginIoThread
- */
-DWORD SerialCommPlugin::Init()
-{
- Util::Debug("SerialCommPlugin::Init()");
-
- std::string filename = SERIAL_INI_FILE_NAME;
- //read properties from serialplugin.ini file
- Util::ReadProperties(filename.c_str(), m_SerialCommPluginProperties);
-
- CheckProperties(m_SerialCommPluginProperties);
-
- CommChannelPlugin::Init();
-
- m_IoThread = new SerialCommIoThread(
- &m_RxQueue,
- &m_TxQueue,
- m_PropertySerialCommInitString,
- m_PropertySerialCommPort,
- m_PropertySerialCommTimeout,
- m_PropertySerialHwFlowControl,
- m_ProperySerialSendPause,
- m_PropertySerialMaxSendSize
- );
-
- m_IoThread->Start();
-
- Event e = m_IoThread->GetOpenedEvent();
- if ( e.Wait(m_PropertySerialCommTimeout) == WAIT_TIMEOUT )
- {
- Util::Debug("SerialCommPlugin::Init() SerialComm opening timed out");
- m_Open = false;
- return ERR_DG_COMM_OPEN_TIMEOUT;
- }
- Util::Debug("SerialCommPlugin::Init() SerialComm opened");
- m_Open = true;
- Util::Debug("SerialCommPlugin::Init() OK");
- return NO_ERRORS;
-}
-
-/*
- * This method initializes class member variables from values in map
- */
-void SerialCommPlugin::CheckProperties(map<string, string>& props)
-{
- char tmp[256];
-
- // Init values for connection
- m_PropertySerialCommInitString = props[SERIAL_INI_INIT_PARAM];
- Util::CheckCommandlineParam( PARAM_SWITCH_INIT_PARAM, m_PropertySerialCommInitString );
- if ( m_PropertySerialCommInitString.empty() )
- {
- m_PropertySerialCommInitString = SERIAL_DEFAULT_INIT_STRING;
- }
- sprintf_s(tmp, 256, "Connection Init : '%s'", m_PropertySerialCommInitString.c_str());
- string s(tmp);
- Util::Debug(s);
-
- // comm port
- m_PropertySerialCommPort = props[SERIAL_INI_COMPORT_PARAM];
- Util::CheckCommandlineParam( PARAM_SWITCH_COMPORT_PARAM, m_PropertySerialCommPort );
- if ( m_PropertySerialCommPort.empty() )
- {
- m_PropertySerialCommPort = SERIAL_DEFAULT_COMPORT;
- }
- sprintf_s(tmp, 256, "Connection port : '%s'", m_PropertySerialCommPort.c_str());
- s = tmp;
- Util::Debug(s);
-
- // Serial operations timeout
- string val = props[SERIAL_INI_COMPORT_TIMEOUT];
- Util::CheckCommandlineParam( PARAM_SWITCH_COMPORT_TIMEOUT, val );
- m_PropertySerialCommTimeout = 0;
- if ( !val.empty() )
- {
- m_PropertySerialCommTimeout = atol(val.c_str());
- }
-
- if ( m_PropertySerialCommTimeout <= 0 )
- {
- m_PropertySerialCommTimeout = g_SerialCommDefaultTimeout;
- }
- sprintf_s(tmp, 256, "Timeout: '%d'", m_PropertySerialCommTimeout);
- s = tmp;
- Util::Debug(s);
-
- // flow control
- m_PropertySerialHwFlowControl = false;
- val = props[SERIAL_INI_USE_HW_FLOW_CONTROL];
- Util::CheckCommandlineParam( PARAM_SWITCH_USE_HW_FLOW_CONTROL, val );
- if ( !val.empty() && val == "1" )
- {
- m_PropertySerialHwFlowControl = true;
- Util::Debug("Use serial HW flow control");
- }
- else
- {
- Util::Debug("Do not use serial HW flow control");
- }
-
- // send pause
- val = props[SERIAL_INI_SEND_SLEEP_PAUSE];
- Util::CheckCommandlineParam( PARAM_SWITCH_SEND_SLEEP_PAUSE, val );
- if ( !val.empty() )
- {
- m_ProperySerialSendPause = atol(val.c_str());
- }
- if ( m_ProperySerialSendPause <= 0 )
- {
- m_ProperySerialSendPause = g_SerialCommDefaultSendPause;
- }
- sprintf_s(tmp, 256, "Send pause: '%d'", m_ProperySerialSendPause);
- s = tmp;
- Util::Debug(s);
-
- // send size
- val = props[SERIAL_INI_SEND_SIZE];
- Util::CheckCommandlineParam( PARAM_SWITCH_SEND_SIZE, val );
- if ( !val.empty() )
- {
- m_PropertySerialMaxSendSize = atol(val.c_str());
- }
- if ( m_PropertySerialMaxSendSize <= 0 )
- {
- m_PropertySerialMaxSendSize = 0;
- }
- sprintf_s(tmp, 256, "Send max size: '%d'", m_PropertySerialMaxSendSize);
- s = tmp;
- Util::Debug(s);
-}
-
-/*
- * This method checks if data is available on incoming queue
- */
-bool SerialCommPlugin::IsDataAvailable()
-{
- return ( !m_RxQueue.empty() );
-}
-
-/*
- * This method is used to:
- * -push given data to outgoing queue
- * -wait for data to become available in incoming queue
- * -pop the first Data object from queue and store it to the Data object given as parameter
- */
-DWORD SerialCommPlugin::SendReceive(Data* data_in, Data** data_out, long timeout)
-{
- DWORD res;
- if ( ( res = Send(data_in, timeout)) == NO_ERRORS &&
- ( res = ReceiveWait(data_out, timeout)) == NO_ERRORS )
- {
- return NO_ERRORS;
- }
- cout << "SerialCommPlugin::SendReceive: error" << endl;
- return res;
-}
-
-/*
- * This method pushes the given Data object(of type Data::EData) to outgoing queue
- */
-DWORD SerialCommPlugin::Send(Data* data_in, long timeout)
-{
- Data::DataType type = data_in->GetType();
- if ( type == Data::EData )
- {
- DWORD length = data_in->GetLength();
- m_TxQueue.push(data_in);
- return NO_ERRORS;
- }
- else if ( type == Data::EControl )
- {
- Util::Debug("SerialCommPlugin::Send: Control Message Received");
- return NO_ERRORS;
- }
- return ERR_DG_COMM_DATA_SEND;
-}
-
-/*
- * This method is used to wait for data to become available in incoming queue
- * and then pop the first Data object from the queue and and store it to Data object given as parameter.
- */
-DWORD SerialCommPlugin::ReceiveWait(Data** data_out, long timeout)
-{
- long elapsed = 0;
- while (elapsed < timeout && !IsDataAvailable())
- {
- elapsed += 25;
- Sleep(25);
- }
- if ( elapsed >= timeout )
- {
- return ERR_DG_COMM_DATA_RECV_TIMEOUT;
- }
- return Receive(data_out, timeout);
-}
-
-/*
- * This method is used to pop the first data object from incoming queue and store it to data object given as parameter
- */
-DWORD SerialCommPlugin::Receive(Data** data_out, long timeout)
-{
- if ( !m_RxQueue.empty() )
- {
- *data_out = m_RxQueue.front();
- m_RxQueue.pop();
- return NO_ERRORS;
- }
- return ERR_DG_COMM_DATA_RECV;
-}
-
-
-DWORD SerialCommPlugin::Open()
-{
- return ( m_Open ? NO_ERRORS : ERR_DG_COMM_OPEN );
-}
-
-/*
- * This method stops SerialCommIoThread and waits for it to be in signaled state
- */
-DWORD SerialCommPlugin::Close()
-{
- m_IoThread->Stop();
- WaitForSingleObject( m_IoThread->ThreadHandle(), g_MaximumShutdownWaitTime );
- return NO_ERRORS;
-}
-
-//**********************************************************************************
-// Class SerialComm
-//
-// This class implements the actual serial communication using Windows API
-//**********************************************************************************
-
-SerialComm::SerialComm()
- : m_Open(false),
- m_SendPause(0),
- m_SendMaxSize(0)
-{
-
-}
-
-SerialComm::~SerialComm()
-{
- Util::Debug("SerialComm::~SerialComm()");
- if ( m_Open )
- {
- Close();
- }
-}
-/*
- * This method opens a communication device that uses serial communication and
- * configures it according initialization parameters
- */
-WORD SerialComm::Open( const string& commPort, const string& initParameters,
- long timeout,
- bool hwFlowControl, long sendPause, long sendMaxSize)
-{
- Util::Debug("SerialComm::Open()");
-
- m_SendPause = sendPause;
-
- if ( sendMaxSize>0 )
- {
- m_SendMaxSize = sendMaxSize;
- }
-
- DWORD err;
- //check commPort and add "\\.\" prefix if port is larger than 9
- string localCommPort(commPort);
- static const basic_string <char>::size_type npos = -1;
- if ( localCommPort.find(HIGH_COM_PORT) == npos &&
- localCommPort.find("COM") == 0 &&
- localCommPort.length() > 4 //two digit port number
- )
- {
- localCommPort.insert(0, HIGH_COM_PORT);
- }
- Util::Debug(localCommPort.c_str());
-
- // If COM-port opening fails, it's retried until HtiGateway is killed.
- m_Com = INVALID_HANDLE_VALUE;
- while ( m_Com == INVALID_HANDLE_VALUE )
- {
- // Open file (COM port)
- m_Com = CreateFile( localCommPort.c_str(),
- GENERIC_READ | GENERIC_WRITE,
- 0, //excusive access
- NULL, //no security
- OPEN_EXISTING, //must use
- 0, //not overlapped i/o
- NULL // must be NULL for comm
- );
-
- if ( m_Com == INVALID_HANDLE_VALUE )
- {
- err = GetLastError();
- Util::Error("[SerialComm] Failed to open COM port", err);
- Util::Info("[SerialComm] Retrying...");
- Sleep(5000);
- }
- }
-
- // Serial port cfg
- Util::Debug(initParameters.c_str());
- DCB dcb;
-
- FillMemory(&dcb, sizeof(dcb), 0);
- dcb.DCBlength = sizeof(dcb);
- if ( !BuildCommDCB(initParameters.c_str(), &dcb) )
- {
- err = GetLastError();
- Util::Error("[SerialComm] Failed to build port settings ", err);
- return ERR_DG_COM_INIT;
- }
-
- dcb.fBinary = TRUE ;
-
- //set hw handshaking
- dcb.fOutX = FALSE;
- dcb.fInX = FALSE;
- dcb.fNull = FALSE;
- dcb.fAbortOnError = TRUE;
-
- dcb.fOutxDsrFlow = FALSE;
- dcb.fDtrControl = DTR_CONTROL_DISABLE;
- dcb.fDsrSensitivity= FALSE;
- dcb.fDtrControl = DTR_CONTROL_DISABLE;
-
- if ( hwFlowControl )
- {
- dcb.fOutxCtsFlow = TRUE;
- dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
- }
- else
- {
- dcb.fOutxCtsFlow = FALSE;
- dcb.fRtsControl = RTS_CONTROL_ENABLE;
- }
-
- if ( !SetCommState(m_Com, &dcb) )
- {
- err = GetLastError();
- Util::Error("[SerialComm] Failed to set port settings ", err);
- return ERR_DG_COM_INIT;
- }
-
- COMMTIMEOUTS timeouts;
-
- timeouts.ReadIntervalTimeout = MAXDWORD;
-
- timeouts.ReadTotalTimeoutMultiplier = timeout;
- timeouts.ReadTotalTimeoutConstant = 1;
- timeouts.WriteTotalTimeoutMultiplier = 1;
- timeouts.WriteTotalTimeoutConstant = timeout;
-
- if ( !SetCommTimeouts(m_Com, &timeouts) )
- {
- // Error setting time-outs.
- err = GetLastError();
- Util::Error("[SerialComm] Failed to set port timeouts ", err);
- return ERR_DG_COM_INIT;
- }
-
-
- m_Open = true;
- Util::Debug("SerialComm::Open() OK");
- Util::Info("[SerialComm] COM port open");
- return NO_ERRORS;
-}
-
-/*
- * This method is used to send Data object using serial communication
- */
-DWORD SerialComm::Send(const Data& data_in)
-{
- Util::Debug("SerialComm::Send()");
- if ( data_in.GetLength() > 0 )
- {
- DWORD sentBytes = 0;
- void* data = data_in.GetData();
- int numOfTries = 0;
- //loop until whole Data object is sent
- while ( sentBytes < data_in.GetLength() )
- {
- //Util::Debug("while");
- DWORD sent;
- BOOL r;
- if ( m_SendMaxSize>0 )
- {
- //Write data to the communication device
- r = WriteFile(m_Com,
- ((char*)data) + sentBytes,
- //data_in.GetLength() - sentBytes,
- min(data_in.GetLength() - sentBytes, m_SendMaxSize),
- &sent,
- NULL);
- }
- else
- {
- r = WriteFile(m_Com,
- ((char*)data) + sentBytes,
- data_in.GetLength() - sentBytes,
- &sent,
- NULL);
- }
-
- if ( r && sent > 0 )
- {
- if (Util::GetVerboseLevel() == Util::debug)
- {
- Util::Hex(((char*)data) + sentBytes, min(sent,16));
- }
- sentBytes+=sent;
- }
- else
- {
- if ( !r )
- {
- DWORD err = GetLastError();
- Util::Error("[SerialComm] Send error", err);
- }
- else
- {
- Util::Error("[SerialComm] Send failed");
- }
- if ( numOfTries++==g_SerialMaxResendNumber )
- {
- return ERR_DG_COMM_DATA_RECV;
- }
- }
- //used to "solve" overflow problem
- if ( m_SendPause > 0 )
- {
- Sleep(m_SendPause);
- }
- }
- }
-
- Util::Debug("SerialComm::Send() OK");
- return NO_ERRORS;
-}
-
-/*
- * This method reads all available data from communication media
- * and returns it in the Data object given as parameter
- */
-DWORD SerialComm::Receive(Data* data_out)
-{
- Util::Debug("SerialComm::Receive()");
-
- //get available bytes in incoming communication channel
- LONG rxBytes = GetRxBytesAvailable();
-
- if ( rxBytes > 0 )
- {
- char* data = new char[rxBytes];
- DWORD readBytes = 0;
- //read data until all available bytes have been red
- do
- {
- DWORD reallyRead;
- if ( ReadFile(m_Com,
- data + readBytes,
- rxBytes - readBytes,
- &reallyRead,
- NULL) )
- {
- if (Util::GetVerboseLevel() == Util::debug)
- {
- char temp[64];
- sprintf_s(temp, 64, "Received %d bytes", reallyRead);
- Util::Debug( temp );
- Util::Hex(data + readBytes, min(16,reallyRead));
- }
- readBytes += reallyRead;
- }
- else
- {
- delete[] data;
- DWORD err = GetLastError();
- Util::Error("[SerialComm] Error %d", err);
- return ERR_DG_COMM_DATA_RECV;
- }
- if ( readBytes > rxBytes )
- {
- Util::Error("[SerialComm] !!! readBytes > rxBytes !!!");
- }
- }
- while( readBytes < rxBytes );
-
- data_out->SetData( data, rxBytes, Data::EData);
- delete[] data;
- }
- else if ( rxBytes < 0 ) //err
- {
- return ERR_DG_COMM_DATA_RECV;
- }
- return NO_ERRORS;
-}
-
-/*
- * This method returns number of bytes available in incoming queue or
- * -1 if communication error has occurred
- */
-LONG SerialComm::GetRxBytesAvailable()
-{
- COMSTAT res;
- DWORD err;
-
- if ( ClearCommError(m_Com, &err, &res ) )
- {
- return res.cbInQue;
- }
- else
- {
- DWORD err = GetLastError();
- Util::Error("[SerialComm] Error getting Rx bytes %d", err);
- return -1;
- }
-}
-
-DWORD SerialComm::Close()
-{
- Util::Debug("SerialComm::Close()");
- m_Open = false;
-
- if ( m_Com != INVALID_HANDLE_VALUE )
- {
- CloseHandle(m_Com);
- m_Com = INVALID_HANDLE_VALUE;
- }
-
- Util::Debug("SerialComm::Close() OK");
- return NO_ERRORS;
-}
-
-//**********************************************************************************
-// Class SerialCommIoThread
-//
-// This thread is used to send data from outgoing queue to serial port
-// and read bytes from serial port and push it to incoming queue
-//**********************************************************************************
-
-SerialCommIoThread::SerialCommIoThread(SafeQueue<Data*>* in,
- SafeQueue<Data*>* out,
- const string& init, const string& commPort, long timeout,
- bool hwFlowControl, long sendPause, long sendMaxSize)
- : m_InitString(init),
- m_CommPort( commPort ),
- m_PropertySerialCommTimeout( timeout ),
- m_PropertySerialHwFlowControl( hwFlowControl ),
- m_ProperySerialSendPause(sendPause),
- m_PropertySerialMaxSendSize(sendMaxSize)
-{
- m_InQueue = in;
- m_OutQueue = out;
- m_Running = true;
- m_OpenedEvent.Reset();
-}
-
-/*
- * Main execution loop which is used to send Data from outgoing queue to serial port
- * and read bytes from serial port, encapsulate it to Data objects and push them to incoming queue
- */
-void SerialCommIoThread::Run()
-{
- while ( m_Running )
- {
- Util::Debug("SerialCommIoThread::Run()");
- SerialComm m_SerialComm;
-
- if ( m_SerialComm.Open(m_CommPort, m_InitString, m_PropertySerialCommTimeout,
- m_PropertySerialHwFlowControl, m_ProperySerialSendPause,
- m_PropertySerialMaxSendSize) != NO_ERRORS )
- {
- m_Running = false;
- return;
- }
- m_OpenedEvent.Set();
-
- Util::Debug("SerialCommIoThread::Run() start loop");
- while ( m_Running )
- {
- // Sending data
- try
- {
- Data* out = m_OutQueue->front(30);
- if ( m_SerialComm.Send(*out) != NO_ERRORS )
- {
- //Data* d = new Data("Error sending data", 19, Data::EControl);
- Data* d = CREATE_CONTROL_MESSAGE("[HtiGateway]: Error sending data");
- m_InQueue->push(d);
- d = NULL;
- }
- m_OutQueue->pop();
- delete out;
- out = NULL;
- } catch (TimeoutException te) {}
-
-
- // Receiving data
- LONG rxBytes = 0;
- while ( ( rxBytes = m_SerialComm.GetRxBytesAvailable() ) > 0 )
- {
- Data* in = new Data;
- if ( m_SerialComm.Receive(in) == NO_ERRORS )
- {
- m_InQueue->push(in);
- in = NULL;
- }
- else
- {
- delete in;
- in = NULL;
- }
- }
- if ( rxBytes < 0 )
- {
- Util::Info("[SerialCommIoThread] COM-port lost. Trying to close & reopen");
- break; // break out but keep the outermost while loop running
- }
- }
- m_OpenedEvent.Reset();
- m_SerialComm.Close();
- }
- Util::Debug("SerialCommIoThread::Run() exiting");
-}
-
-void SerialCommIoThread::Stop()
-{
- Util::Debug("SerialCommIoThread::Stop()");
- m_Running = false;
-}
-
-Event SerialCommIoThread::GetOpenedEvent()
-{
- return m_OpenedEvent;
-}
-
-void SerialCommIoThread::SetTimeout(long timeout)
-{
- if ( timeout > 0 )
- {
- m_PropertySerialCommTimeout = timeout;
- }
- else
- {
- m_PropertySerialCommTimeout = g_SerialCommDefaultTimeout;
- }
-}
-
-long SerialCommIoThread::GetTimeout() const
-{
- return m_PropertySerialCommTimeout;
-}
-
-// End of the file