text: /*
   * \file       ocsd_dcd_tree.cpp
   * \brief      OpenCSD : 
   * 
   * \copyright  Copyright (c) 2015, ARM Limited. All Rights Reserved.
   */
  
  
  /* 
   * 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. 
   * 
   * 3. Neither the name of the copyright holder nor the names of its contributors 
   * may be used to endorse or promote products derived from this software without 
   * specific prior written permission. 
   * 
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. 
   */ 
  
  #include "common/ocsd_dcd_tree.h"
  #include "common/ocsd_lib_dcd_register.h"
  #include "mem_acc/trc_mem_acc_mapper.h"
  
  /***************************************************************/
  ITraceErrorLog *DecodeTree::s_i_error_logger = &DecodeTree::s_error_logger; 
  std::list<DecodeTree *> DecodeTree::s_trace_dcd_trees;  /**< list of pointers to decode tree objects */
  ocsdDefaultErrorLogger DecodeTree::s_error_logger;     /**< The library default error logger */
  TrcIDecode DecodeTree::s_instruction_decoder;           /**< default instruction decode library */
  
  DecodeTree *DecodeTree::CreateDecodeTree(const ocsd_dcd_tree_src_t src_type, uint32_t formatterCfgFlags)
  {
      DecodeTree *dcd_tree = new (std::nothrow) DecodeTree();
      if(dcd_tree != 0)
      {
          if(dcd_tree->initialise(src_type, formatterCfgFlags))
          {
              s_trace_dcd_trees.push_back(dcd_tree);
          }
          else 
          {
              delete dcd_tree;
              dcd_tree = 0;
          }
      }
      return dcd_tree;
  }
  
  void DecodeTree::DestroyDecodeTree(DecodeTree *p_dcd_tree)
  {
      std::list<DecodeTree *>::iterator it;
      bool bDestroyed = false;
      it = s_trace_dcd_trees.begin();
      while(!bDestroyed && (it != s_trace_dcd_trees.end()))
      {
          if(*it == p_dcd_tree)
          {
              s_trace_dcd_trees.erase(it);
              delete p_dcd_tree;
              bDestroyed = true;
          }
          else
              it++;
      }
  }
  
  void DecodeTree::setAlternateErrorLogger(ITraceErrorLog *p_error_logger)
  {
      if(p_error_logger)
          s_i_error_logger = p_error_logger;
      else
          s_i_error_logger = &s_error_logger;
  }
  
  /***************************************************************/
  
  DecodeTree::DecodeTree() :
      m_i_instr_decode(&s_instruction_decoder),
      m_i_mem_access(0),
      m_i_gen_elem_out(0),
      m_i_decoder_root(0),
      m_frame_deformatter_root(0),
      m_decode_elem_iter(0),
      m_default_mapper(0),
      m_created_mapper(false)
  {
      for(int i = 0; i < 0x80; i++)
          m_decode_elements[i] = 0;
  }
  
  DecodeTree::~DecodeTree()
  {
      destroyMemAccMapper();
      for(uint8_t i = 0; i < 0x80; i++)
      {
          destroyDecodeElement(i);
      }
      PktPrinterFact::destroyAllPrinters(m_printer_list);
      delete m_frame_deformatter_root;
  }
  
  
  
  ocsd_datapath_resp_t DecodeTree::TraceDataIn( const ocsd_datapath_op_t op,
                                                 const ocsd_trc_index_t index,
                                                 const uint32_t dataBlockSize,
                                                 const uint8_t *pDataBlock,
                                                 uint32_t *numBytesProcessed)
  {
      if(m_i_decoder_root)
          return m_i_decoder_root->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed);
      *numBytesProcessed = 0;
      return OCSD_RESP_FATAL_NOT_INIT;
  }
  
  /* set key interfaces - attach / replace on any existing tree components */
  void DecodeTree::setInstrDecoder(IInstrDecode *i_instr_decode)
  {
      uint8_t elemID;
      DecodeTreeElement *pElem = 0;
  
      pElem = getFirstElement(elemID);
      while(pElem != 0)
      {
          pElem->getDecoderMngr()->attachInstrDecoder(pElem->getDecoderHandle(),i_instr_decode);
          pElem = getNextElement(elemID);
      }
  }
  
  void DecodeTree::setMemAccessI(ITargetMemAccess *i_mem_access)
  {
      uint8_t elemID;
      DecodeTreeElement *pElem = 0;
     
      pElem = getFirstElement(elemID);
      while(pElem != 0)
      {
          pElem->getDecoderMngr()->attachMemAccessor(pElem->getDecoderHandle(),i_mem_access);
          pElem = getNextElement(elemID);
      }
      m_i_mem_access = i_mem_access;
  }
  
  void DecodeTree::setGenTraceElemOutI(ITrcGenElemIn *i_gen_trace_elem)
  {
      uint8_t elemID;
      DecodeTreeElement *pElem = 0;
  
      pElem = getFirstElement(elemID);
      while(pElem != 0)
      {
          pElem->getDecoderMngr()->attachOutputSink(pElem->getDecoderHandle(),i_gen_trace_elem);
          pElem = getNextElement(elemID);
      }
  }
  
  ocsd_err_t DecodeTree::createMemAccMapper(memacc_mapper_t type /* = MEMACC_MAP_GLOBAL*/ )
  {
      // clean up any old one
      destroyMemAccMapper();
  
      // make a new one
      switch(type)
      {
      default:
      case MEMACC_MAP_GLOBAL:
          m_default_mapper = new (std::nothrow) TrcMemAccMapGlobalSpace();
          break;
      }
  
      // set the access interface
      if(m_default_mapper)
      {
          m_created_mapper = true;
          setMemAccessI(m_default_mapper);
          m_default_mapper->setErrorLog(s_i_error_logger);
      }
  
      return (m_default_mapper != 0) ? OCSD_OK : OCSD_ERR_MEM;
  }
  
  void DecodeTree::setExternMemAccMapper(TrcMemAccMapper* pMapper)
  {
      destroyMemAccMapper();  // destroy any existing mapper - if decode tree created it.
      m_default_mapper = pMapper;
  }
  
  void DecodeTree::destroyMemAccMapper()
  {
      if(m_default_mapper && m_created_mapper)
      {
          m_default_mapper->RemoveAllAccessors();
          delete m_default_mapper;
          m_default_mapper = 0;
          m_created_mapper = false;
      }
  }
  
  void DecodeTree::logMappedRanges()
  {
      if(m_default_mapper)
          m_default_mapper->logMappedRanges();
  }
  
  /* Memory accessor creation - all on default mem accessor using the 0 CSID for global core space. */
  ocsd_err_t DecodeTree::addBufferMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t *p_mem_buffer, const uint32_t mem_length)
  {
      if(!hasMemAccMapper())
          return OCSD_ERR_NOT_INIT;
  
      // need a valid memory buffer, and a least enough bytes for one opcode.
      if((p_mem_buffer == 0) || (mem_length < 4))
          return OCSD_ERR_INVALID_PARAM_VAL;
  
      TrcMemAccessorBase *p_accessor;
      ocsd_err_t err = TrcMemAccFactory::CreateBufferAccessor(&p_accessor, address, p_mem_buffer, mem_length);
      if(err == OCSD_OK)
      {
          TrcMemAccBufPtr *pMBuffAcc = dynamic_cast<TrcMemAccBufPtr *>(p_accessor);
          if(pMBuffAcc)
          {
              pMBuffAcc->setMemSpace(mem_space);
              err = m_default_mapper->AddAccessor(p_accessor,0);
          }
          else
              err = OCSD_ERR_MEM;    // wrong type of object - treat as mem error
  
          if(err != OCSD_OK)
              TrcMemAccFactory::DestroyAccessor(p_accessor);
      }
      return err;
  }
  
  ocsd_err_t DecodeTree::addBinFileMemAcc(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const std::string &filepath)
  {
      if(!hasMemAccMapper())
          return OCSD_ERR_NOT_INIT;
      
      if(filepath.length() == 0)
          return OCSD_ERR_INVALID_PARAM_VAL;
  
      TrcMemAccessorBase *p_accessor;
      ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,address);
  
      if(err == OCSD_OK)
      {
          TrcMemAccessorFile *pAcc = dynamic_cast<TrcMemAccessorFile *>(p_accessor);
          if(pAcc)
          {
              pAcc->setMemSpace(mem_space);
              err = m_default_mapper->AddAccessor(pAcc,0);
          }
          else
              err = OCSD_ERR_MEM;    // wrong type of object - treat as mem error
  
          if(err != OCSD_OK)
              TrcMemAccFactory::DestroyAccessor(p_accessor);
      }
      return err;
  
  }
  
  ocsd_err_t DecodeTree::addBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath)
  {
      if(!hasMemAccMapper())
          return OCSD_ERR_NOT_INIT;
  
      if((region_array == 0) || (num_regions == 0) || (filepath.length() == 0))
          return OCSD_ERR_INVALID_PARAM_VAL;
  
      TrcMemAccessorBase *p_accessor;
      int curr_region_idx = 0;
  
      // add first region during the creation of the file accessor.
      ocsd_err_t err = TrcMemAccFactory::CreateFileAccessor(&p_accessor,filepath,region_array[curr_region_idx].start_address,region_array[curr_region_idx].file_offset, region_array[curr_region_idx].region_size);            
      if(err == OCSD_OK)
      {
          TrcMemAccessorFile *pAcc = dynamic_cast<TrcMemAccessorFile *>(p_accessor);
          if(pAcc)
          {
              // add additional regions to the file accessor.
              curr_region_idx++;
              while(curr_region_idx < num_regions)
              {
                  pAcc->AddOffsetRange(region_array[curr_region_idx].start_address, 
                                          region_array[curr_region_idx].region_size,
                                          region_array[curr_region_idx].file_offset);
                  curr_region_idx++;
              }
              pAcc->setMemSpace(mem_space);
  
              // add the accessor to the map.
              err = m_default_mapper->AddAccessor(pAcc,0);
          }
          else
              err = OCSD_ERR_MEM;    // wrong type of object - treat as mem error
  
          if(err != OCSD_OK)
              TrcMemAccFactory::DestroyAccessor(p_accessor);
      }
      return err;
  }
  
  ocsd_err_t DecodeTree::updateBinFileRegionMemAcc(const ocsd_file_mem_region_t *region_array, const int num_regions, const ocsd_mem_space_acc_t mem_space, const std::string &filepath)
  {
      if (!hasMemAccMapper())
          return OCSD_ERR_NOT_INIT;
  
      if ((region_array == 0) || (num_regions == 0) || (filepath.length() == 0))
          return OCSD_ERR_INVALID_PARAM_VAL;
  
      TrcMemAccessorFile *pAcc = TrcMemAccessorFile::getExistingFileAccessor(filepath);
      if (!pAcc) 
          return OCSD_ERR_INVALID_PARAM_VAL;
  
      int curr_region_idx = 0;
      while (curr_region_idx < num_regions)
      {
          // check "new" range
          if (!pAcc->addrStartOfRange(region_array[curr_region_idx].start_address))
          {
              // ensure adds cleanly
              if (!pAcc->AddOffsetRange(region_array[curr_region_idx].start_address,
                  region_array[curr_region_idx].region_size,
                  region_array[curr_region_idx].file_offset))
                  return OCSD_ERR_INVALID_PARAM_VAL;  // otherwise bail out
          }
          curr_region_idx++;
      }
      return OCSD_OK;
  }
  ocsd_err_t DecodeTree::initCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, 
      const ocsd_mem_space_acc_t mem_space, void *p_cb_func, bool IDfn, const void *p_context)
  {
      if(!hasMemAccMapper())
          return OCSD_ERR_NOT_INIT;
  
      if(p_cb_func == 0)
          return OCSD_ERR_INVALID_PARAM_VAL;
  
      TrcMemAccessorBase *p_accessor;
      ocsd_err_t err = TrcMemAccFactory::CreateCBAccessor(&p_accessor, st_address, en_address, mem_space);
      if(err == OCSD_OK)
      {
          TrcMemAccCB *pCBAcc = dynamic_cast<TrcMemAccCB *>(p_accessor);
          if(pCBAcc)
          {
              if (IDfn)
                  pCBAcc->setCBIDIfFn((Fn_MemAccID_CB)p_cb_func, p_context);
              else
                  pCBAcc->setCBIfFn((Fn_MemAcc_CB)p_cb_func, p_context);
  
              err = m_default_mapper->AddAccessor(p_accessor,0);
          }
          else
              err = OCSD_ERR_MEM;    // wrong type of object - treat as mem error
  
          if(err != OCSD_OK)
              TrcMemAccFactory::DestroyAccessor(p_accessor);
      }
      return err;
  }
  
  ocsd_err_t DecodeTree::addCallbackMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAcc_CB p_cb_func, const void *p_context)
  {
      return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, false, p_context);
  }
  
  ocsd_err_t DecodeTree::addCallbackIDMemAcc(const ocsd_vaddr_t st_address, const ocsd_vaddr_t en_address, const ocsd_mem_space_acc_t mem_space, Fn_MemAccID_CB p_cb_func, const void *p_context)
  {
      return initCallbackMemAcc(st_address, en_address, mem_space, (void *)p_cb_func, true, p_context);
  }
  
  ocsd_err_t DecodeTree::removeMemAccByAddress(const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space)
  {
      if(!hasMemAccMapper())
          return OCSD_ERR_NOT_INIT;
      return m_default_mapper->RemoveAccessorByAddress(address,mem_space,0);
  }
  
  ocsd_err_t DecodeTree::createDecoder(const std::string &decoderName, const int createFlags, const CSConfig *pConfig)
  {
      ocsd_err_t err = OCSD_OK;
      IDecoderMngr *pDecoderMngr = 0;
      TraceComponent *pTraceComp = 0;
      int crtFlags = createFlags;
  
      uint8_t CSID = 0;   // default for single stream decoder (no deformatter) - we ignore the ID
      if(usingFormatter())
      {
          CSID = pConfig->getTraceID();
          crtFlags |= OCSD_CREATE_FLG_INST_ID;
      }
  
      // create the decode element to attach to the channel.
      if((err = createDecodeElement(CSID)) != OCSD_OK)
          return err;
  
      // get the libary decoder register.
      OcsdLibDcdRegister * lib_reg = OcsdLibDcdRegister::getDecoderRegister();
      if(lib_reg == 0)
          return OCSD_ERR_NOT_INIT;
  
      // find the named decoder
      if((err = lib_reg->getDecoderMngrByName(decoderName,&pDecoderMngr)) != OCSD_OK)
          return err;
  
      // got the decoder...
      if((err = pDecoderMngr->createDecoder(crtFlags,(int)CSID,pConfig,&pTraceComp)) != OCSD_OK)
          return err;
  
      m_decode_elements[CSID]->SetDecoderElement(decoderName, pDecoderMngr, pTraceComp, true);
  
      // always attach an error logger
      if(err == OCSD_OK)
          err = pDecoderMngr->attachErrorLogger(pTraceComp,DecodeTree::s_i_error_logger);
  
      // if we created a packet decoder it may need additional components.
      if(crtFlags &  OCSD_CREATE_FLG_FULL_DECODER)
      {
          if(m_i_instr_decode && (err == OCSD_OK))
              err = pDecoderMngr->attachInstrDecoder(pTraceComp,m_i_instr_decode);
          
          if(err == OCSD_ERR_DCD_INTERFACE_UNUSED)    // ignore if instruction decoder refused
              err = OCSD_OK;
  
          if(m_i_mem_access && (err == OCSD_OK))
              err = pDecoderMngr->attachMemAccessor(pTraceComp,m_i_mem_access);
  
          if(err == OCSD_ERR_DCD_INTERFACE_UNUSED)    // ignore if mem accessor refused
              err = OCSD_OK;
  
          if( m_i_gen_elem_out && (err == OCSD_OK))
              err = pDecoderMngr->attachOutputSink(pTraceComp,m_i_gen_elem_out);
      }
  
      // finally attach the packet processor input to the demux output channel
      if(err == OCSD_OK)
      {
          ITrcDataIn *pDataIn = 0;
          if((err = pDecoderMngr->getDataInputI(pTraceComp,&pDataIn)) == OCSD_OK)
          {
              // got the interface -> attach to demux, or direct to input of decode tree
              if(usingFormatter())
                  err = m_frame_deformatter_root->getIDStreamAttachPt(CSID)->attach(pDataIn);
              else
                  m_i_decoder_root = pDataIn;
          }
      }
  
      if(err != OCSD_OK)
      {
          destroyDecodeElement(CSID); // will destroy decoder as well.       
      }
      return err;
  }
  
  ocsd_err_t DecodeTree::removeDecoder(const uint8_t CSID)
  {
      ocsd_err_t err = OCSD_OK;
      uint8_t localID = CSID;
      if(!usingFormatter())
          localID = 0;
  
      if(usingFormatter() && !OCSD_IS_VALID_CS_SRC_ID(CSID))
          err = OCSD_ERR_INVALID_ID;
      else
      {
          destroyDecodeElement(localID);
      }
      return err;
  }
  
  DecodeTreeElement * DecodeTree::getDecoderElement(const uint8_t CSID) const
  {
      DecodeTreeElement *ret_elem = 0;
      if(usingFormatter() && OCSD_IS_VALID_CS_SRC_ID(CSID))
      {
          ret_elem = m_decode_elements[CSID]; 
      }
      else
          ret_elem = m_decode_elements[0];    // ID 0 is used if single leaf tree.
      return ret_elem;
  }
  
  DecodeTreeElement *DecodeTree::getFirstElement(uint8_t &elemID)
  {
      m_decode_elem_iter = 0;
      return getNextElement(elemID);
  }
  
  DecodeTreeElement *DecodeTree::getNextElement(uint8_t &elemID)
  {
      DecodeTreeElement *ret_elem = 0;
  
      if(m_decode_elem_iter < 0x80)
      {
          // find a none zero entry or end of range
          while((m_decode_elements[m_decode_elem_iter] == 0) && (m_decode_elem_iter < 0x80))
              m_decode_elem_iter++;
  
          // return entry unless end of range
          if(m_decode_elem_iter < 0x80)
          {
              ret_elem = m_decode_elements[m_decode_elem_iter];
              elemID = m_decode_elem_iter;
              m_decode_elem_iter++;
          }
      }
      return ret_elem;
  }
  
  bool DecodeTree::initialise(const ocsd_dcd_tree_src_t type, uint32_t formatterCfgFlags)
  {
      bool initOK = true;
      m_dcd_tree_type = type;
      if(type ==  OCSD_TRC_SRC_FRAME_FORMATTED)
      {
          // frame formatted - we want to create the deformatter and hook it up
          m_frame_deformatter_root = new (std::nothrow) TraceFormatterFrameDecoder();
          if(m_frame_deformatter_root)
          {
              m_frame_deformatter_root->Configure(formatterCfgFlags);
              m_frame_deformatter_root->getErrLogAttachPt()->attach(DecodeTree::s_i_error_logger);
              m_i_decoder_root = dynamic_cast<ITrcDataIn*>(m_frame_deformatter_root);
          }
          else 
              initOK = false;
      }
      return initOK;
  }
  
  void DecodeTree::setSingleRoot(TrcPktProcI *pComp)
  {
      m_i_decoder_root = static_cast<ITrcDataIn*>(pComp);
  }
  
  ocsd_err_t DecodeTree::createDecodeElement(const uint8_t CSID)
  {
      ocsd_err_t err = OCSD_ERR_INVALID_ID;
      if(CSID < 0x80)
      {
          if(m_decode_elements[CSID] == 0)
          {
              m_decode_elements[CSID] = new (std::nothrow) DecodeTreeElement();
              if(m_decode_elements[CSID] == 0)
                  err = OCSD_ERR_MEM;
              else 
                  err = OCSD_OK;
          }
          else
              err = OCSD_ERR_ATTACH_TOO_MANY;
      }
      return err;
  }
  
  void DecodeTree::destroyDecodeElement(const uint8_t CSID)
  {
      if(CSID < 0x80)
      {
          if(m_decode_elements[CSID] != 0)
          {
              m_decode_elements[CSID]->DestroyElem();
              delete m_decode_elements[CSID];
              m_decode_elements[CSID] = 0;
          }
      }
  }
  
  ocsd_err_t DecodeTree::setIDFilter(std::vector<uint8_t> &ids)
  {
      ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER;
      if(usingFormatter())
      {
          err = m_frame_deformatter_root->OutputFilterAllIDs(false);
          if(err == OCSD_OK)
              err = m_frame_deformatter_root->OutputFilterIDs(ids,true);
      }
      return err;
  }
  
  ocsd_err_t DecodeTree::clearIDFilter()
  {
      ocsd_err_t err = OCSD_ERR_DCDT_NO_FORMATTER;
      if(usingFormatter())
      {
          err = m_frame_deformatter_root->OutputFilterAllIDs(true);
      }
      return err;
  }
  
  /** add a protocol packet printer */
  ocsd_err_t DecodeTree::addPacketPrinter(uint8_t CSID, bool bMonitor, ItemPrinter **ppPrinter)
  {
      ocsd_err_t err = OCSD_ERR_INVALID_PARAM_VAL;
      DecodeTreeElement *pElement = getDecoderElement(CSID);
      if (pElement)
      {
          ocsd_trace_protocol_t protocol = pElement->getProtocol();
          ItemPrinter *pPrinter;
  
          pPrinter = PktPrinterFact::createProtocolPrinter(getPrinterList(), protocol, CSID);        
          if (pPrinter)
          {
              pPrinter->setMessageLogger(getCurrentErrorLogI()->getOutputLogger());
              switch (protocol)
              {
              case  OCSD_PROTOCOL_ETMV4I:
              {
                  PacketPrinter<EtmV4ITrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV4ITrcPacket> *>(pPrinter);
                  if (bMonitor)
                      err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV4ITrcPacket> *)pTPrinter);
                  else
                      err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV4ITrcPacket> *)pTPrinter);
              }
              break;
  
              case  OCSD_PROTOCOL_ETMV3:
              {
                  PacketPrinter<EtmV3TrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<EtmV3TrcPacket> *>(pPrinter);
                  if (bMonitor)
                      err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<EtmV3TrcPacket> *)pTPrinter);
                  else
                      err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<EtmV3TrcPacket> *)pTPrinter);
              }
              break;
  
              case  OCSD_PROTOCOL_PTM:
              {
                  PacketPrinter<PtmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<PtmTrcPacket> *>(pPrinter);
                  if (bMonitor)
                      err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<PtmTrcPacket> *)pTPrinter);
                  else
                      err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<PtmTrcPacket> *)pTPrinter);
              }
              break;
  
              case OCSD_PROTOCOL_STM:
              {
                  PacketPrinter<StmTrcPacket> *pTPrinter = dynamic_cast<PacketPrinter<StmTrcPacket> *>(pPrinter);
                  if (bMonitor)
                      err = pElement->getDecoderMngr()->attachPktMonitor(pElement->getDecoderHandle(), (IPktRawDataMon<StmTrcPacket> *)pTPrinter);
                  else
                      err = pElement->getDecoderMngr()->attachPktSink(pElement->getDecoderHandle(), (IPktDataIn<StmTrcPacket> *)pTPrinter);
              }
              break;
  
              default:
                  err = OCSD_ERR_NO_PROTOCOL;
                  break;
              }
  
              if (err == OCSD_OK)
              {
                  if (ppPrinter)
                      *ppPrinter = pPrinter;
              }
              else
                  PktPrinterFact::destroyPrinter(getPrinterList(), pPrinter);
          }
      }
      return err;
  }
  
  /** add a raw frame printer */
  ocsd_err_t DecodeTree::addRawFramePrinter(RawFramePrinter **ppPrinter, uint32_t flags)
  {
      ocsd_err_t err = OCSD_ERR_MEM;
      RawFramePrinter *pPrinter = PktPrinterFact::createRawFramePrinter(getPrinterList());
      if (pPrinter)
      {
          pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger()));
          TraceFormatterFrameDecoder *pFrameDecoder = getFrameDeformatter();
          uint32_t cfgFlags = pFrameDecoder->getConfigFlags();
          cfgFlags |= ((uint32_t)flags & (OCSD_DFRMTR_PACKED_RAW_OUT | OCSD_DFRMTR_UNPACKED_RAW_OUT));
          pFrameDecoder->Configure(cfgFlags);
          err = pFrameDecoder->getTrcRawFrameAttachPt()->attach(pPrinter);        
          if (ppPrinter && (err==OCSD_OK))
              *ppPrinter = pPrinter;
      }
      return err;
  }
  
  /** add a generic element output printer */
  ocsd_err_t DecodeTree::addGenElemPrinter(TrcGenericElementPrinter **ppPrinter)
  {
      ocsd_err_t err = OCSD_ERR_MEM;
      TrcGenericElementPrinter *pPrinter = PktPrinterFact::createGenElemPrinter(getPrinterList());
      if (pPrinter)
      {
          pPrinter->setMessageLogger((DecodeTree::getCurrentErrorLogI()->getOutputLogger()));
          setGenTraceElemOutI(pPrinter);
          err = OCSD_OK;
          if (ppPrinter)
              *ppPrinter = pPrinter;
      }
      return err;
  
  }
  
  /* End of File ocsd_dcd_tree.cpp */
  