/**
 * @file tracer.h
 *
 * Tracer - Classes for creating CAPI trace files.
 *
 * Copyright: 2002-2003 Thomas Wintergerst. All rights reserved.
 *
 * $FreeBSD$
 * $Id: tracer.h,v 1.1.2.1 2006/02/28 21:35:44 thomas Exp $
 * Project  CAPI for BSD
 * Target   capitrace - Tracing CAPI calls and messages
 * @date    21.09.2002
 * @author  "Thomas Wintergerst" <twinterg@gmx.de>
 * <p>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * </p>
 */

#ifndef __TRACER_H
#define __TRACER_H

#include <list>
#include <iostream>
#include <fstream>
#include <pthread.h>
#include <capi20.h>
#include <capi_bsd.h>
#include <capi_bsdtrc.h>

#ifndef __CONFIG_H
#  include "config.h"
#endif





// === Public declarations ===============================================





// === Class declarations ================================================





/**
 * Class for creating a single CAPI trace.
 */
class CTracer
{
   public:
      /// The possible states of a tracer object.
      enum State_t
      {
         STATE_IDLE,            ///< Starting state, nothing done yet.
         STATE_STARTING,        ///< Tracer start request sent, waiting for
                                ///< confirmation.
         STATE_ACTIVE,          ///< Tracer is started successfully, expecting
                                ///< trace messages.
         STATE_STOPPING,        ///< Tracer stop request sent, waiting for
                                ///< confirmation.
         STATE_STOPPED          ///< Final state after tracer stop confirmation,
                                ///< request failure or negative confirmation.
      };
      
      
      
      /**
       * Constructor.
       */
      CTracer
         (const CConfig::TracerConfig_t &roTracerConfig);
      
      /**
       * Destructor.
       */
      ~CTracer (void);
      
      /**
       * Query the state of this tracer object.
       */
      State_t GetState (void) const;
      
      /**
       * Query the unique number of the current tracer object.
       */
      int GetUniqueNumber (void) const;
      
      /**
       * Query if the tracer is of type controller tracer.
       */
      bool IsCtlrTracer (void) const;
      
      /**
       * Query for the controller number this (controller) tracer runs for.
       *
       * @note If this is an application tracer, the result value of this
       *       function is simple null, i.e. an invalid controller number.
       */
      unsigned GetCtlr (void) const;
      
      /**
       * Query the tracer id for the running tracer.
       *
       * @note If the tracer is not currently running, the result is simply
       *       null, i.e. an invalid tracer id.
       */
      u_int32_t GetTracerID (void) const;
      
      /**
       * Send CAPI message to start the tracer.
       *
       * @attention To serialize CAPI access this message must be called with
       *            the CAPI mutex locked.
       *
       * @param uCapiApplID     I: The CAPI application id to use.
       *
       * @return                The CAPI result value of the
       *                        capi20_put_message() function. If it is CAPI_OK,
       *                        the message was successfully sent, the tracer
       *                        may go to active state if a positive
       *                        confirmation is received later. Else the message
       *                        could not be sent, the tracer will not go to
       *                        active state.
       */
      unsigned SendStartTracerRequest
         (unsigned uCapiApplID);
      
      /**
       * Send CAPI message to stop the tracer.
       *
       * @attention To serialize CAPI access this message must be called with
       *            the CAPI mutex locked.
       *
       * @param uCapiApplID     I: The CAPI application id to use.
       *
       * @return                The CAPI result value of the
       *                        capi20_put_message() function call. If it is
       *                        CAPI_OK, the message was successfully sent, the
       *                        tracer may go to disabled state if a positive
       *                        confirmation is received later. Else the message
       *                        could not be sent, the tracer will not go to
       *                        disabled state.
       */
      unsigned SendStopTracerRequest
         (unsigned uCapiApplID);
      
      /**
       * Handle a confirmation for a tracer start request.
       *
       * @param pMsg            I: The CAPI message for the start confirmation.
       *
       * @return Nothing.
       */
      void HandleStartTracerConfirm
         (const CAPIMsg_t *pMsg);
      
      /**
       * Handle a confirmation for a tracer stop request.
       *
       * @param pMsg            I: The CAPI message for the stop confirmation.
       *
       * @return Nothing.
       */
      void HandleStopTracerConfirm
         (const CAPIMsg_t *pMsg);
      
      /**
       * Handle a CAPI trace message.
       *
       * @param pTraceMsg       I: The trace message information part of the
       *                           CAPI message after the dwManuID part.
       *
       * @return Nothing.
       */
      void HandleTraceMessage
         (const CAPITraceMsg_t *pTraceMsg);



   protected:
      /// The class global counter for creating unique tracer numbers.
      static int m_iCurrUniqueNumber;
      
      /// The current state of the tracer object
      State_t m_state;
      
      /// The unique number of the current tracer object
      int m_iUniqueNumber;
      
      /// The tracer configuration from startup
      CConfig::TracerConfig_t m_oConfig;
      
      /// The tracer id assigned by CAPI.
      u_int32_t m_dwTracerID;
      
      /// If the output stream is a regular file, this member holds the stream
      /// to it; otherwise it is NULL.
      std::ofstream *m_poOutFStream;
      
      /// This reference points either to cout or to the stream stored in
      /// m_poOutFStream.
      std::ostream *m_poOS;
      
   
   
   private:
   
   
   
}; // CTracer





/**
 * Class for maintaining a list of CAPI tracers and providing them with CAPI
 * messages.
 */
class CTracerList: public std::list<CTracer *>
{
   friend void TermSignalHandler (int);
   friend void *DoCapiService (void *);
   
   public:
      /**
       * Constructor.
       */
      CTracerList (void);
      
      /**
       * Destructor.
       */
      ~CTracerList (void);
      
      /**
       * Get the running instance of this class.
       */
      static CTracerList *GetInstance (void);
      
      /**
       * Add a new tracer object to this list.
       */
      void Add
         (const CConfig::TracerConfig_t &roTracerConfig);
      
      /**
       * Start all tracers and handle CAPI messages until program termination
       * signal.
       */
      void Run (void);
   
      /**
       * Stop all running tracers and the handling of incoming CAPI messages.
       */
      void Stop (void);

   
   
   protected:
      /// Place to store the address of the one-and-only instance of this class.
      static CTracerList *m_poInstance;
      
      /// Flag for completed CAPI registration.
      bool m_fCapiRegistered;
      
      /// Assigned CAPI application id if registration completed.
      unsigned m_uCapiApplID;
      
      /// Flag for running CAPI message receive thread.
      bool m_fCapiThreadRunning;
      
      /// Thread id for the running CAPI message receive thread.
      pthread_t m_capiThreadID;
   
      /// The mutex to serialize CAPI access for the main thread, the CAPI
      /// thread and the signal handler.
      pthread_mutex_t m_mutexCapi;
      
      /// Flag for an initialized CAPI serialization mutex.
      bool m_fCapiMutexValid;
      
   
   
   private:
   
   
   
}; // CTracerList





// === Prototypes of interface functions =================================





#endif // __TRACER_H
