| /* |
| * \file trc_frame_deformatter.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 <cstring> |
| #include <new> |
| |
| #include "common/trc_frame_deformatter.h" |
| #include "trc_frame_deformatter_impl.h" |
| |
| /***************************************************************/ |
| /* Implementation */ |
| /***************************************************************/ |
| |
| #ifdef __GNUC__ |
| // G++ doesn't like the ## pasting |
| #define DEFORMATTER_NAME "DFMT_CSFRAMES" |
| #else |
| // VC is fine |
| #define DEFORMATTER_NAME OCSD_CMPNAME_PREFIX_FRAMEDEFORMATTER##"_CSFRAMES" |
| #endif |
| |
| |
| static const uint32_t FSYNC_PATTERN = 0x7FFFFFFF; // LE host pattern for FSYNC |
| static const uint16_t FSYNC_START = 0xFFFF; |
| static const uint16_t FSYNC_END = 0x7FFF; |
| static const uint16_t HSYNC_PATTERN = 0x7FFF; // LE host pattern for HSYNC |
| |
| |
| TraceFmtDcdImpl::TraceFmtDcdImpl() : TraceComponent(DEFORMATTER_NAME), |
| m_cfgFlags(0), |
| m_force_sync_idx(0), |
| m_use_force_sync(false), |
| m_alignment(16), // assume frame aligned data as default. |
| m_b_output_packed_raw(false), |
| m_b_output_unpacked_raw(false), |
| m_pStatsBlock(0) |
| |
| { |
| resetStateParams(); |
| setRawChanFilterAll(true); |
| } |
| |
| TraceFmtDcdImpl::TraceFmtDcdImpl(int instNum) : TraceComponent(DEFORMATTER_NAME, instNum), |
| m_cfgFlags(0), |
| m_force_sync_idx(0), |
| m_use_force_sync(false), |
| m_alignment(16) |
| { |
| resetStateParams(); |
| setRawChanFilterAll(true); |
| } |
| |
| TraceFmtDcdImpl::~TraceFmtDcdImpl() |
| { |
| } |
| |
| ocsd_datapath_resp_t TraceFmtDcdImpl::TraceDataIn( |
| const ocsd_datapath_op_t op, |
| const ocsd_trc_index_t index, |
| const uint32_t dataBlockSize, |
| const uint8_t *pDataBlock, |
| uint32_t *numBytesProcessed) |
| { |
| ocsd_datapath_resp_t resp = OCSD_RESP_FATAL_INVALID_OP; |
| InitCollateDataPathResp(); |
| |
| m_b_output_packed_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_PACKED_RAW_OUT) != 0); |
| m_b_output_unpacked_raw = m_RawTraceFrame.num_attached() && ((m_cfgFlags & OCSD_DFRMTR_UNPACKED_RAW_OUT) != 0); |
| |
| switch(op) |
| { |
| case OCSD_OP_RESET: |
| resp = Reset(); |
| break; |
| |
| case OCSD_OP_FLUSH: |
| resp = Flush(); |
| break; |
| |
| case OCSD_OP_EOT: |
| // local 'flush' here? |
| // pass on EOT to connected ID streams |
| resp = executeNoneDataOpAllIDs(OCSD_OP_EOT); |
| break; |
| |
| case OCSD_OP_DATA: |
| if((dataBlockSize <= 0) || ( pDataBlock == 0) || (numBytesProcessed == 0)) |
| resp = OCSD_RESP_FATAL_INVALID_PARAM; |
| else |
| resp = processTraceData(index,dataBlockSize, pDataBlock, numBytesProcessed); |
| break; |
| |
| default: |
| break; |
| } |
| |
| return resp; |
| } |
| |
| /* enable / disable ID streams - default as all enabled */ |
| ocsd_err_t TraceFmtDcdImpl::OutputFilterIDs(std::vector<uint8_t> &id_list, bool bEnable) |
| { |
| ocsd_err_t err = OCSD_OK; |
| std::vector<uint8_t>::iterator iter = id_list.begin(); |
| uint8_t id = 0; |
| |
| while((iter < id_list.end()) && (err == OCSD_OK)) |
| { |
| id = *iter; |
| if(id >= 128) |
| err = OCSD_ERR_INVALID_ID; |
| else |
| { |
| m_IDStreams[id].set_enabled(bEnable); |
| m_raw_chan_enable[id] = bEnable; |
| } |
| iter++; |
| } |
| return err; |
| } |
| |
| ocsd_err_t TraceFmtDcdImpl::OutputFilterAllIDs(bool bEnable) |
| { |
| for(uint8_t id = 0; id < 128; id++) |
| { |
| m_IDStreams[id].set_enabled(bEnable); |
| } |
| setRawChanFilterAll(bEnable); |
| return OCSD_OK; |
| } |
| |
| void TraceFmtDcdImpl::setRawChanFilterAll(bool bEnable) |
| { |
| for(int i=0; i<128; i++) |
| { |
| m_raw_chan_enable[i] = bEnable; |
| } |
| } |
| |
| const bool TraceFmtDcdImpl::rawChanEnabled(const uint8_t id) const |
| { |
| if(id < 128) |
| return m_raw_chan_enable[id]; |
| return false; |
| } |
| |
| /* decode control */ |
| ocsd_datapath_resp_t TraceFmtDcdImpl::Reset() |
| { |
| resetStateParams(); |
| InitCollateDataPathResp(); |
| return executeNoneDataOpAllIDs(OCSD_OP_RESET); |
| } |
| |
| ocsd_datapath_resp_t TraceFmtDcdImpl::Flush() |
| { |
| executeNoneDataOpAllIDs(OCSD_OP_FLUSH); // flush any upstream data. |
| if(dataPathCont()) |
| outputFrame(); // try to flush any partial frame data remaining |
| return highestDataPathResp(); |
| } |
| |
| ocsd_datapath_resp_t TraceFmtDcdImpl::executeNoneDataOpAllIDs(ocsd_datapath_op_t op, |
| const ocsd_trc_index_t index /* = 0*/) |
| { |
| ITrcDataIn *pTrcComp = 0; |
| for(uint8_t id = 0; id < 128; id++) |
| { |
| if(m_IDStreams[id].num_attached()) |
| { |
| pTrcComp = m_IDStreams[id].first(); |
| while(pTrcComp) |
| { |
| CollateDataPathResp(pTrcComp->TraceDataIn(op,index,0,0,0)); |
| pTrcComp = m_IDStreams[id].next(); |
| } |
| } |
| } |
| |
| if( m_RawTraceFrame.num_attached()) |
| { |
| if(m_RawTraceFrame.first()) |
| m_RawTraceFrame.first()->TraceRawFrameIn(op,0,OCSD_FRM_NONE,0,0,0); |
| } |
| return highestDataPathResp(); |
| } |
| |
| void TraceFmtDcdImpl::outputRawMonBytes(const ocsd_datapath_op_t op, |
| const ocsd_trc_index_t index, |
| const ocsd_rawframe_elem_t frame_element, |
| const int dataBlockSize, |
| const uint8_t *pDataBlock, |
| const uint8_t traceID) |
| { |
| if( m_RawTraceFrame.num_attached()) |
| { |
| if(m_RawTraceFrame.first()) |
| m_RawTraceFrame.first()->TraceRawFrameIn(op,index,frame_element,dataBlockSize, pDataBlock,traceID); |
| } |
| } |
| |
| void TraceFmtDcdImpl::CollateDataPathResp(const ocsd_datapath_resp_t resp) |
| { |
| // simple most severe error across multiple IDs. |
| if(resp > m_highestResp) m_highestResp = resp; |
| } |
| |
| ocsd_datapath_resp_t TraceFmtDcdImpl::processTraceData( |
| const ocsd_trc_index_t index, |
| const uint32_t dataBlockSize, |
| const uint8_t *pDataBlock, |
| uint32_t *numBytesProcessed |
| ) |
| { |
| try { |
| |
| if(!m_first_data) // is this the initial data block? |
| { |
| m_trc_curr_idx = index; |
| } |
| else |
| { |
| if(m_trc_curr_idx != index) // none continuous trace data - throw an error. |
| throw ocsdError(OCSD_ERR_SEV_ERROR,OCSD_ERR_DFMTR_NOTCONTTRACE,index); |
| } |
| |
| // record the incoming block for extraction routines to use. |
| m_in_block_base = pDataBlock; |
| m_in_block_size = dataBlockSize; |
| m_in_block_processed = 0; |
| |
| if(dataBlockSize % m_alignment) // must be correctly aligned data |
| { |
| ocsdError err(OCSD_ERR_SEV_ERROR, OCSD_ERR_INVALID_PARAM_VAL); |
| char msg_buffer[64]; |
| sprintf(msg_buffer,"Input block incorrect size, must be %d byte multiple", m_alignment); |
| err.setMessage(msg_buffer); |
| throw ocsdError(&err); |
| } |
| |
| // processing loop... |
| if(checkForSync()) |
| { |
| bool bProcessing = true; |
| while(bProcessing) |
| { |
| bProcessing = extractFrame(); // will stop on end of input data. |
| if(bProcessing) |
| bProcessing = unpackFrame(); |
| if(bProcessing) |
| bProcessing = outputFrame(); // will stop on data path halt. |
| } |
| } |
| } |
| catch(const ocsdError &err) { |
| LogError(err); |
| CollateDataPathResp(OCSD_RESP_FATAL_INVALID_DATA); |
| } |
| catch(...) { |
| LogError(ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_FAIL)); |
| CollateDataPathResp(OCSD_RESP_FATAL_SYS_ERR); |
| } |
| |
| if(!m_first_data) |
| m_first_data = true; |
| |
| // update the outputs. |
| *numBytesProcessed = m_in_block_processed; |
| |
| return highestDataPathResp(); |
| } |
| |
| ocsd_err_t TraceFmtDcdImpl::DecodeConfigure(uint32_t flags) |
| { |
| const char *pszErrMsg = ""; |
| ocsd_err_t err = OCSD_OK; |
| |
| if((flags & ~OCSD_DFRMTR_VALID_MASK) != 0) |
| { |
| err = OCSD_ERR_INVALID_PARAM_VAL; |
| pszErrMsg = "Unknown Config Flags"; |
| } |
| |
| if((flags & OCSD_DFRMTR_VALID_MASK) == 0) |
| { |
| err = OCSD_ERR_INVALID_PARAM_VAL; |
| pszErrMsg = "No Config Flags Set"; |
| } |
| |
| if((flags & (OCSD_DFRMTR_HAS_FSYNCS | OCSD_DFRMTR_HAS_HSYNCS)) && |
| (flags & OCSD_DFRMTR_FRAME_MEM_ALIGN) |
| ) |
| { |
| err = OCSD_ERR_INVALID_PARAM_VAL; |
| pszErrMsg = "Invalid Config Flag Combination Set"; |
| } |
| |
| if(err != OCSD_OK) |
| { |
| ocsdError errObj(OCSD_ERR_SEV_ERROR,OCSD_ERR_INVALID_PARAM_VAL); |
| errObj.setMessage(pszErrMsg); |
| LogError(errObj); |
| } |
| else |
| { |
| // alightment is the multiple of bytes the buffer size must be. |
| m_cfgFlags = flags; |
| |
| // using memory aligned buffers, the formatter always outputs 16 byte frames so enforce |
| // this on the input |
| m_alignment = 16; |
| // if we have HSYNCS then always align to 2 byte buffers |
| if(flags & OCSD_DFRMTR_HAS_HSYNCS) |
| m_alignment = 2; |
| // otherwise FSYNCS only can have 4 byte aligned buffers. |
| else if(flags & OCSD_DFRMTR_HAS_FSYNCS) |
| m_alignment = 4; |
| } |
| return err; |
| } |
| |
| void TraceFmtDcdImpl::resetStateParams() |
| { |
| // overall dynamic state - intra frame |
| m_trc_curr_idx = OCSD_BAD_TRC_INDEX; /* source index of current trace data */ |
| m_frame_synced = false; |
| m_first_data = false; |
| m_curr_src_ID = OCSD_BAD_CS_SRC_ID; |
| |
| // current frame processing |
| m_ex_frm_n_bytes = 0; |
| m_b_fsync_start_eob = false; |
| m_b_fsync_chk_eo_buf = false; |
| m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX; |
| } |
| |
| ocsd_err_t TraceFmtDcdImpl::SetForcedSyncIndex(ocsd_trc_index_t index, bool bSet) |
| { |
| m_use_force_sync = bSet; |
| m_force_sync_idx = index; |
| return OCSD_OK; |
| } |
| |
| bool TraceFmtDcdImpl::checkForSync() |
| { |
| // we can sync on:- |
| // 16 byte alignment - standard input buffers such as ETB |
| // FSYNC packets in the stream |
| // forced index programmed into the object. |
| uint32_t unsynced_bytes = 0; |
| |
| if(!m_frame_synced) |
| { |
| if(m_use_force_sync) |
| { |
| // is the force sync point in this block? |
| if((m_force_sync_idx >= m_trc_curr_idx) && (m_force_sync_idx < (m_trc_curr_idx + m_in_block_size))) |
| { |
| unsynced_bytes = m_force_sync_idx - m_trc_curr_idx; |
| m_frame_synced = true; |
| } |
| else |
| { |
| unsynced_bytes = m_in_block_size; |
| } |
| } |
| else if( m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) // memory aligned data |
| { |
| unsynced_bytes = findfirstFSync(); |
| |
| } |
| else |
| { |
| // OCSD_DFRMTR_FRAME_MEM_ALIGN - this has guaranteed 16 byte frame size and alignment. |
| m_frame_synced = true; |
| } |
| |
| if(unsynced_bytes) |
| { |
| m_in_block_processed = unsynced_bytes; |
| m_trc_curr_idx += unsynced_bytes; |
| } |
| } |
| |
| // continue processing if synced or potentially synced |
| return (m_frame_synced || m_b_fsync_chk_eo_buf); |
| } |
| |
| uint32_t TraceFmtDcdImpl::findfirstFSync() |
| { |
| uint32_t processed = 0, remain = m_in_block_size; |
| const uint8_t *dataPtr = m_in_block_base; |
| |
| // last time had potential fsync at end of buffer |
| if (m_b_fsync_chk_eo_buf == true) |
| { |
| if (*((uint16_t*)(dataPtr)) == FSYNC_END) |
| { |
| m_frame_synced = true; |
| } |
| // return to let frame processor deal with fsync / error |
| m_b_fsync_chk_eo_buf = false; |
| return 0; |
| } |
| |
| while (processed < (remain - 2)) |
| { |
| if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) |
| { |
| m_frame_synced = true; |
| break; |
| } |
| processed += 2; |
| dataPtr += 2; |
| remain -= 2; |
| } |
| |
| // HSYNC aligned 2 byte, allows small blocks or start of fsync at EOB |
| if (!m_frame_synced && (remain == 2)) |
| { |
| if (*((uint16_t*)(dataPtr)) == FSYNC_START) |
| m_b_fsync_chk_eo_buf = true; |
| } |
| |
| return processed; |
| } |
| |
| ocsd_err_t TraceFmtDcdImpl::checkForResetFSyncPatterns(uint32_t &f_sync_bytes) |
| { |
| bool check_for_fsync = true; |
| int num_fsyncs = 0; |
| uint32_t bytes_processed = m_in_block_processed; |
| const uint8_t *dataPtr = m_in_block_base + bytes_processed; |
| ocsd_err_t err = OCSD_OK; |
| |
| while (check_for_fsync && (bytes_processed < m_in_block_size)) |
| { |
| // look for consecutive fsyncs as padding or for reset downstream - both cases will reset downstream.... |
| if (*((uint32_t *)(dataPtr)) == FSYNC_PATTERN) |
| { |
| dataPtr += sizeof(uint32_t); |
| num_fsyncs++; |
| bytes_processed += sizeof(uint32_t); |
| } |
| else |
| check_for_fsync = false; |
| } |
| |
| if (num_fsyncs) |
| { |
| if ((num_fsyncs % 4) == 0) |
| { |
| // reset the upstream decoders |
| executeNoneDataOpAllIDs(OCSD_OP_RESET,m_trc_curr_idx); |
| |
| // reset the intra frame parameters |
| m_curr_src_ID = OCSD_BAD_CS_SRC_ID; |
| m_ex_frm_n_bytes = 0; |
| m_trc_curr_idx_sof = OCSD_BAD_TRC_INDEX; |
| } |
| else |
| { |
| err = OCSD_ERR_DFMTR_BAD_FHSYNC; |
| } |
| } |
| f_sync_bytes += num_fsyncs * 4; |
| return err; |
| } |
| |
| /* Extract a single frame from the input buffer. */ |
| bool TraceFmtDcdImpl::extractFrame() |
| { |
| ocsd_err_t err; |
| uint32_t f_sync_bytes = 0; // skipped f sync bytes |
| uint32_t h_sync_bytes = 0; // skipped h sync bytes |
| uint32_t ex_bytes = 0; // extracted this pass (may be filling out part frame) |
| uint32_t buf_left = m_in_block_size - m_in_block_processed; // bytes remaining in buffer this pass. |
| |
| // last call was end of input block - but carried on to process full frame. |
| // exit early here. |
| if (!buf_left) |
| return false; |
| |
| // memory aligned input data is forced to be always multiples of 16 byte frames, aligned to start. |
| if( m_cfgFlags & OCSD_DFRMTR_FRAME_MEM_ALIGN) |
| { |
| // some linux drivers (e.g. for perf) will insert FSYNCS to pad or differentiate |
| // between blocks of aligned data, always in frame aligned complete 16 byte frames. |
| // we need to skip past these frames, resetting as we go. |
| if (m_cfgFlags & OCSD_DFRMTR_RESET_ON_4X_FSYNC) |
| { |
| err = checkForResetFSyncPatterns(f_sync_bytes); |
| |
| /* in this case the FSYNC pattern is output on both packed and unpacked cases */ |
| if (f_sync_bytes && (m_b_output_packed_raw || m_b_output_unpacked_raw)) |
| { |
| outputRawMonBytes(OCSD_OP_DATA, |
| m_trc_curr_idx, |
| OCSD_FRM_FSYNC, |
| f_sync_bytes, |
| m_in_block_base + m_in_block_processed, |
| 0); |
| } |
| |
| // throw processing error, none frame size block of fsyncs |
| if (err) |
| throw ocsdError(OCSD_ERR_SEV_ERROR, err, m_trc_curr_idx, "Incorrect FSYNC frame reset pattern"); |
| |
| buf_left -= f_sync_bytes; |
| } |
| |
| if (buf_left) |
| { |
| // always a complete frame - the input data has to be 16 byte multiple alignment. |
| m_ex_frm_n_bytes = OCSD_DFRMTR_FRAME_SIZE; |
| memcpy(m_ex_frm_data, m_in_block_base + m_in_block_processed + f_sync_bytes, m_ex_frm_n_bytes); |
| m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; |
| ex_bytes = OCSD_DFRMTR_FRAME_SIZE; |
| } |
| } |
| else |
| { |
| // extract data accounting for frame syncs and hsyncs if present. |
| // we know we are aligned at this point - could be FSYNC or HSYNCs here. |
| // HSYNC present, library forces input to be aligned 2 byte multiples |
| // FSYNC - w/o HSYNCs, forces input to be aligned 4 byte multiples. |
| |
| // check what we a looking for |
| bool hasFSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_FSYNCS) == OCSD_DFRMTR_HAS_FSYNCS); |
| bool hasHSyncs = ((m_cfgFlags & OCSD_DFRMTR_HAS_HSYNCS) == OCSD_DFRMTR_HAS_HSYNCS); |
| |
| const uint8_t* dataPtr = m_in_block_base + m_in_block_processed; |
| uint16_t data_pair_val; |
| |
| // can have FSYNCS at start of frame (in middle is an error). |
| if (hasFSyncs && (m_ex_frm_n_bytes == 0)) |
| { |
| // was there an fsync start at the end of the last buffer? |
| if (m_b_fsync_start_eob) { |
| if (*(uint16_t*)(dataPtr) != FSYNC_END) |
| { |
| // this means 0xFFFF followed by something else - invalid ID + ???? |
| throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC pattern before frame or invalid ID.(0x7F)"); |
| } |
| else |
| { |
| f_sync_bytes += 2; |
| buf_left -= 2; |
| dataPtr += 2; |
| } |
| m_b_fsync_start_eob = false; |
| m_b_fsync_chk_eo_buf = false; |
| } |
| |
| // regular fsync checks |
| while ((buf_left >= 4) && (*((uint32_t*)(dataPtr)) == FSYNC_PATTERN)) |
| { |
| f_sync_bytes += 4; |
| dataPtr += 4; |
| buf_left -= 4; |
| } |
| |
| // handle possible part fsync at the end of a buffer |
| if (buf_left == 2) |
| { |
| if (*(uint16_t*)(dataPtr) == FSYNC_START) |
| { |
| f_sync_bytes += 2; |
| buf_left -= 2; |
| dataPtr += 2; |
| m_b_fsync_start_eob = true; |
| } |
| } |
| } |
| |
| // process remaining data in pairs of bytes |
| while ((m_ex_frm_n_bytes < OCSD_DFRMTR_FRAME_SIZE) && buf_left) |
| { |
| // mark start of frame after FSyncs |
| if (m_ex_frm_n_bytes == 0) |
| m_trc_curr_idx_sof = m_trc_curr_idx + f_sync_bytes; |
| |
| m_ex_frm_data[m_ex_frm_n_bytes] = dataPtr[0]; |
| m_ex_frm_data[m_ex_frm_n_bytes + 1] = dataPtr[1]; |
| |
| data_pair_val = *((uint16_t*)(dataPtr)); |
| |
| // check pair is not HSYNC |
| if (data_pair_val == HSYNC_PATTERN) |
| { |
| if (hasHSyncs) |
| { |
| h_sync_bytes += 2; |
| } |
| else |
| { |
| // throw illegal HSYNC error. |
| m_trc_curr_idx += ex_bytes + f_sync_bytes + h_sync_bytes; |
| throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad HSYNC in frame."); |
| } |
| } |
| // can't have a start of FSYNC here / illegal trace ID |
| else if (data_pair_val == FSYNC_START) |
| { |
| m_trc_curr_idx += ex_bytes + f_sync_bytes + h_sync_bytes; |
| throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_DFMTR_BAD_FHSYNC, m_trc_curr_idx, "Bad FSYNC start in frame or invalid ID (0x7F)."); |
| } |
| else |
| { |
| m_ex_frm_n_bytes += 2; |
| ex_bytes += 2; |
| } |
| |
| buf_left -= 2; |
| dataPtr += 2; |
| } |
| } |
| |
| // total bytes processed this pass |
| uint32_t total_processed = ex_bytes + f_sync_bytes + h_sync_bytes; |
| |
| // output raw data on raw frame channel - packed raw. |
| if (((m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE) || (buf_left == 0)) && m_b_output_packed_raw) |
| { |
| outputRawMonBytes( OCSD_OP_DATA, |
| m_trc_curr_idx, |
| OCSD_FRM_PACKED, |
| total_processed, |
| m_in_block_base+m_in_block_processed, |
| 0); |
| } |
| |
| // update the processed count for the buffer |
| m_in_block_processed += total_processed; |
| |
| // update index past the processed data |
| m_trc_curr_idx += total_processed; |
| |
| // update any none trace data byte stats |
| addToFrameStats((uint64_t)(f_sync_bytes + h_sync_bytes)); |
| |
| // if we are exiting with a full frame then signal processing to continue |
| return (bool)(m_ex_frm_n_bytes == OCSD_DFRMTR_FRAME_SIZE); |
| } |
| |
| bool TraceFmtDcdImpl::unpackFrame() |
| { |
| // unpack cannot fail as never called on incomplete frame. |
| uint8_t frameFlagBit = 0x1; |
| uint8_t newSrcID = OCSD_BAD_CS_SRC_ID; |
| bool PrevIDandIDChange = false; |
| uint64_t noneDataBytes = 0; |
| |
| // init output processing |
| m_out_data_idx = 0; |
| m_out_processed = 0; |
| |
| // set up first out data packet... |
| m_out_data[m_out_data_idx].id = m_curr_src_ID; |
| m_out_data[m_out_data_idx].valid = 0; |
| m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof; |
| m_out_data[m_out_data_idx].used = 0; |
| |
| // work on byte pairs - bytes 0 - 13. |
| for(int i = 0; i < 14; i+=2) |
| { |
| PrevIDandIDChange = false; |
| |
| // it's an ID + data |
| if(m_ex_frm_data[i] & 0x1) |
| { |
| newSrcID = (m_ex_frm_data[i] >> 1) & 0x7f; |
| if(newSrcID != m_curr_src_ID) // ID change |
| { |
| PrevIDandIDChange = ((frameFlagBit & m_ex_frm_data[15]) != 0); |
| |
| // following byte for old id? |
| if(PrevIDandIDChange) |
| // 2nd byte always data |
| m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1]; |
| |
| // change ID |
| m_curr_src_ID = newSrcID; |
| |
| // if we already have data in this buffer |
| if(m_out_data[m_out_data_idx].valid > 0) |
| { |
| m_out_data_idx++; // move to next buffer |
| m_out_data[m_out_data_idx].valid = 0; |
| m_out_data[m_out_data_idx].used = 0; |
| m_out_data[m_out_data_idx].index = m_trc_curr_idx_sof + i; |
| } |
| |
| // set new ID on buffer |
| m_out_data[m_out_data_idx].id = m_curr_src_ID; |
| |
| /// TBD - ID indexing in here. |
| } |
| noneDataBytes++; |
| } |
| else |
| // it's just data |
| { |
| m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0); |
| } |
| |
| // 2nd byte always data |
| if(!PrevIDandIDChange) // output only if we didn't for an ID change + prev ID. |
| m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[i+1]; |
| |
| frameFlagBit <<= 1; |
| } |
| |
| // unpack byte 14; |
| |
| // it's an ID |
| if(m_ex_frm_data[14] & 0x1) |
| { |
| // no matter if change or not, no associated data in byte 15 anyway so just set. |
| m_curr_src_ID = (m_ex_frm_data[14] >> 1) & 0x7f; |
| noneDataBytes++; |
| } |
| // it's data |
| else |
| { |
| m_out_data[m_out_data_idx].data[m_out_data[m_out_data_idx].valid++] = m_ex_frm_data[14] | ((frameFlagBit & m_ex_frm_data[15]) ? 0x1 : 0x0); |
| } |
| m_ex_frm_n_bytes = 0; // mark frame as empty; |
| |
| noneDataBytes++; // byte 15 is always non-data. |
| addToFrameStats(noneDataBytes); // update the non data byte stats. |
| return true; |
| } |
| |
| // output data to channels. |
| bool TraceFmtDcdImpl::outputFrame() |
| { |
| bool cont_processing = true; |
| ITrcDataIn *pDataIn = 0; |
| uint32_t bytes_used; |
| |
| // output each valid ID within the frame - stopping if we get a wait or error |
| while((m_out_processed < (m_out_data_idx + 1)) && cont_processing) |
| { |
| |
| // may have data prior to a valid ID appearing |
| if(m_out_data[m_out_processed].id != OCSD_BAD_CS_SRC_ID) |
| { |
| if((pDataIn = m_IDStreams[m_out_data[m_out_processed].id].first()) != 0) |
| { |
| // log the stuff we are about to put out early so as to make it visible before interpretation |
| // however, don't re-output if only part used first time round. |
| if(m_b_output_unpacked_raw && (m_out_data[m_out_processed].used == 0) && rawChanEnabled( m_out_data[m_out_processed].id)) |
| { |
| outputRawMonBytes( OCSD_OP_DATA, |
| m_out_data[m_out_processed].index, |
| OCSD_FRM_ID_DATA, |
| m_out_data[m_out_processed].valid, |
| m_out_data[m_out_processed].data, |
| m_out_data[m_out_processed].id); |
| } |
| |
| // output to the connected packet process |
| CollateDataPathResp(pDataIn->TraceDataIn(OCSD_OP_DATA, |
| m_out_data[m_out_processed].index + m_out_data[m_out_processed].used, |
| m_out_data[m_out_processed].valid - m_out_data[m_out_processed].used, |
| m_out_data[m_out_processed].data + m_out_data[m_out_processed].used, |
| &bytes_used)); |
| |
| addToIDStats((uint64_t)bytes_used); |
| |
| if(!dataPathCont()) |
| { |
| cont_processing = false; |
| m_out_data[m_out_processed].used += bytes_used; |
| if(m_out_data[m_out_processed].used == m_out_data[m_out_processed].valid) |
| m_out_processed++; // we have used up all this data. |
| } |
| else |
| { |
| m_out_processed++; // we have sent this data; |
| } |
| } |
| else |
| { |
| // optional raw output for debugging / monitor tools |
| if(m_b_output_unpacked_raw && rawChanEnabled( m_out_data[m_out_processed].id)) |
| { |
| outputRawMonBytes( OCSD_OP_DATA, |
| m_out_data[m_out_processed].index, |
| OCSD_FRM_ID_DATA, |
| m_out_data[m_out_processed].valid, |
| m_out_data[m_out_processed].data, |
| m_out_data[m_out_processed].id); |
| } |
| |
| if (isReservedID(m_out_data[m_out_processed].id)) |
| addToReservedIDStats((uint64_t)m_out_data[m_out_processed].valid); |
| else |
| addToNoIDStats((uint64_t)m_out_data[m_out_processed].valid); |
| m_out_processed++; // skip past this data. |
| } |
| } |
| else |
| { |
| // optional raw output for debugging / monitor tools of unknown src ID data |
| if(m_b_output_unpacked_raw) |
| { |
| outputRawMonBytes( OCSD_OP_DATA, |
| m_out_data[m_out_processed].index, |
| OCSD_FRM_ID_DATA, |
| m_out_data[m_out_processed].valid, |
| m_out_data[m_out_processed].data, |
| m_out_data[m_out_processed].id); |
| } |
| addToUnknownIDStats((uint64_t)m_out_data[m_out_processed].valid); |
| m_out_processed++; // skip past this data. |
| } |
| } |
| return cont_processing; |
| } |
| |
| void TraceFmtDcdImpl::addToIDStats(uint64_t val) |
| { |
| if (m_pStatsBlock) |
| m_pStatsBlock->valid_id_bytes += val; |
| } |
| |
| void TraceFmtDcdImpl::addToNoIDStats(uint64_t val) |
| { |
| if (m_pStatsBlock) |
| m_pStatsBlock->no_id_bytes += val; |
| } |
| |
| void TraceFmtDcdImpl::addToFrameStats(uint64_t val) |
| { |
| if (m_pStatsBlock) |
| m_pStatsBlock->frame_bytes += val; |
| } |
| |
| void TraceFmtDcdImpl::addToUnknownIDStats(uint64_t val) |
| { |
| if (m_pStatsBlock) |
| m_pStatsBlock->unknown_id_bytes += val; |
| } |
| |
| void TraceFmtDcdImpl::addToReservedIDStats(uint64_t val) |
| { |
| if (m_pStatsBlock) |
| m_pStatsBlock->reserved_id_bytes += val; |
| } |
| |
| /***************************************************************/ |
| /* interface */ |
| /***************************************************************/ |
| TraceFormatterFrameDecoder::TraceFormatterFrameDecoder() : m_pDecoder(0) |
| { |
| m_instNum = -1; |
| } |
| |
| TraceFormatterFrameDecoder::TraceFormatterFrameDecoder(int instNum) : m_pDecoder(0) |
| { |
| m_instNum = instNum; |
| } |
| |
| TraceFormatterFrameDecoder::~TraceFormatterFrameDecoder() |
| { |
| if(m_pDecoder) |
| { |
| delete m_pDecoder; |
| m_pDecoder = 0; |
| } |
| } |
| |
| /* the data input interface from the reader / source */ |
| ocsd_datapath_resp_t TraceFormatterFrameDecoder::TraceDataIn( const ocsd_datapath_op_t op, |
| const ocsd_trc_index_t index, |
| const uint32_t dataBlockSize, |
| const uint8_t *pDataBlock, |
| uint32_t *numBytesProcessed) |
| { |
| return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->TraceDataIn(op,index,dataBlockSize,pDataBlock,numBytesProcessed); |
| } |
| |
| /* attach a data processor to a stream ID output */ |
| componentAttachPt<ITrcDataIn> *TraceFormatterFrameDecoder::getIDStreamAttachPt(uint8_t ID) |
| { |
| componentAttachPt<ITrcDataIn> *pAttachPt = 0; |
| if((ID < 128) && (m_pDecoder != 0)) |
| pAttachPt = &(m_pDecoder->m_IDStreams[ID]); |
| return pAttachPt; |
| } |
| |
| /* attach a data processor to the raw frame output */ |
| componentAttachPt<ITrcRawFrameIn> *TraceFormatterFrameDecoder::getTrcRawFrameAttachPt() |
| { |
| return (m_pDecoder != 0) ? &m_pDecoder->m_RawTraceFrame : 0; |
| } |
| |
| |
| componentAttachPt<ITrcSrcIndexCreator> *TraceFormatterFrameDecoder::getTrcSrcIndexAttachPt() |
| { |
| return (m_pDecoder != 0) ? &m_pDecoder->m_SrcIndexer : 0; |
| } |
| |
| componentAttachPt<ITraceErrorLog> *TraceFormatterFrameDecoder::getErrLogAttachPt() |
| { |
| return (m_pDecoder != 0) ? m_pDecoder->getErrorLogAttachPt() : 0; |
| } |
| |
| ocsd_err_t TraceFormatterFrameDecoder::Init() |
| { |
| if (!m_pDecoder) |
| { |
| if (m_instNum >= 0) |
| m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(m_instNum); |
| else |
| m_pDecoder = new (std::nothrow) TraceFmtDcdImpl(); |
| if (!m_pDecoder) return OCSD_ERR_MEM; |
| } |
| return OCSD_OK; |
| } |
| |
| /* configuration - set operational mode for incoming stream (has FSYNCS etc) */ |
| ocsd_err_t TraceFormatterFrameDecoder::Configure(uint32_t cfg_flags) |
| { |
| if (!m_pDecoder) |
| return OCSD_ERR_NOT_INIT; |
| return m_pDecoder->DecodeConfigure(cfg_flags); |
| } |
| |
| const uint32_t TraceFormatterFrameDecoder::getConfigFlags() const |
| { |
| uint32_t flags = 0; |
| if(m_pDecoder) |
| flags = m_pDecoder->m_cfgFlags; |
| return flags; |
| } |
| |
| |
| /* enable / disable ID streams - default as all enabled */ |
| ocsd_err_t TraceFormatterFrameDecoder::OutputFilterIDs(std::vector<uint8_t> &id_list, bool bEnable) |
| { |
| return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterIDs(id_list,bEnable); |
| } |
| |
| ocsd_err_t TraceFormatterFrameDecoder::OutputFilterAllIDs(bool bEnable) |
| { |
| return (m_pDecoder == 0) ? OCSD_ERR_NOT_INIT : m_pDecoder->OutputFilterAllIDs(bEnable); |
| } |
| |
| /* decode control */ |
| ocsd_datapath_resp_t TraceFormatterFrameDecoder::Reset() |
| { |
| return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Reset(); |
| } |
| |
| ocsd_datapath_resp_t TraceFormatterFrameDecoder::Flush() |
| { |
| return (m_pDecoder == 0) ? OCSD_RESP_FATAL_NOT_INIT : m_pDecoder->Flush(); |
| } |
| |
| void TraceFormatterFrameDecoder::SetDemuxStatsBlock(ocsd_demux_stats_t *pStatsBlock) |
| { |
| if (m_pDecoder) |
| m_pDecoder->SetDemuxStatsBlock(pStatsBlock); |
| } |
| |
| /* End of File trc_frame_deformatter.cpp */ |