view main/packages/linux/can/CANMsgProcessor.cpp @ 264:cb0d6aab498d main

Reduce the waiting time when polling for messages to receive, send
author Bob Cook <bob@bobcookdev.com>
date Fri, 25 Mar 2016 12:09:41 -0700
parents f1944fbcf419
children
line wrap: on
line source

// ----------------------------------------------------------------------------------------
//
//  packages/linux/can/CANMsgProcessor.cpp
//    
//  Bob Cook Development, Robotics Library
//  http://www.bobcookdev.com/rl/
// 
//  Thread that processes CAN messages for a socket. Messages read from the socket are put
//  into a global queue for processing by other threads. Messages are pulled from another
//  global queue for writing to the socket.
//
//  Copyright (c) 2011-2016 Bob Cook
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//
// ----------------------------------------------------------------------------------------

#include "CANMsgProcessor.h"

#include <stdexcept>

#include <Poco/Exception.h>
#include <Poco/Logger.h>
#include <Poco/Thread.h>
#include <Poco/Timespan.h>

#include "packages/linux/can/CANMessage.h"
#include "packages/linux/can/CANSocket.h"

// ----------------------------------------------------------------------------------------

CANMsgProcessor::CANMsgProcessor( const std::string& canInterface )
    : Poco::Runnable(),
      m_canInterfaceName( canInterface ),
      m_loggerName(),
      m_quitEvent( false /* not auto-reset */ ),
      m_logIncoming( false ),
      m_logOutgoing( false )
{
}

// ----------------------------------------------------------------------------------------

CANMsgProcessor::CANMsgProcessor
(
    const std::string& canInterface,
    const std::string& logger
)
    : Poco::Runnable(),
      m_canInterfaceName( canInterface ),
      m_loggerName( logger ),
      m_quitEvent( false /* not auto-reset */ ),
      m_logIncoming( false ),
      m_logOutgoing( false )
{
}

// ----------------------------------------------------------------------------------------

CANMsgProcessor::~CANMsgProcessor()
{
}

// ----------------------------------------------------------------------------------------

void CANMsgProcessor::logIncomingMessages( bool yesLog )
{
    m_logIncoming = yesLog;
}

// ----------------------------------------------------------------------------------------

void CANMsgProcessor::logOutgoingMessages( bool yesLog )
{
    m_logOutgoing = yesLog;
}

// ----------------------------------------------------------------------------------------

void CANMsgProcessor::timeToQuit()
{
    m_quitEvent.set();
}

// ----------------------------------------------------------------------------------------

void CANMsgProcessor::run()
{
    Poco::Logger& log = Poco::Logger::get( m_loggerName );

    for ( ;; )
    {
        try
        {
            CANSocket sock;
            sock.bind( m_canInterfaceName );

            Poco::Timespan pollDelay( 100 ); // 0.1ms
            Poco::Timespan writeWaitTime( 1 * 1000 ); // 1ms

            for ( ;; )
            {
                // handle pending reads

                if ( sock.poll( pollDelay, Poco::Net::Socket::SELECT_READ ) )
                {
                    Poco::AutoPtr<CANMessage> msg( sock.read() );

                    if ( m_logIncoming )
                    {
                        std::string text( "CAN frame recv: " );
                        text += CANMessage::asText( msg );
                        log.information( text );
                    }

                    CANMessage::QueueReceived( msg.duplicate() );
                }

                // handle queued writes

                Poco::AutoPtr<CANMessage> msg( CANMessage::WaitDequeueToSend( 0 ) );

                if ( msg.get() != 0 )
                {
                    if ( sock.poll( writeWaitTime, Poco::Net::Socket::SELECT_WRITE ) )
                    {
                        if ( m_logOutgoing )
                        {
                            std::string text( "CAN frame send: " );
                            text += CANMessage::asText( msg );
                            log.information( text );
                        }

                        sock.write( *msg );
                    }
                    else
                    {
                        throw Poco::Exception( "socket failed to become writable" );
                    }
                }

                // handle socket errors

                if ( sock.poll( Poco::Timespan( 0 ), Poco::Net::Socket::SELECT_ERROR ) )
                {
                    throw Poco::Exception( "socket in error state" );
                }

                // time to quit?

                if ( m_quitEvent.tryWait( 0 ) && CANMessage::IsSendQueueEmpty() )
                {
                    return;
                }
            }
        }
        catch ( const Poco::Exception& ex )
        {
            log.error( std::string( "CANMsgProcessor::run() caught Poco::Exception: " )
                                + ex.displayText() );
        }
        catch ( const std::exception& ex )
        {
            log.error( std::string( "CANMsgProcessor::run() caught std::exception: " )
                                + ex.what() );
        }
        catch ( ... )
        {
            log.error( "CANMsgProcessor::run() caught unknown exception" );
        }

        // sleep for 1/2 second after exception processing, but don't exit
        Poco::Thread::sleep( 500 );
    }
}

// ----------------------------------------------------------------------------------------