diff --git a/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARA.h b/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARA.h index 97757097758d85b050ce3f1a78373f04c0422f3b..a202a7c4e26195541780509d69e58069a0e5d3b2 100644 --- a/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARA.h +++ b/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARA.h @@ -1,134 +1,182 @@ #ifndef __ADARA_H #define __ADARA_H +// +// SNS ADARA SYSTEM - Common Library +// +// This repository contains the software for the next-generation Data +// Acquisition System (DAS) at the Spallation Neutron Source (SNS) at +// Oak Ridge National Laboratory (ORNL) -- "ADARA". +// +// Copyright (c) 2015, UT-Battelle LLC +// 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 <string> #include <stdexcept> namespace ADARA { -const std::string VERSION = "1.1.0"; +const std::string VERSION = "1.3.0"; +const std::string TAG_NAME = "XXX_TAG_NAME_XXX"; -#define ADARA_PKT_TYPE(type, ver) ((((uint32_t)type) << 8) | (ver)) +#define ADARA_PKT_TYPE(type, ver) ((((uint32_t) type) << 8) | (ver)) namespace PacketType { -enum Enum { - RAW_EVENT_V0 = ADARA_PKT_TYPE(0x0000, 0), - RTDL_V0 = ADARA_PKT_TYPE(0x0001, 0), - SOURCE_LIST_V0 = ADARA_PKT_TYPE(0x0002, 0), - BANKED_EVENT_V0 = ADARA_PKT_TYPE(0x4000, 0), - BEAM_MONITOR_EVENT_V0 = ADARA_PKT_TYPE(0x4001, 0), - PIXEL_MAPPING_V0 = ADARA_PKT_TYPE(0x4002, 0), - RUN_STATUS_V0 = ADARA_PKT_TYPE(0x4003, 0), - RUN_INFO_V0 = ADARA_PKT_TYPE(0x4004, 0), - TRANS_COMPLETE_V0 = ADARA_PKT_TYPE(0x4005, 0), - CLIENT_HELLO_V0 = ADARA_PKT_TYPE(0x4006, 0), - STREAM_ANNOTATION_V0 = ADARA_PKT_TYPE(0x4007, 0), - SYNC_V0 = ADARA_PKT_TYPE(0x4008, 0), - HEARTBEAT_V0 = ADARA_PKT_TYPE(0x4009, 0), - GEOMETRY_V0 = ADARA_PKT_TYPE(0x400A, 0), - BEAMLINE_INFO_V0 = ADARA_PKT_TYPE(0x400B, 0), - DEVICE_DESC_V0 = ADARA_PKT_TYPE(0x8000, 0), - VAR_VALUE_U32_V0 = ADARA_PKT_TYPE(0x8001, 0), - VAR_VALUE_DOUBLE_V0 = ADARA_PKT_TYPE(0x8002, 0), - VAR_VALUE_STRING_V0 = ADARA_PKT_TYPE(0x8003, 0) -}; + enum Enum { + RAW_EVENT_V0 = ADARA_PKT_TYPE(0x0000, 0), + RTDL_V0 = ADARA_PKT_TYPE(0x0001, 0), + SOURCE_LIST_V0 = ADARA_PKT_TYPE(0x0002, 0), + MAPPED_EVENT_V0 = ADARA_PKT_TYPE(0x0003, 0), + BANKED_EVENT_V0 = ADARA_PKT_TYPE(0x4000, 0), + BANKED_EVENT_V1 = ADARA_PKT_TYPE(0x4000, 1), + BEAM_MONITOR_EVENT_V0 = ADARA_PKT_TYPE(0x4001, 0), + BEAM_MONITOR_EVENT_V1 = ADARA_PKT_TYPE(0x4001, 1), + PIXEL_MAPPING_V0 = ADARA_PKT_TYPE(0x4002, 0), + RUN_STATUS_V0 = ADARA_PKT_TYPE(0x4003, 0), + RUN_INFO_V0 = ADARA_PKT_TYPE(0x4004, 0), + TRANS_COMPLETE_V0 = ADARA_PKT_TYPE(0x4005, 0), + CLIENT_HELLO_V0 = ADARA_PKT_TYPE(0x4006, 0), + STREAM_ANNOTATION_V0 = ADARA_PKT_TYPE(0x4007, 0), + SYNC_V0 = ADARA_PKT_TYPE(0x4008, 0), + HEARTBEAT_V0 = ADARA_PKT_TYPE(0x4009, 0), + GEOMETRY_V0 = ADARA_PKT_TYPE(0x400A, 0), + BEAMLINE_INFO_V0 = ADARA_PKT_TYPE(0x400B, 0), + BEAMLINE_INFO_V1 = ADARA_PKT_TYPE(0x400B, 1), + DATA_DONE_V0 = ADARA_PKT_TYPE(0x400C, 0), + BEAM_MONITOR_CONFIG_V0 = ADARA_PKT_TYPE(0x400D, 0), + DETECTOR_BANK_SETS_V0 = ADARA_PKT_TYPE(0x400E, 0), + DEVICE_DESC_V0 = ADARA_PKT_TYPE(0x8000, 0), + VAR_VALUE_U32_V0 = ADARA_PKT_TYPE(0x8001, 0), + VAR_VALUE_DOUBLE_V0 = ADARA_PKT_TYPE(0x8002, 0), + VAR_VALUE_STRING_V0 = ADARA_PKT_TYPE(0x8003, 0), + }; } /* These are defined in the SNS Timing Master Functional System Description, * section 1.3.4. */ namespace PulseFlavor { -enum Enum { - NO_BEAM = 0, - NORMAL = 1, - NORMAL_TGT_1 = 1, - NORMAL_TGT_2 = 2, - DIAG_10us = 3, - DIAG_50us = 4, - DIAG_100us = 5, - SPECIAL_PHYSICS_1 = 6, - SPECIAL_PHYSICS_2 = 7 -}; + enum Enum { + NO_BEAM = 0, + NORMAL = 1, + NORMAL_TGT_1 = 1, + NORMAL_TGT_2 = 2, + DIAG_10us = 3, + DIAG_50us = 4, + DIAG_100us = 5, + SPECIAL_PHYSICS_1 = 6, + SPECIAL_PHYSICS_2 = 7 + }; } namespace RunStatus { -enum Enum { - NO_RUN = 0, - NEW_RUN = 1, - RUN_EOF = 2, - RUN_BOF = 3, - END_RUN = 4, - STATE = 5 -}; + enum Enum { + NO_RUN = 0, + NEW_RUN = 1, + RUN_EOF = 2, + RUN_BOF = 3, + END_RUN = 4, + STATE = 5, + }; } namespace VariableStatus { -enum Enum { - OK = 0, // EPICS: NO_ALARM - READ_ERROR = 1, - WRITE_ERROR = 2, - HIHI_LIMIT = 3, - HIGH_LIMIT = 4, - LOLO_LIMIT = 5, - LOW_LIMIT = 6, - BAD_STATE = 7, - CHANGED_STATE = 8, - NO_COMMUNICATION = 9, - COMMUNICATION_TIMEOUT = 10, - HARDWARE_LIMIT = 11, - BAD_CALCULATION = 12, - INVALID_SCAN = 13, - LINK_FAILED = 14, - INVALID_STATE = 15, - BAD_SUBROUTINE = 16, - UNDEFINED_ALARM = 17, - DISABLED = 18, - SIMULATED = 19, - READ_PERMISSION = 20, - WRITE_PERMISSION = 21, - UPSTREAM_DISCONNECTED = 0xfffe, - NOT_REPORTED = 0xffff -}; + enum Enum { + OK = 0, // EPICS: NO_ALARM + READ_ERROR = 1, + WRITE_ERROR = 2, + HIHI_LIMIT = 3, + HIGH_LIMIT = 4, + LOLO_LIMIT = 5, + LOW_LIMIT = 6, + BAD_STATE = 7, + CHANGED_STATE = 8, + NO_COMMUNICATION = 9, + COMMUNICATION_TIMEOUT = 10, + HARDWARE_LIMIT = 11, + BAD_CALCULATION = 12, + INVALID_SCAN = 13, + LINK_FAILED = 14, + INVALID_STATE = 15, + BAD_SUBROUTINE = 16, + UNDEFINED_ALARM = 17, + DISABLED = 18, + SIMULATED = 19, + READ_PERMISSION = 20, + WRITE_PERMISSION = 21, + UPSTREAM_DISCONNECTED = 0xfffe, + NOT_REPORTED = 0xffff, + }; } namespace VariableSeverity { -enum Enum { - OK = 0, // EPICS: NO_ALARM - MINOR_ALARM = 1, - MAJOR_ALARM = 2, - INVALID = 3, - NOT_REPORTED = 0xffff -}; + enum Enum { + OK = 0, // EPICS: NO_ALARM + MINOR_ALARM = 1, + MAJOR_ALARM = 2, + INVALID = 3, + NOT_REPORTED = 0xffff, + }; } namespace MarkerType { -enum Enum { - GENERIC, - SCAN_START, - SCAN_STOP, - PAUSE, - RESUME, - OVERALL_RUN_COMMENT -}; + enum Enum { + GENERIC, + SCAN_START, + SCAN_STOP, + PAUSE, + RESUME, + OVERALL_RUN_COMMENT, + }; } struct Event { - uint32_t tof; - uint32_t pixel; + uint32_t tof; + uint32_t pixel; }; struct Header { - uint32_t payload_len; - uint32_t pkt_format; - uint32_t ts_sec; - uint32_t ts_nsec; + uint32_t payload_len; + uint32_t pkt_format; + uint32_t ts_sec; + uint32_t ts_nsec; }; class invalid_packet : public std::runtime_error { public: - explicit invalid_packet(const std::string &msg) : runtime_error(msg) {} + explicit invalid_packet(const std::string &msg) : runtime_error(msg) {} }; -enum { EPICS_EPOCH_OFFSET = 631152000 }; +enum { + EPICS_EPOCH_OFFSET = 631152000 +}; } /* namespace ADARA */ diff --git a/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAPackets.h b/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAPackets.h index 9a616c43892aa2a1c6b4dd1beba99e4ca39b8a34..79f0be62c836ca73176e29cbec0c3c9df19df539 100644 --- a/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAPackets.h +++ b/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAPackets.h @@ -2,6 +2,9 @@ #define __ADARA_PACKETS_H #include <stdint.h> +#include <string> +#include <sstream> +#include <string.h> #include "ADARA.h" #include "MantidKernel/System.h" @@ -11,10 +14,10 @@ namespace ADARA { class DLLExport PacketHeader { public: PacketHeader(const uint8_t *data) { - const uint32_t *field = (const uint32_t *)data; + const uint32_t *field = (const uint32_t *) data; m_payload_len = field[0]; - m_type = (PacketType::Enum)field[1]; + m_type = (PacketType::Enum) field[1]; #if 0 // NOTE: Windows doesn't have struct timespec and Mantid doesn't really need this, @@ -26,7 +29,7 @@ public: m_timestamp.tv_nsec = field[3]; #endif - m_pulseId = ((uint64_t)field[2]) << 32; + m_pulseId = ((uint64_t) field[2]) << 32; m_pulseId |= field[3]; } @@ -61,10 +64,12 @@ public: virtual ~Packet(); const uint8_t *packet(void) const { return m_data; } - const uint8_t *payload(void) const { return m_data + header_length(); } + const uint8_t *payload(void) const { + return m_data + header_length(); + } protected: - const uint8_t *m_data; + const uint8_t * m_data; uint32_t m_len; bool m_allocated; @@ -83,22 +88,25 @@ public: uint16_t pktSeq(void) const { return (m_fields[1] >> 16) & 0x7fff; } uint16_t dspSeq(void) const { return m_fields[1] & 0x7fff; } PulseFlavor::Enum flavor(void) const { - return static_cast<PulseFlavor::Enum>((m_fields[2] >> 24) & 0x7); + return static_cast<PulseFlavor::Enum> + ((m_fields[2] >> 24) & 0x7); } uint32_t pulseCharge(void) const { return m_fields[2] & 0x00ffffff; } - bool badVeto(void) const { return !!(m_fields[3] & 0x8000000); } + bool badVeto(void) const { return !!(m_fields[3] & 0x80000000); } bool badCycle(void) const { return !!(m_fields[3] & 0x40000000); } - uint8_t timingStatus(void) const { return (uint8_t)(m_fields[3] >> 22); } - uint16_t veto(void) const { return (m_fields[3] >> 10) & 0xfff; } + uint8_t timingStatus(void) const { + return (uint8_t) (m_fields[3] >> 22); + } + uint16_t vetoFlags(void) const { return (m_fields[3] >> 10) & 0xfff; } uint16_t cycle(void) const { return m_fields[3] & 0x3ff; } uint32_t intraPulseTime(void) const { return m_fields[4]; } bool tofCorrected(void) const { return !!(m_fields[5] & 0x80000000); } uint32_t tofOffset(void) const { return m_fields[5] & 0x7fffffff; } uint32_t tofField(void) const { return m_fields[5]; } - const Event *events(void) const { return (const Event *)&m_fields[6]; } + const Event *events(void) const { return (const Event *) &m_fields[6]; } uint32_t num_events(void) const { - return (m_payload_len - 24) / static_cast<uint32_t>(2 * sizeof(uint32_t)); + return (m_payload_len - 24) / (uint32_t) (2 * sizeof(uint32_t)); } private: @@ -106,6 +114,16 @@ private: RawDataPkt(const uint8_t *data, uint32_t len); + friend class Parser; + friend class MappedDataPkt; +}; + +class DLLExport MappedDataPkt : public RawDataPkt { +public: + MappedDataPkt(const MappedDataPkt &pkt); +private: + MappedDataPkt(const uint8_t *data, uint32_t len); + friend class Parser; }; @@ -114,20 +132,41 @@ public: RTDLPkt(const RTDLPkt &pkt); PulseFlavor::Enum flavor(void) const { - return static_cast<PulseFlavor::Enum>((m_fields[0] >> 24) & 0x7); + return static_cast<PulseFlavor::Enum> + ((m_fields[0] >> 24) & 0x7); } uint32_t pulseCharge(void) const { return m_fields[0] & 0x00ffffff; } - bool badVeto(void) const { return !!(m_fields[1] & 0x8000000); } + bool badVeto(void) const { return !!(m_fields[1] & 0x80000000); } bool badCycle(void) const { return !!(m_fields[1] & 0x40000000); } - uint8_t timingStatus(void) const { return (uint8_t)(m_fields[1] >> 22); } - uint16_t veto(void) const { return (m_fields[1] >> 10) & 0xfff; } + uint8_t timingStatus(void) const { + return (uint8_t) (m_fields[1] >> 22); + } + uint16_t vetoFlags(void) const { return (m_fields[1] >> 10) & 0xfff; } uint16_t cycle(void) const { return m_fields[1] & 0x3ff; } uint32_t intraPulseTime(void) const { return m_fields[2]; } bool tofCorrected(void) const { return !!(m_fields[3] & 0x80000000); } uint32_t tofOffset(void) const { return m_fields[3] & 0x7fffffff; } uint32_t ringPeriod(void) const { return m_fields[4] & 0xffffff; } - // TODO implement accessor for optional fields + // accessor methods for optional FNA/Frame Data fields + + uint32_t FNA(uint32_t index) const + { + // If out of bounds, just return "0" for "Unused Frame"... ;-D + if ( index > 24 ) + return( 0 ); + else + return ( m_fields[ 5 + index ] >> 24 ) & 0xff; + } + + uint32_t frameData(uint32_t index) const + { + // Out of bounds, return "-1" (0xffffff) for Bogus "Frame Data" ;-b + if ( index > 24 ) + return( -1 ); + else + return m_fields[ 5 + index ] & 0xffffff; + } private: const uint32_t *m_fields; @@ -141,9 +180,9 @@ class DLLExport SourceListPkt : public Packet { public: SourceListPkt(const SourceListPkt &pkt); - const uint32_t *ids(void) const { return (const uint32_t *)payload(); } + const uint32_t *ids(void) const { return (const uint32_t *) payload(); } uint32_t num_ids(void) const { - return payload_length() / static_cast<uint32_t>(sizeof(uint32_t)); + return (uint32_t) payload_length() / (uint32_t) sizeof(uint32_t); } private: @@ -162,13 +201,14 @@ public: PULSE_VETO = 0x0004, MISSING_RTDL = 0x0008, MAPPING_ERROR = 0x0010, - DUPLICATE_PULSE = 0x0020 + DUPLICATE_PULSE = 0x0020, }; uint32_t pulseCharge(void) const { return m_fields[0]; } uint32_t pulseEnergy(void) const { return m_fields[1]; } uint32_t cycle(void) const { return m_fields[2]; } - uint32_t flags(void) const { return m_fields[3]; } + uint32_t vetoFlags(void) const { return (m_fields[3] >> 20) & 0xfff; } + uint32_t flags(void) const { return m_fields[3] & 0xfffff; } // The source, bank and event accessors all return NULL if we've // incremented past the end @@ -222,7 +262,8 @@ public: uint32_t pulseCharge(void) const { return m_fields[0]; } uint32_t pulseEnergy(void) const { return m_fields[1]; } uint32_t cycle(void) const { return m_fields[2]; } - uint32_t flags(void) const { return m_fields[3]; } + uint32_t vetoFlags(void) const { return (m_fields[3] >> 20) & 0xfff; } + uint32_t flags(void) const { return m_fields[3] & 0xfffff; } // bool firstSection() const; bool nextSection() const; // iterate over the sections in the packet @@ -331,14 +372,15 @@ public: AnnotationPkt(const AnnotationPkt &pkt); bool resetHint(void) const { return !!(m_fields[0] & 0x80000000); } - MarkerType::Enum type(void) const { + MarkerType::Enum marker_type(void) const { uint16_t type = (m_fields[0] >> 16) & 0x7fff; return static_cast<MarkerType::Enum>(type); } uint32_t scanIndex(void) const { return m_fields[1]; } const std::string &comment(void) const { if (!m_comment.length() && (m_fields[0] & 0xffff)) { - m_comment.assign((const char *)&m_fields[2], m_fields[0] & 0xffff); + m_comment.assign((const char *) &m_fields[2], + m_fields[0] & 0xffff); } return m_comment; @@ -392,11 +434,15 @@ class DLLExport BeamlineInfoPkt : public Packet { public: BeamlineInfoPkt(const BeamlineInfoPkt &pkt); + const uint32_t &targetNumber(void) const { return m_targetNumber; } + const std::string &id(void) const { return m_id; } const std::string &shortName(void) const { return m_shortName; } const std::string &longName(void) const { return m_longName; } private: + uint32_t m_targetNumber; + std::string m_id; std::string m_shortName; std::string m_longName; @@ -406,6 +452,206 @@ private: friend class Parser; }; +class DLLExport BeamMonitorConfigPkt : public Packet { +public: + BeamMonitorConfigPkt(const BeamMonitorConfigPkt &pkt); + + uint32_t beamMonCount(void) const { return m_fields[0]; } + + uint32_t bmonId(uint32_t index) const + { + if ( index < beamMonCount() ) + return m_fields[(index * 6) + 1]; + else + return( 0 ); + } + + uint32_t tofOffset(uint32_t index) const + { + if ( index < beamMonCount() ) + return m_fields[(index * 6) + 2]; + else + return( 0 ); + } + + uint32_t tofMax(uint32_t index) const + { + if ( index < beamMonCount() ) + return m_fields[(index * 6) + 3]; + else + return( 0 ); + } + + uint32_t tofBin(uint32_t index) const + { + if ( index < beamMonCount() ) + return m_fields[(index * 6) + 4]; + else + return( 0 ); + } + + double distance(uint32_t index) const + { + if ( index < beamMonCount() ) + return *(const double *) &m_fields[(index * 6) + 5]; + else + return( 0.0 ); + } + +private: + const uint32_t *m_fields; + + BeamMonitorConfigPkt(const uint8_t *data, uint32_t len); + + friend class Parser; +}; + +class DLLExport DetectorBankSetsPkt : public Packet { +public: + DetectorBankSetsPkt(const DetectorBankSetsPkt &pkt); + + // Detector Bank Set Name, alphanumeric characters... + static const size_t SET_NAME_SIZE = 16; + + // Throttle Suffix, alphanumeric, no spaces/punctuation... + static const size_t THROTTLE_SUFFIX_SIZE = 16; + + enum Flags { + EVENT_FORMAT = 0x0001, + HISTO_FORMAT = 0x0002, + }; + + uint32_t detBankSetCount(void) const { return m_fields[0]; } + + uint32_t sectionOffset(uint32_t index) const + { + if ( index < detBankSetCount() ) + return( m_sectionOffsets[index] ); + else + return( 0 ); // Minimum Valid offset is always past Header... + } + + std::string name(uint32_t index) const + { + if ( index < detBankSetCount() ) { + char name_c[SET_NAME_SIZE + 1]; // give them an inch... + memset( (void *) name_c, '\0', SET_NAME_SIZE + 1 ); + strncpy(name_c, + (const char *) &(m_fields[ m_sectionOffsets[index] ]), + SET_NAME_SIZE); + return( std::string(name_c) ); + } else { + return( "<Out Of Range!>" ); + } + } + + uint32_t flags(uint32_t index) const + { + if ( index < detBankSetCount() ) + return m_fields[ m_sectionOffsets[index] + m_name_offset ]; + else + return( 0 ); + } + + uint32_t bankCount(uint32_t index) const + { + if ( index < detBankSetCount() ) + return m_fields[ m_sectionOffsets[index] + m_name_offset + 1 ]; + else + return( 0 ); + } + + const uint32_t *banklist(uint32_t index) const + { + if ( index < detBankSetCount() ) { + return (const uint32_t *) &m_fields[ m_sectionOffsets[index] + + m_name_offset + 2 ]; + } + else { + // Shouldn't be asking for this if bankCount() returned 0...! + return( (const uint32_t *) NULL ); + } + } + + uint32_t tofOffset(uint32_t index) const + { + if ( index < detBankSetCount() ) + return m_fields[ m_after_banks_offset[index] ]; + else + return( 0 ); + } + + uint32_t tofMax(uint32_t index) const + { + if ( index < detBankSetCount() ) + return m_fields[ m_after_banks_offset[index] + 1 ]; + else + return( 0 ); + } + + uint32_t tofBin(uint32_t index) const + { + if ( index < detBankSetCount() ) + return m_fields[ m_after_banks_offset[index] + 2 ]; + else + return( 0 ); + } + + double throttle(uint32_t index) const + { + if ( index < detBankSetCount() ) { + return *(const double *) &m_fields[ + m_after_banks_offset[index] + 3 ]; + } + else + return( 0.0 ); + } + + std::string suffix(uint32_t index) const + { + if ( index < detBankSetCount() ) { + char suffix_c[THROTTLE_SUFFIX_SIZE + 1]; // give them an inch + memset( (void *) suffix_c, '\0', THROTTLE_SUFFIX_SIZE + 1 ); + strncpy(suffix_c, + (const char *) &(m_fields[m_after_banks_offset[index] + 5]), + THROTTLE_SUFFIX_SIZE); + return( std::string(suffix_c) ); + } else { + std::stringstream ss; + ss << "out-of-range-"; + ss << index; + return( ss.str() ); + } + } + +private: + const uint32_t *m_fields; + + static const uint32_t m_name_offset = + SET_NAME_SIZE / sizeof(uint32_t); + + static const uint32_t m_suffix_offset = + THROTTLE_SUFFIX_SIZE / sizeof(uint32_t); + + uint32_t *m_sectionOffsets; + + uint32_t *m_after_banks_offset; + + DetectorBankSetsPkt(const uint8_t *data, uint32_t len); + + friend class Parser; +}; + +class DLLExport DataDonePkt : public Packet { +public: + DataDonePkt(const DataDonePkt &pkt); + +private: + DataDonePkt(const uint8_t *data, uint32_t len); + + friend class Parser; +}; + class DLLExport DeviceDescriptorPkt : public Packet { public: DeviceDescriptorPkt(const DeviceDescriptorPkt &pkt); @@ -435,10 +681,11 @@ public: uint32_t devId(void) const { return m_fields[0]; } uint32_t varId(void) const { return m_fields[1]; } VariableStatus::Enum status(void) const { - return static_cast<VariableStatus::Enum>(m_fields[2] >> 16); + return static_cast<VariableStatus::Enum> (m_fields[2] >> 16); } VariableSeverity::Enum severity(void) const { - return static_cast<VariableSeverity::Enum>(m_fields[2] & 0xffff); + return static_cast<VariableSeverity::Enum> + (m_fields[2] & 0xffff); } uint32_t value(void) const { return m_fields[3]; } @@ -462,12 +709,13 @@ public: uint32_t devId(void) const { return m_fields[0]; } uint32_t varId(void) const { return m_fields[1]; } VariableStatus::Enum status(void) const { - return static_cast<VariableStatus::Enum>(m_fields[2] >> 16); + return static_cast<VariableStatus::Enum> (m_fields[2] >> 16); } VariableSeverity::Enum severity(void) const { - return static_cast<VariableSeverity::Enum>(m_fields[2] & 0xffff); + return static_cast<VariableSeverity::Enum> + (m_fields[2] & 0xffff); } - double value(void) const { return *(const double *)&m_fields[3]; } + double value(void) const { return *(const double *) &m_fields[3]; } void remapDevice(uint32_t dev) { uint32_t *fields = (uint32_t *)const_cast<uint8_t *>(payload()); @@ -489,10 +737,11 @@ public: uint32_t devId(void) const { return m_fields[0]; } uint32_t varId(void) const { return m_fields[1]; } VariableStatus::Enum status(void) const { - return static_cast<VariableStatus::Enum>(m_fields[2] >> 16); + return static_cast<VariableStatus::Enum> (m_fields[2] >> 16); } VariableSeverity::Enum severity(void) const { - return static_cast<VariableSeverity::Enum>(m_fields[2] & 0xffff); + return static_cast<VariableSeverity::Enum> + (m_fields[2] & 0xffff); } const std::string &value(void) const { return m_val; } diff --git a/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAParser.h b/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAParser.h index dafaece450e8f1b2e1d6fd05627837441269c587..d7619e66cb79ce2ae6b6fc7258b27b31a08b00ee 100644 --- a/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAParser.h +++ b/Code/Mantid/Framework/LiveData/inc/MantidLiveData/ADARA/ADARAParser.h @@ -4,6 +4,7 @@ #include <string> #include <stdint.h> #include <stdexcept> +#include <map> #include "ADARA.h" #include "ADARAPackets.h" @@ -53,7 +54,9 @@ protected: return NULL; } - unsigned int bufferFillLength(void) const { return m_size - m_len; } + unsigned int bufferFillLength(void) const { + return m_size - m_len; + } void bufferBytesAppended(unsigned int count) { if (bufferFillLength() < count) { @@ -78,7 +81,7 @@ protected: * Partial packet chunks will be counted as completed when the last * fragment is processed. **/ - int bufferParse(unsigned int max_packets = 0); + int bufferParse(std::string & log_info, unsigned int max_packets = 0); /** Flush the internal buffers and get ready to restart parsing. **/ @@ -101,8 +104,10 @@ protected: /**@{*/ virtual bool rxPacket(const Packet &pkt); virtual bool rxUnknownPkt(const Packet &pkt); - virtual bool rxOversizePkt(const PacketHeader *hdr, const uint8_t *chunk, - unsigned int chunk_offset, unsigned int chunk_len); + virtual bool rxOversizePkt(const PacketHeader *hdr, + const uint8_t *chunk, + unsigned int chunk_offset, + unsigned int chunk_len); /**@}*/ /** @name Specific rxPacket Functions @@ -120,6 +125,7 @@ protected: **/ /**@{*/ virtual bool rxPacket(const RawDataPkt &pkt); + virtual bool rxPacket(const MappedDataPkt &pkt); virtual bool rxPacket(const RTDLPkt &pkt); virtual bool rxPacket(const SourceListPkt &pkt); virtual bool rxPacket(const BankedEventPkt &pkt); @@ -134,14 +140,31 @@ protected: virtual bool rxPacket(const HeartbeatPkt &pkt); virtual bool rxPacket(const GeometryPkt &pkt); virtual bool rxPacket(const BeamlineInfoPkt &pkt); + virtual bool rxPacket(const BeamMonitorConfigPkt &pkt); + virtual bool rxPacket(const DetectorBankSetsPkt &pkt); + virtual bool rxPacket(const DataDonePkt &pkt); virtual bool rxPacket(const DeviceDescriptorPkt &pkt); virtual bool rxPacket(const VariableU32Pkt &pkt); virtual bool rxPacket(const VariableDoublePkt &pkt); virtual bool rxPacket(const VariableStringPkt &pkt); /**@}*/ + + /* Collect a log string with statistics on "discarded" packet types, + * i.e. packets that for one reason or another were _Not_ parsed + * or processed. + * + * Since we don't have a common logging approach in this software suite + * (<sigh/>), we just fill up a happy logging string with info + * and return it for the caller's logger du jour. + */ + void getDiscardedPacketsLogString(std::string & log_info); + + /* Reset the collected "discarded packet" statistics. + */ + void resetDiscardedPacketsStats(void); private: - uint8_t *m_buffer; + uint8_t * m_buffer; unsigned int m_size; unsigned int m_max_size; unsigned int m_len; @@ -149,6 +172,8 @@ private: unsigned int m_restart_offset; unsigned int m_oversize_len; unsigned int m_oversize_offset; + + std::map<PacketType::Enum, uint64_t> m_discarded_packets; }; } /* namespacce ADARA */ diff --git a/Code/Mantid/Framework/LiveData/src/ADARA/ADARAPackets.cpp b/Code/Mantid/Framework/LiveData/src/ADARA/ADARAPackets.cpp index fbf5a1af1a7e873ca0ab11106fab09791f519e7c..0204ceb436dd5127be84afd83306f5e3a79d0ba6 100644 --- a/Code/Mantid/Framework/LiveData/src/ADARA/ADARAPackets.cpp +++ b/Code/Mantid/Framework/LiveData/src/ADARA/ADARAPackets.cpp @@ -6,57 +6,57 @@ using namespace ADARA; static bool validate_status(uint16_t val) { - VariableStatus::Enum e = static_cast<VariableStatus::Enum>(val); + VariableStatus::Enum e = static_cast<VariableStatus::Enum>(val); - /* No default case so that we get warned when new status values - * get added. - */ + /* No default case so that we get warned when new status values + * get added. + */ switch (e) { - case VariableStatus::OK: - case VariableStatus::READ_ERROR: - case VariableStatus::WRITE_ERROR: - case VariableStatus::HIHI_LIMIT: - case VariableStatus::HIGH_LIMIT: - case VariableStatus::LOLO_LIMIT: - case VariableStatus::LOW_LIMIT: - case VariableStatus::BAD_STATE: - case VariableStatus::CHANGED_STATE: - case VariableStatus::NO_COMMUNICATION: - case VariableStatus::COMMUNICATION_TIMEOUT: - case VariableStatus::HARDWARE_LIMIT: - case VariableStatus::BAD_CALCULATION: - case VariableStatus::INVALID_SCAN: - case VariableStatus::LINK_FAILED: - case VariableStatus::INVALID_STATE: - case VariableStatus::BAD_SUBROUTINE: - case VariableStatus::UNDEFINED_ALARM: - case VariableStatus::DISABLED: - case VariableStatus::SIMULATED: - case VariableStatus::READ_PERMISSION: - case VariableStatus::WRITE_PERMISSION: - case VariableStatus::UPSTREAM_DISCONNECTED: - case VariableStatus::NOT_REPORTED: - return false; - } - - return true; + case VariableStatus::OK: + case VariableStatus::READ_ERROR: + case VariableStatus::WRITE_ERROR: + case VariableStatus::HIHI_LIMIT: + case VariableStatus::HIGH_LIMIT: + case VariableStatus::LOLO_LIMIT: + case VariableStatus::LOW_LIMIT: + case VariableStatus::BAD_STATE: + case VariableStatus::CHANGED_STATE: + case VariableStatus::NO_COMMUNICATION: + case VariableStatus::COMMUNICATION_TIMEOUT: + case VariableStatus::HARDWARE_LIMIT: + case VariableStatus::BAD_CALCULATION: + case VariableStatus::INVALID_SCAN: + case VariableStatus::LINK_FAILED: + case VariableStatus::INVALID_STATE: + case VariableStatus::BAD_SUBROUTINE: + case VariableStatus::UNDEFINED_ALARM: + case VariableStatus::DISABLED: + case VariableStatus::SIMULATED: + case VariableStatus::READ_PERMISSION: + case VariableStatus::WRITE_PERMISSION: + case VariableStatus::UPSTREAM_DISCONNECTED: + case VariableStatus::NOT_REPORTED: + return false; + } + + return true; } static bool validate_severity(uint16_t val) { - VariableSeverity::Enum e = static_cast<VariableSeverity::Enum>(val); + VariableSeverity::Enum e = static_cast<VariableSeverity::Enum>(val); - /* No default case so that we get warned when new severities get added. - */ - switch (e) { - case VariableSeverity::OK: - case VariableSeverity::MINOR_ALARM: - case VariableSeverity::MAJOR_ALARM: - case VariableSeverity::INVALID: - case VariableSeverity::NOT_REPORTED: - return false; - } + /* No default case so that we get warned when new severities get added. + */ + switch (e) { + case VariableSeverity::OK: + case VariableSeverity::MINOR_ALARM: + case VariableSeverity::MAJOR_ALARM: + case VariableSeverity::INVALID: + case VariableSeverity::NOT_REPORTED: + return false; + } - return true; + return true; } Packet::Packet(const uint8_t *data, uint32_t len) @@ -64,13 +64,13 @@ Packet::Packet(const uint8_t *data, uint32_t len) Packet::Packet(const Packet &pkt) : PacketHeader(pkt.packet()), m_allocated(true) { - m_data = new uint8_t[pkt.packet_length()]; - m_len = pkt.packet_length(); + m_data = new uint8_t[pkt.packet_length()]; + m_len = pkt.packet_length(); memcpy(const_cast<uint8_t *>(m_data), pkt.packet(), m_len); } Packet::~Packet() { - if (m_allocated) + if (m_allocated) delete[] m_data; } @@ -78,8 +78,8 @@ Packet::~Packet() { RawDataPkt::RawDataPkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()) { - if (m_payload_len < (6 * sizeof(uint32_t))) - throw invalid_packet("RawDataPacket is too short"); + if (m_payload_len < (6 * sizeof(uint32_t))) + throw invalid_packet("RawDataPacket is too short"); } RawDataPkt::RawDataPkt(const RawDataPkt &pkt) @@ -87,13 +87,26 @@ RawDataPkt::RawDataPkt(const RawDataPkt &pkt) /* ------------------------------------------------------------------------ */ +MappedDataPkt::MappedDataPkt(const uint8_t *data, uint32_t len) : + RawDataPkt(data, len) +{ + if (m_payload_len < (6 * sizeof(uint32_t))) + throw invalid_packet("MappedDataPacket is too short"); +} + +MappedDataPkt::MappedDataPkt(const MappedDataPkt &pkt) : + RawDataPkt(pkt) +{} + +/* ------------------------------------------------------------------------ */ + RTDLPkt::RTDLPkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()) { - if (m_payload_len != 120) - throw invalid_packet("RTDL Packet is incorrect length"); + if (m_payload_len != 120) + throw invalid_packet("RTDL Packet is incorrect length"); - if ((m_fields[4] >> 24) != 4) - throw invalid_packet("Missing ring period"); + if ((m_fields[4] >> 24) != 4) + throw invalid_packet("Missing ring period"); } RTDLPkt::RTDLPkt(const RTDLPkt &pkt) @@ -114,8 +127,8 @@ BankedEventPkt::BankedEventPkt(const uint8_t *data, uint32_t len) m_TOFOffset(0), m_isCorrected(false), m_bankNum(0), m_bankStartIndex(0), m_bankId(0), m_eventCount(0) { - if (m_payload_len < (4 * sizeof(uint32_t))) - throw invalid_packet("BankedEvent packet is too short"); + if (m_payload_len < (4 * sizeof(uint32_t))) + throw invalid_packet("BankedEvent packet is too short"); m_lastFieldIndex = (payload_length() / 4) - 1; } @@ -239,8 +252,8 @@ void BankedEventPkt::firstEventInBank() const { BeamMonitorPkt::BeamMonitorPkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()), m_sectionStartIndex(0), m_eventNum(0) { - if (m_payload_len < (4 * sizeof(uint32_t))) - throw invalid_packet("BeamMonitor packet is too short"); + if (m_payload_len < (4 * sizeof(uint32_t))) + throw invalid_packet("BeamMonitor packet is too short"); } BeamMonitorPkt::BeamMonitorPkt(const BeamMonitorPkt &pkt) @@ -322,8 +335,8 @@ PixelMappingPkt::PixelMappingPkt(const PixelMappingPkt &pkt) : Packet(pkt) {} RunStatusPkt::RunStatusPkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()) { - if (m_payload_len != (3 * sizeof(uint32_t))) - throw invalid_packet("RunStatus packet is incorrect size"); + if (m_payload_len != (3 * sizeof(uint32_t))) + throw invalid_packet("RunStatus packet is incorrect size"); } RunStatusPkt::RunStatusPkt(const RunStatusPkt &pkt) @@ -335,15 +348,15 @@ RunInfoPkt::RunInfoPkt(const uint8_t *data, uint32_t len) : Packet(data, len) { uint32_t size = *(const uint32_t *)payload(); const char *xml = (const char *)payload() + sizeof(uint32_t); - if (m_payload_len < sizeof(uint32_t)) - throw invalid_packet("RunInfo packet is too short"); - if (m_payload_len < (size + sizeof(uint32_t))) - throw invalid_packet("RunInfo packet has oversize string"); + if (m_payload_len < sizeof(uint32_t)) + throw invalid_packet("RunInfo packet is too short"); + if (m_payload_len < (size + sizeof(uint32_t))) + throw invalid_packet("RunInfo packet has oversize string"); - /* TODO it would be better to create the string on access - * rather than object construction; the user may not care. - */ - m_xml.assign(xml, size); + /* TODO it would be better to create the string on access + * rather than object construction; the user may not care. + */ + m_xml.assign(xml, size); } RunInfoPkt::RunInfoPkt(const RunInfoPkt &pkt) : Packet(pkt), m_xml(pkt.m_xml) {} @@ -356,17 +369,17 @@ TransCompletePkt::TransCompletePkt(const uint8_t *data, uint32_t len) const char *reason = (const char *)payload() + sizeof(uint32_t); m_status = (uint16_t)(size >> 16); - size &= 0xffff; - if (m_payload_len < sizeof(uint32_t)) - throw invalid_packet("TransComplete packet is too short"); - if (m_payload_len < (size + sizeof(uint32_t))) - throw invalid_packet("TransComplete packet has oversize " - "string"); + size &= 0xffff; + if (m_payload_len < sizeof(uint32_t)) + throw invalid_packet("TransComplete packet is too short"); + if (m_payload_len < (size + sizeof(uint32_t))) + throw invalid_packet("TransComplete packet has oversize " + "string"); - /* TODO it would be better to create the string on access - * rather than object construction; the user may not care. - */ - m_reason.assign(reason, size); + /* TODO it would be better to create the string on access + * rather than object construction; the user may not care. + */ + m_reason.assign(reason, size); } TransCompletePkt::TransCompletePkt(const TransCompletePkt &pkt) @@ -376,8 +389,8 @@ TransCompletePkt::TransCompletePkt(const TransCompletePkt &pkt) ClientHelloPkt::ClientHelloPkt(const uint8_t *data, uint32_t len) : Packet(data, len) { - if (m_payload_len != sizeof(uint32_t)) - throw invalid_packet("ClientHello packet is incorrect size"); + if (m_payload_len != sizeof(uint32_t)) + throw invalid_packet("ClientHello packet is incorrect size"); m_reqStart = *(const uint32_t *)payload(); } @@ -389,13 +402,13 @@ ClientHelloPkt::ClientHelloPkt(const ClientHelloPkt &pkt) AnnotationPkt::AnnotationPkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()) { - if (m_payload_len < (2 * sizeof(uint32_t))) - throw invalid_packet("AnnotationPkt packet is incorrect size"); + if (m_payload_len < (2 * sizeof(uint32_t))) + throw invalid_packet("AnnotationPkt packet is incorrect size"); - uint16_t size = m_fields[0] & 0xffff; - if (m_payload_len < (size + (2 * sizeof(uint32_t)))) - throw invalid_packet("AnnotationPkt packet has oversize " - "string"); + uint16_t size = m_fields[0] & 0xffff; + if (m_payload_len < (size + (2 * sizeof(uint32_t)))) + throw invalid_packet("AnnotationPkt packet has oversize " + "string"); } AnnotationPkt::AnnotationPkt(const AnnotationPkt &pkt) @@ -404,12 +417,12 @@ AnnotationPkt::AnnotationPkt(const AnnotationPkt &pkt) /* ------------------------------------------------------------------------ */ SyncPkt::SyncPkt(const uint8_t *data, uint32_t len) : Packet(data, len) { - uint32_t size = *(const uint32_t *)(payload() + 24); + uint32_t size = *(const uint32_t *)(payload() + 24); - if (m_payload_len < 28) - throw invalid_packet("Sync packet is too small"); - if (m_payload_len < (size + 28)) - throw invalid_packet("Sync packet has oversize string"); + if (m_payload_len < 28) + throw invalid_packet("Sync packet is too small"); + if (m_payload_len < (size + 28)) + throw invalid_packet("Sync packet has oversize string"); } SyncPkt::SyncPkt(const SyncPkt &pkt) : Packet(pkt) {} @@ -418,8 +431,8 @@ SyncPkt::SyncPkt(const SyncPkt &pkt) : Packet(pkt) {} HeartbeatPkt::HeartbeatPkt(const uint8_t *data, uint32_t len) : Packet(data, len) { - if (m_payload_len) - throw invalid_packet("Heartbeat packet is incorrect size"); + if (m_payload_len) + throw invalid_packet("Heartbeat packet is incorrect size"); } HeartbeatPkt::HeartbeatPkt(const HeartbeatPkt &pkt) : Packet(pkt) {} @@ -431,15 +444,15 @@ GeometryPkt::GeometryPkt(const uint8_t *data, uint32_t len) uint32_t size = *(const uint32_t *)payload(); const char *xml = (const char *)payload() + sizeof(uint32_t); - if (m_payload_len < sizeof(uint32_t)) - throw invalid_packet("Geometry packet is too short"); - if (m_payload_len < (size + sizeof(uint32_t))) - throw invalid_packet("Geometry packet has oversize string"); + if (m_payload_len < sizeof(uint32_t)) + throw invalid_packet("Geometry packet is too short"); + if (m_payload_len < (size + sizeof(uint32_t))) + throw invalid_packet("Geometry packet has oversize string"); - /* TODO it would be better to create the string on access - * rather than object construction; the user may not care. - */ - m_xml.assign(xml, size); + /* TODO it would be better to create the string on access + * rather than object construction; the user may not care. + */ + m_xml.assign(xml, size); } GeometryPkt::GeometryPkt(const GeometryPkt &pkt) @@ -451,49 +464,200 @@ BeamlineInfoPkt::BeamlineInfoPkt(const uint8_t *data, uint32_t len) : Packet(data, len) { const char *info = (const char *)payload() + sizeof(uint32_t); uint32_t sizes = *(const uint32_t *)payload(); - uint32_t id_len, shortName_len, longName_len, info_len; + uint32_t id_len, shortName_len, longName_len, info_len; + + if (m_payload_len < sizeof(uint32_t)) + throw invalid_packet("Beamline info packet is too short"); + + longName_len = sizes & 0xff; + shortName_len = (sizes >> 8) & 0xff; + id_len = (sizes >> 16) & 0xff; + m_targetNumber = (sizes >> 24) & 0xff; // formerly "Unused" in V0... + + // Unspecified (Version 0 Packet) Target Number Defaults to 1. + if ( m_targetNumber == 0 ) + m_targetNumber = 1; + + info_len = id_len + shortName_len + longName_len; + + if (m_payload_len < (info_len + sizeof(uint32_t))) + throw invalid_packet("Beamline info packet has undersize data"); + + m_id.assign(info, id_len); + info += id_len; + m_shortName.assign(info, shortName_len); + info += shortName_len; + m_longName.assign(info, longName_len); +} + +BeamlineInfoPkt::BeamlineInfoPkt(const BeamlineInfoPkt &pkt) : + Packet(pkt), m_targetNumber(pkt.m_targetNumber), + m_id(pkt.m_id), m_shortName(pkt.m_shortName), m_longName(pkt.m_longName) +{} + +/* ------------------------------------------------------------------------ */ + +BeamMonitorConfigPkt::BeamMonitorConfigPkt(const uint8_t *data, + uint32_t len) : + Packet(data, len), m_fields((const uint32_t *)payload()) +{ + size_t sectionSize = sizeof(double) + (4 * sizeof(uint32_t)); - if (m_payload_len < sizeof(uint32_t)) - throw invalid_packet("Beamline info packet is too short"); + if (m_payload_len != + (sizeof(uint32_t) + (beamMonCount() * sectionSize))) { + std::string msg("BeamMonitorConfig packet is incorrect length: "); + msg += boost::lexical_cast<std::string>(m_payload_len); + throw invalid_packet(msg); + } +} - longName_len = sizes & 0xff; - shortName_len = (sizes >> 8) & 0xff; - id_len = (sizes >> 16) & 0xff; +BeamMonitorConfigPkt::BeamMonitorConfigPkt( + const BeamMonitorConfigPkt &pkt ) : + Packet(pkt), m_fields((const uint32_t *)payload()) +{} - info_len = id_len + shortName_len + longName_len; +/* ------------------------------------------------------------------------ */ - if (m_payload_len < (info_len + sizeof(uint32_t))) - throw invalid_packet("Beamline info packet has undersize data"); +DetectorBankSetsPkt::DetectorBankSetsPkt(const uint8_t *data, + uint32_t len) : + Packet(data, len), m_fields((const uint32_t *)payload()), + m_sectionOffsets(NULL), m_after_banks_offset(NULL) +{ + // Get Number of Detector Bank Sets... + // - Basic Packet Size Sanity Check + + if ( m_payload_len < sizeof(uint32_t) ) { + std::string msg("DetectorBankSets packet is too short for Count! "); + msg += boost::lexical_cast<std::string>(m_payload_len); + throw invalid_packet(msg); + } + + uint32_t numSets = detBankSetCount(); + + // Don't Allocate Anything if there are No Detector Bank Sets... + if ( numSets < 1 ) + return; + + m_sectionOffsets = new uint32_t[numSets]; + + m_after_banks_offset = new uint32_t[numSets]; + + // Traverse Detector Bank Sets... + // - Set Section Offsets + // - Set "After Banks" Offsets + + // Base Section Sizes (w/o Bank Ids) + uint32_t baseSectionOffsetPart1 = 0 + + m_name_offset // name + + 2; // flags & bank id count + uint32_t baseSectionOffsetPart2 = 0 + + 3 // histo params + + 2 // throttle rate (double) + + m_suffix_offset; + uint32_t baseSectionOffsetNoBanks = + baseSectionOffsetPart1 + baseSectionOffsetPart2; + + // Running Section Offset (in number of uint32_t elements) + uint32_t sectionOffset = 1; // for Detector Bank Set Count... + + for ( uint32_t i=0 ; i < numSets ; i++ ) + { + // Section Offset + m_sectionOffsets[i] = sectionOffset; + + if ( m_payload_len < ( ( sectionOffset + baseSectionOffsetNoBanks ) + * sizeof(uint32_t) ) ) { + std::string msg("DetectorBankSets packet: too short for Set "); + msg += boost::lexical_cast<std::string>( i + 1 ); + msg += " of "; + msg += boost::lexical_cast<std::string>(numSets); + msg += " sectionOffset="; + msg += boost::lexical_cast<std::string>(sectionOffset); + msg += " baseSectionOffsetNoBanks="; + msg += boost::lexical_cast<std::string>( + baseSectionOffsetNoBanks); + msg += " payload_len="; + msg += boost::lexical_cast<std::string>(m_payload_len); + delete[] m_sectionOffsets; + m_sectionOffsets = (uint32_t *) NULL; + delete[] m_after_banks_offset; + m_after_banks_offset = (uint32_t *) NULL; + throw invalid_packet(msg); + } + + // Offset thru end of Bank Ids list... + sectionOffset += baseSectionOffsetPart1 + + bankCount(i); // just in time m_sectionOffset delivery...! + + // Save as "After Banks" Offset... + m_after_banks_offset[i] = sectionOffset; + + // Rest of Set Offset... + sectionOffset += baseSectionOffsetPart2; + } + + // Final Payload Size Check... ;-D + if ( m_payload_len < ( sectionOffset * sizeof(uint32_t) ) ) { + std::string msg("DetectorBankSets packet: overall too short "); + msg += " numSets="; + msg += boost::lexical_cast<std::string>(numSets); + msg += " baseSectionOffsetNoBanks="; + msg += boost::lexical_cast<std::string>( + baseSectionOffsetNoBanks); + msg += " final sectionOffset="; + msg += boost::lexical_cast<std::string>(sectionOffset); + msg += " payload_len="; + msg += boost::lexical_cast<std::string>(m_payload_len); + delete[] m_sectionOffsets; + m_sectionOffsets = (uint32_t *) NULL; + delete[] m_after_banks_offset; + m_after_banks_offset = (uint32_t *) NULL; + throw invalid_packet(msg); + } +} + +DetectorBankSetsPkt::DetectorBankSetsPkt( + const DetectorBankSetsPkt &pkt ) : + Packet(pkt), m_fields((const uint32_t *)payload()) +{ + if ( m_sectionOffsets != NULL ) + delete[] m_sectionOffsets; - m_id.assign(info, id_len); - info += id_len; - m_shortName.assign(info, shortName_len); - info += shortName_len; - m_longName.assign(info, longName_len); + if ( m_after_banks_offset != NULL ) + delete[] m_after_banks_offset; } -BeamlineInfoPkt::BeamlineInfoPkt(const BeamlineInfoPkt &pkt) - : Packet(pkt), m_id(pkt.m_id), m_shortName(pkt.m_shortName), - m_longName(pkt.m_longName) {} +/* ------------------------------------------------------------------------ */ + +DataDonePkt::DataDonePkt(const uint8_t *data, uint32_t len) : + Packet(data, len) +{ + if (m_payload_len) + throw invalid_packet("DataDone packet is incorrect size"); +} + +DataDonePkt::DataDonePkt(const DataDonePkt &pkt) : + Packet(pkt) +{} /* ------------------------------------------------------------------------ */ DeviceDescriptorPkt::DeviceDescriptorPkt(const uint8_t *data, uint32_t len) : Packet(data, len) { const uint32_t *fields = (const uint32_t *)payload(); - uint32_t size; - - if (m_payload_len < (2 * sizeof(uint32_t))) - throw invalid_packet("DeviceDescriptor packet is too short"); - size = fields[1]; - if (m_payload_len < (size + (2 * sizeof(uint32_t)))) - throw invalid_packet("DeviceDescriptor packet has oversize " - "string"); - - /* TODO it would be better to create the string on access - * rather than object construction; the user may not care. - */ - m_devId = fields[0]; + uint32_t size; + + if (m_payload_len < (2 * sizeof(uint32_t))) + throw invalid_packet("DeviceDescriptor packet is too short"); + size = fields[1]; + if (m_payload_len < (size + (2 * sizeof(uint32_t)))) + throw invalid_packet("DeviceDescriptor packet has oversize " + "string"); + + /* TODO it would be better to create the string on access + * rather than object construction; the user may not care. + */ + m_devId = fields[0]; m_desc.assign((const char *)&fields[2], size); } @@ -504,24 +668,24 @@ DeviceDescriptorPkt::DeviceDescriptorPkt(const DeviceDescriptorPkt &pkt) VariableU32Pkt::VariableU32Pkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()) { - if (m_payload_len != (4 * sizeof(uint32_t))) { - std::string msg("VariableValue (U32) packet is incorrect " - "length: "); - msg += boost::lexical_cast<std::string>(m_payload_len); - throw invalid_packet(msg); - } - if (validate_status(status())) { - std::string msg("VariableValue (U32) packet has invalid " - "status: "); - msg += boost::lexical_cast<std::string>(status()); - throw invalid_packet(msg); - } - if (validate_severity(severity())) { - std::string msg("VariableValue (U32) packet has invalid " - "severity: "); - msg += boost::lexical_cast<std::string>(severity()); - throw invalid_packet(msg); - } + if (m_payload_len != (4 * sizeof(uint32_t))) { + std::string msg("VariableValue (U32) packet is incorrect " + "length: "); + msg += boost::lexical_cast<std::string>(m_payload_len); + throw invalid_packet(msg); + } + if (validate_status(status())) { + std::string msg("VariableValue (U32) packet has invalid " + "status: "); + msg += boost::lexical_cast<std::string>(status()); + throw invalid_packet(msg); + } + if (validate_severity(severity())) { + std::string msg("VariableValue (U32) packet has invalid " + "severity: "); + msg += boost::lexical_cast<std::string>(severity()); + throw invalid_packet(msg); + } } VariableU32Pkt::VariableU32Pkt(const VariableU32Pkt &pkt) @@ -531,24 +695,24 @@ VariableU32Pkt::VariableU32Pkt(const VariableU32Pkt &pkt) VariableDoublePkt::VariableDoublePkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()) { - if (m_payload_len != (sizeof(double) + (3 * sizeof(uint32_t)))) { - std::string msg("VariableValue (double) packet is incorrect " - "length: "); - msg += boost::lexical_cast<std::string>(m_payload_len); - throw invalid_packet(msg); - } - if (validate_status(status())) { - std::string msg("VariableValue (double) packet has invalid " - "status: "); - msg += boost::lexical_cast<std::string>(status()); - throw invalid_packet(msg); - } - if (validate_severity(severity())) { - std::string msg("VariableValue (double) packet has invalid " - "severity: "); - msg += boost::lexical_cast<std::string>(severity()); - throw invalid_packet(msg); - } + if (m_payload_len != (sizeof(double) + (3 * sizeof(uint32_t)))) { + std::string msg("VariableValue (double) packet is incorrect " + "length: "); + msg += boost::lexical_cast<std::string>(m_payload_len); + throw invalid_packet(msg); + } + if (validate_status(status())) { + std::string msg("VariableValue (double) packet has invalid " + "status: "); + msg += boost::lexical_cast<std::string>(status()); + throw invalid_packet(msg); + } + if (validate_severity(severity())) { + std::string msg("VariableValue (double) packet has invalid " + "severity: "); + msg += boost::lexical_cast<std::string>(severity()); + throw invalid_packet(msg); + } } VariableDoublePkt::VariableDoublePkt(const VariableDoublePkt &pkt) @@ -558,39 +722,39 @@ VariableDoublePkt::VariableDoublePkt(const VariableDoublePkt &pkt) VariableStringPkt::VariableStringPkt(const uint8_t *data, uint32_t len) : Packet(data, len), m_fields((const uint32_t *)payload()) { - uint32_t size; - - if (m_payload_len < (4 * sizeof(uint32_t))) { - std::string msg("VariableValue (string) packet is too short "); - msg += boost::lexical_cast<std::string>(m_payload_len); - throw invalid_packet(msg); - } - size = m_fields[3]; - if (m_payload_len < (size + (2 * sizeof(uint32_t)))) { - std::string msg("VariableValue (string) packet has oversize " - "string: "); - msg += boost::lexical_cast<std::string>(size); - msg += " vs payload "; - msg += boost::lexical_cast<std::string>(m_payload_len); - throw invalid_packet(msg); - } - - if (validate_status(status())) { - std::string msg("VariableValue (string) packet has invalid " - "status: "); - msg += boost::lexical_cast<std::string>(status()); - throw invalid_packet(msg); - } - if (validate_severity(severity())) { - std::string msg("VariableValue (string) packet has invalid " - "severity: "); - msg += boost::lexical_cast<std::string>(severity()); - throw invalid_packet(msg); - } - - /* TODO it would be better to create the string on access - * rather than object construction; the user may not care. - */ + uint32_t size; + + if (m_payload_len < (4 * sizeof(uint32_t))) { + std::string msg("VariableValue (string) packet is too short "); + msg += boost::lexical_cast<std::string>(m_payload_len); + throw invalid_packet(msg); + } + size = m_fields[3]; + if (m_payload_len < (size + (2 * sizeof(uint32_t)))) { + std::string msg("VariableValue (string) packet has oversize " + "string: "); + msg += boost::lexical_cast<std::string>(size); + msg += " vs payload "; + msg += boost::lexical_cast<std::string>(m_payload_len); + throw invalid_packet(msg); + } + + if (validate_status(status())) { + std::string msg("VariableValue (string) packet has invalid " + "status: "); + msg += boost::lexical_cast<std::string>(status()); + throw invalid_packet(msg); + } + if (validate_severity(severity())) { + std::string msg("VariableValue (string) packet has invalid " + "severity: "); + msg += boost::lexical_cast<std::string>(severity()); + throw invalid_packet(msg); + } + + /* TODO it would be better to create the string on access + * rather than object construction; the user may not care. + */ m_val.assign((const char *)&m_fields[4], size); } diff --git a/Code/Mantid/Framework/LiveData/src/ADARA/ADARAParser.cpp b/Code/Mantid/Framework/LiveData/src/ADARA/ADARAParser.cpp index 9c5232b1616275a6557819ea62608f40bf84383d..f40b81e8b6a6d97efcfa87774f0ade4eb262bad3 100644 --- a/Code/Mantid/Framework/LiveData/src/ADARA/ADARAParser.cpp +++ b/Code/Mantid/Framework/LiveData/src/ADARA/ADARAParser.cpp @@ -1,3 +1,4 @@ +#include <sstream> #include <string.h> #include "MantidLiveData/ADARA/ADARAParser.h" @@ -6,210 +7,277 @@ using namespace ADARA; /* ------------------------------------------------------------------------ */ -Parser::Parser(unsigned int initial_buffer_size, unsigned int max_pkt_size) - : m_size(initial_buffer_size), m_max_size(max_pkt_size), m_len(0), - m_restart_offset(0), m_oversize_len(0), m_oversize_offset(0) { - m_buffer = new uint8_t[initial_buffer_size]; +Parser::Parser(unsigned int initial_buffer_size, unsigned int max_pkt_size) : + m_size(initial_buffer_size), m_max_size(max_pkt_size), m_len(0), + m_restart_offset(0), m_oversize_len(0) +{ + m_buffer = new uint8_t[initial_buffer_size]; + m_discarded_packets.clear(); } -Parser::~Parser() { delete[] m_buffer; } +Parser::~Parser() +{ + delete [] m_buffer; +} + +void Parser::reset(void) +{ + m_len = 0; + m_oversize_len = 0; + m_restart_offset = 0; -void Parser::reset(void) { - m_len = 0; - m_oversize_len = 0; - m_restart_offset = 0; + m_discarded_packets.clear(); } -int Parser::bufferParse(unsigned int max_packets) { - unsigned int valid_len = m_len - m_restart_offset; - uint8_t *p = m_buffer + m_restart_offset; - unsigned int processed = 0; - bool stopped = false; - - /* Is there anything to do? */ - if (!valid_len) - return 0; - - /* If we don't care how many packets we process, then set the limit - * above the range of possibility to avoid needing to check for zero - * multiple times. - */ - if (!max_packets) - max_packets = m_size; - - /* If we're processing an oversize packet, then we will find its - * data at the front of the buffer. We'll either consume our - * entire buffer, or find the end of the oversize packet and - * process the rest of the buffer as normal. - */ - if (m_oversize_len) { - unsigned int chunk_len; - - chunk_len = m_oversize_len; - if (valid_len < chunk_len) - chunk_len = valid_len; - stopped = rxOversizePkt(NULL, p, m_oversize_offset, chunk_len); - m_oversize_offset += chunk_len; - m_oversize_len -= chunk_len; - valid_len -= chunk_len; - p += chunk_len; - - /* Did we finish this packet? */ - if (!m_oversize_len) - processed++; - } - - while (valid_len >= PacketHeader::header_length() && - processed < max_packets && !stopped) { - PacketHeader hdr(p); - - if (hdr.payload_length() % 4) - throw invalid_packet("Payload length not " - "multiple of 4"); - - if (m_max_size < hdr.packet_length()) { - /* This packet is over the maximum limit; we'll - * call the oversize handler with this first - * chunk, consuming our entire buffer. - */ - stopped = rxOversizePkt(&hdr, p, 0, valid_len); - m_oversize_len = hdr.packet_length() - valid_len; - m_oversize_offset = valid_len; - valid_len = 0; - break; - } - - if (m_size < hdr.packet_length()) { - /* This packet is too big to possibly fit in our - * current buffer, so we need to grow. Once we've - * resized, return to our caller as we obviously - * don't have the full packet yet. - */ - unsigned int new_size = m_size; - uint8_t *new_buffer; - - do { - new_size *= 2; - } while (new_size < hdr.packet_length()); - - if (new_size > m_max_size) - new_size = m_max_size; - - new_buffer = new uint8_t[new_size]; - memcpy(new_buffer, p, valid_len); - - delete[] m_buffer; - m_buffer = new_buffer; - m_size = new_size; - - /* We moved the data to the front of the buffer as - * part of the resize; account for that. - */ - m_restart_offset = 0; - m_len = valid_len; - return processed; - } - - if (valid_len < hdr.packet_length()) - break; - - Packet pkt(p, hdr.packet_length()); - - p += hdr.packet_length(); - valid_len -= hdr.packet_length(); - - stopped = rxPacket(pkt); - processed++; - } - - /* We're done processing for this round. Update our position and/or - * amount of buffered data so that we restart in the correct spot - * on our next call. - * - * We only need to move data if we ran out of data to process -- - * ie, we processed fewer packets than requested without being - * stopped by a callback. This moves any possible fragment of a - * packet to the front, maximizing the room for more data. If this - * occurs coincidentally with a stop request, the next call to - * to bufferParse() will only see the fragment and stop, but that - * should be rare. - */ - if (valid_len) { - if (!stopped && processed < max_packets) { - if (p != m_buffer) - memmove(m_buffer, p, valid_len); - m_len = valid_len; - m_restart_offset = 0; - } else { - /* We know that the offset will fit into an unsigned - * int, as that is the type we use for the buffer size. - */ - m_restart_offset = (unsigned int)(p - m_buffer); - } - } else { - /* We used up the buffer. */ - m_len = 0; - m_restart_offset = 0; - } - - /* We need an 32 GB buffer before we can fit 2^31 packets, so - * casting to int is safe here. - */ - return stopped ? -(int)processed : (int)processed; +int Parser::bufferParse(std::string & log_info, unsigned int max_packets) +{ + unsigned int valid_len = m_len - m_restart_offset; + uint8_t *p = m_buffer + m_restart_offset; + unsigned int processed = 0; + bool stopped = false; + + /* Is there anything to do? */ + if (!valid_len) { + log_info.append("bufferParse() nothing to do; "); + return 0; + } + + /* If we don't care how many packets we process, then set the limit + * above the range of possibility to avoid needing to check for zero + * multiple times. + */ + if (!max_packets) + max_packets = m_size; + + /* If we're processing an oversize packet, then we will find its + * data at the front of the buffer. We'll either consume our + * entire buffer, or find the end of the oversize packet and + * process the rest of the buffer as normal. + */ + if (m_oversize_len) { + unsigned int chunk_len; + + chunk_len = m_oversize_len; + if (valid_len < chunk_len) + chunk_len = valid_len; + stopped = rxOversizePkt(NULL, p, m_oversize_offset, chunk_len); + m_oversize_offset += chunk_len; + m_oversize_len -= chunk_len; + valid_len -= chunk_len; + p += chunk_len; + + /* Did we finish this packet? */ + if (!m_oversize_len) + processed++; + } + + while (valid_len >= PacketHeader::header_length() && + processed < max_packets && !stopped) { + + PacketHeader hdr(p); + + if (hdr.payload_length() % 4) + throw invalid_packet("Payload length not " + "multiple of 4"); + + if (m_max_size < hdr.packet_length()) { + /* This packet is over the maximum limit; we'll + * call the oversize handler with this first + * chunk, consuming our entire buffer. + */ + stopped = rxOversizePkt(&hdr, p, 0, valid_len); + m_oversize_len = hdr.packet_length() - valid_len; + m_oversize_offset = valid_len; + valid_len = 0; + break; + } + + if (m_size < hdr.packet_length()) { + /* This packet is too big to possibly fit in our + * current buffer, so we need to grow. Once we've + * resized, return to our caller as we obviously + * don't have the full packet yet. + */ + unsigned int new_size = m_size; + uint8_t *new_buffer; + + do { + new_size *= 2; + } while (new_size < hdr.packet_length()); + + if (new_size > m_max_size) + new_size = m_max_size; + + new_buffer = new uint8_t[new_size]; + memcpy(new_buffer, p, valid_len); + + delete [] m_buffer; + m_buffer = new_buffer; + m_size = new_size; + + /* We moved the data to the front of the buffer as + * part of the resize; account for that. + */ + m_restart_offset = 0; + m_len = valid_len; + + // log what we did... + std::stringstream ss; + ss << processed; + log_info.append("bufferParse(): resized, processed "); + log_info.append(ss.str()); + log_info.append(" packets; "); + + return processed; + } + + if (valid_len < hdr.packet_length()) + break; + + Packet pkt(p, hdr.packet_length()); + + p += hdr.packet_length(); + valid_len -= hdr.packet_length(); + + stopped = rxPacket(pkt); + processed++; + + // log failed packet parsing...! + if ( stopped ) { + std::stringstream ss; + log_info.append( + "bufferParse(): rxPacket() returned error for type="); + ss << pkt.type(); + log_info.append(ss.str()); + log_info.append(", stopped; "); + } + } + + /* We're done processing for this round. Update our position and/or + * amount of buffered data so that we restart in the correct spot + * on our next call. + * + * We only need to move data if we ran out of data to process -- + * ie, we processed fewer packets than requested without being + * stopped by a callback. This moves any possible fragment of a + * packet to the front, maximizing the room for more data. If this + * occurs coincidentally with a stop request, the next call to + * to bufferParse() will only see the fragment and stop, but that + * should be rare. + */ + if (valid_len) { + if (!stopped && processed < max_packets) { + if (p != m_buffer) + memmove(m_buffer, p, valid_len); + m_len = valid_len; + m_restart_offset = 0; + } else { + /* We know that the offset will fit into an unsigned + * int, as that is the type we use for the buffer size. + */ + m_restart_offset = (unsigned int) (p - m_buffer); + } + } else { + /* We used up the buffer. */ + m_len = 0; + m_restart_offset = 0; + } + + /* We need an 32 GB buffer before we can fit 2^31 packets, so + * casting to int is safe here. + */ + + std::stringstream ss; + int rc; + + if ( stopped ) { + rc = - (int) processed; + // add to "stopped" log info... + ss << processed; + log_info.append("had parsed "); + log_info.append(ss.str()); + log_info.append(" packets; "); + } + else { + rc = (int) processed; + // create log info... + ss << rc; + log_info.append("bufferParse(): Done. Parsed "); + log_info.append(ss.str()); + log_info.append(" packets; "); + } + + return rc; } -bool Parser::rxPacket(const Packet &pkt) { -#define MAP_TYPE(pkt_type, obj_type) \ - case pkt_type: { \ - obj_type raw(pkt.packet(), pkt.packet_length()); \ - return rxPacket(raw); \ - } - - switch (pkt.type()) { - MAP_TYPE(PacketType::RAW_EVENT_V0, RawDataPkt); - MAP_TYPE(PacketType::RTDL_V0, RTDLPkt); - MAP_TYPE(PacketType::SOURCE_LIST_V0, SourceListPkt); - MAP_TYPE(PacketType::BANKED_EVENT_V0, BankedEventPkt); - MAP_TYPE(PacketType::BEAM_MONITOR_EVENT_V0, BeamMonitorPkt); - MAP_TYPE(PacketType::PIXEL_MAPPING_V0, PixelMappingPkt); - MAP_TYPE(PacketType::RUN_STATUS_V0, RunStatusPkt); - MAP_TYPE(PacketType::RUN_INFO_V0, RunInfoPkt); - MAP_TYPE(PacketType::TRANS_COMPLETE_V0, TransCompletePkt); - MAP_TYPE(PacketType::CLIENT_HELLO_V0, ClientHelloPkt); - MAP_TYPE(PacketType::STREAM_ANNOTATION_V0, AnnotationPkt); - MAP_TYPE(PacketType::SYNC_V0, SyncPkt); - MAP_TYPE(PacketType::HEARTBEAT_V0, HeartbeatPkt); - MAP_TYPE(PacketType::GEOMETRY_V0, GeometryPkt); - MAP_TYPE(PacketType::BEAMLINE_INFO_V0, BeamlineInfoPkt); - MAP_TYPE(PacketType::DEVICE_DESC_V0, DeviceDescriptorPkt); - MAP_TYPE(PacketType::VAR_VALUE_U32_V0, VariableU32Pkt); - MAP_TYPE(PacketType::VAR_VALUE_DOUBLE_V0, VariableDoublePkt); - MAP_TYPE(PacketType::VAR_VALUE_STRING_V0, VariableStringPkt); - - /* No default handler; we want the compiler to warn about - * the unhandled PacketType values when we add new packets. - */ - } - - return rxUnknownPkt(pkt); +bool Parser::rxPacket(const Packet &pkt) +{ +#define MAP_TYPE(pkt_type, obj_type) \ + case pkt_type: { \ + obj_type raw(pkt.packet(), pkt.packet_length()); \ + return rxPacket(raw); \ + } + + switch (pkt.type()) { + MAP_TYPE(PacketType::RAW_EVENT_V0, RawDataPkt); + MAP_TYPE(PacketType::MAPPED_EVENT_V0, MappedDataPkt); + MAP_TYPE(PacketType::RTDL_V0, RTDLPkt); + MAP_TYPE(PacketType::SOURCE_LIST_V0, SourceListPkt); + MAP_TYPE(PacketType::BANKED_EVENT_V0, BankedEventPkt); + MAP_TYPE(PacketType::BANKED_EVENT_V1, BankedEventPkt); + MAP_TYPE(PacketType::BEAM_MONITOR_EVENT_V0, BeamMonitorPkt); + MAP_TYPE(PacketType::BEAM_MONITOR_EVENT_V1, BeamMonitorPkt); + MAP_TYPE(PacketType::PIXEL_MAPPING_V0, PixelMappingPkt); + MAP_TYPE(PacketType::RUN_STATUS_V0, RunStatusPkt); + MAP_TYPE(PacketType::RUN_INFO_V0, RunInfoPkt); + MAP_TYPE(PacketType::TRANS_COMPLETE_V0, TransCompletePkt); + MAP_TYPE(PacketType::CLIENT_HELLO_V0, ClientHelloPkt); + MAP_TYPE(PacketType::STREAM_ANNOTATION_V0, AnnotationPkt); + MAP_TYPE(PacketType::SYNC_V0, SyncPkt); + MAP_TYPE(PacketType::HEARTBEAT_V0, HeartbeatPkt); + MAP_TYPE(PacketType::GEOMETRY_V0, GeometryPkt); + MAP_TYPE(PacketType::BEAMLINE_INFO_V0, BeamlineInfoPkt); + MAP_TYPE(PacketType::BEAMLINE_INFO_V1, BeamlineInfoPkt); + MAP_TYPE(PacketType::BEAM_MONITOR_CONFIG_V0, BeamMonitorConfigPkt); + MAP_TYPE(PacketType::DETECTOR_BANK_SETS_V0, DetectorBankSetsPkt); + MAP_TYPE(PacketType::DATA_DONE_V0, DataDonePkt); + MAP_TYPE(PacketType::DEVICE_DESC_V0, DeviceDescriptorPkt); + MAP_TYPE(PacketType::VAR_VALUE_U32_V0, VariableU32Pkt); + MAP_TYPE(PacketType::VAR_VALUE_DOUBLE_V0, VariableDoublePkt); + MAP_TYPE(PacketType::VAR_VALUE_STRING_V0, VariableStringPkt); + + /* No default handler; we want the compiler to warn about + * the unhandled PacketType values when we add new packets. + */ + } + + return rxUnknownPkt(pkt); #undef MAP_TYPE } -bool Parser::rxUnknownPkt(const Packet &) { - /* Default is to discard the data */ - return false; +bool Parser::rxUnknownPkt(const Packet &pkt) +{ + /* Default is to discard the data */ + (m_discarded_packets[pkt.type()])++; + return false; } -bool Parser::rxOversizePkt(const PacketHeader *, const uint8_t *, unsigned int, - unsigned int) { - /* Default is to discard the data */ - return false; +bool Parser::rxOversizePkt(const PacketHeader *hdr, const uint8_t *, + unsigned int, unsigned int) +{ + // NOTE: ADARA::PacketHeader *hdr can be NULL...! ;-o + /* Default is to discard the data */ + if (hdr != NULL) + (m_discarded_packets[hdr->type()])++; + return false; } -#define EXPAND_HANDLER(type) \ - bool Parser::rxPacket(const type &) { return false; } +#define EXPAND_HANDLER(_class) \ +bool Parser::rxPacket(const _class &pkt) \ + { (m_discarded_packets[pkt.type()])++; return false; } EXPAND_HANDLER(RawDataPkt) +EXPAND_HANDLER(MappedDataPkt) EXPAND_HANDLER(RTDLPkt) EXPAND_HANDLER(SourceListPkt) EXPAND_HANDLER(BankedEventPkt) @@ -224,7 +292,42 @@ EXPAND_HANDLER(SyncPkt) EXPAND_HANDLER(HeartbeatPkt) EXPAND_HANDLER(GeometryPkt) EXPAND_HANDLER(BeamlineInfoPkt) +EXPAND_HANDLER(BeamMonitorConfigPkt) +EXPAND_HANDLER(DetectorBankSetsPkt) +EXPAND_HANDLER(DataDonePkt) EXPAND_HANDLER(DeviceDescriptorPkt) EXPAND_HANDLER(VariableU32Pkt) EXPAND_HANDLER(VariableDoublePkt) EXPAND_HANDLER(VariableStringPkt) + +void Parser::getDiscardedPacketsLogString(std::string & log_info) +{ + log_info = "Discarded ADARA Packet/Counts: "; + + uint64_t total_discarded = 0; + + // Append Each Discarded Packet Type Count... + for (std::map<PacketType::Enum, uint64_t>::iterator + it = m_discarded_packets.begin(); + it != m_discarded_packets.end(); ++it) + { + std::stringstream ss; + ss << std::hex << "0x" << it->first << std::dec + << "=" << it->second << "; "; + log_info.append(ss.str()); + + total_discarded += it->second; + } + + // Append Total Discarded Packet Count + std::stringstream ss; + ss << "Total=" << total_discarded; + log_info.append(ss.str()); +} + +void Parser::resetDiscardedPacketsStats(void) +{ + // Reset Associative Map, Start Clean Stats... + m_discarded_packets.clear(); +} + diff --git a/Code/Mantid/Framework/LiveData/src/SNSLiveEventDataListener.cpp b/Code/Mantid/Framework/LiveData/src/SNSLiveEventDataListener.cpp index 60e074ffa4001ebc89d36da584aa53a68b0cce8d..92525ca8480f6d609eb5b8713c9efeff537a3219 100644 --- a/Code/Mantid/Framework/LiveData/src/SNSLiveEventDataListener.cpp +++ b/Code/Mantid/Framework/LiveData/src/SNSLiveEventDataListener.cpp @@ -265,7 +265,12 @@ void SNSLiveEventDataListener::run() { bufferBytesAppended(bytesRead); } } - int packetsParsed = bufferParse(); + + std::string bufferParseLog; + // bufferParse() wants a string where it can save log messages. + // We don't actually use the messages for anything, though. + int packetsParsed = bufferParse( bufferParseLog); + bufferParseLog.clear(); // keep the string from growing without bound if (packetsParsed == 0) { // No packets were parsed. Sleep a little to let some data accumulate // before calling read again. (Keeps us from spinlocking the cpu...) @@ -1157,7 +1162,7 @@ bool SNSLiveEventDataListener::rxPacket(const ADARA::AnnotationPkt &pkt) { { Poco::ScopedLock<Poco::FastMutex> scopedLock(m_mutex); // We have to lock the mutex prior to calling mutableRun() - switch (pkt.type()) { + switch (pkt.marker_type()) { case ADARA::MarkerType::GENERIC: // Do nothing. We log the comment field below for all types break; diff --git a/Code/Mantid/Framework/LiveData/test/ADARAPacketTest.h b/Code/Mantid/Framework/LiveData/test/ADARAPacketTest.h index 294cebe69ab155f924b73c703ad91f12d8feb7ee..ba329522b4b85cebd7906336cf64aa2e76b91044 100644 --- a/Code/Mantid/Framework/LiveData/test/ADARAPacketTest.h +++ b/Code/Mantid/Framework/LiveData/test/ADARAPacketTest.h @@ -121,7 +121,7 @@ public: if( pkt != NULL) { TS_ASSERT_EQUALS( pkt->cycle(), 60); - TS_ASSERT_EQUALS( pkt->veto(), 0x4); + TS_ASSERT_EQUALS( pkt->vetoFlags(), 0x4); TS_ASSERT_EQUALS( pkt->badVeto(), false); TS_ASSERT_EQUALS( pkt->timingStatus(), 0x1e); TS_ASSERT_EQUALS( pkt->flavor(), 1); @@ -175,6 +175,7 @@ public: protected: // The rxPacket() functions just make a copy of the packet available in the public member // The test class will handle everything from there. + using ADARA::Parser::rxPacket; #define DEFINE_RX_PACKET( PktType) \ virtual bool rxPacket( const PktType &pkt) { m_pkt.reset( new PktType( pkt)); return false; } @@ -258,11 +259,14 @@ private: bufferBytesAppended( len); int packetsParsed = 0; - TS_ASSERT_THROWS_NOTHING( (packetsParsed = bufferParse( 1))); + std::string bufferParseLog; + // bufferParse() wants a string where it can save log messages. + // We don't actually use the messages for anything, though. + TS_ASSERT_THROWS_NOTHING( (packetsParsed = bufferParse( bufferParseLog, 1))); TS_ASSERT( packetsParsed == 1); TS_ASSERT( m_pkt != boost::shared_ptr<ADARA::Packet>()); // verify m_pkt has been updated - TS_ASSERT( bufferParse( 0) == 0); // try to parse again, make sure there's nothing to parse + TS_ASSERT( bufferParse( bufferParseLog, 0) == 0); // try to parse again, make sure there's nothing to parse TS_ASSERT( bufferFillAddress() == m_initialBufferAddr); // verify that there's nothing in the buffer }