From: Joel Holdsworth Date: Sun, 30 Nov 2014 10:46:23 +0000 (+0000) Subject: Snapshot: Renamed to Segment X-Git-Tag: pulseview-0.3.0~393 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=f3d66e52ed6b454ea7a0662d5e6367e230116a2b;p=pulseview.git Snapshot: Renamed to Segment --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 40878efa..de264c5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,11 +147,11 @@ set(pulseview_SOURCES pv/storesession.cpp pv/util.cpp pv/data/analog.cpp - pv/data/analogsnapshot.cpp + pv/data/analogsegment.cpp pv/data/logic.cpp - pv/data/logicsnapshot.cpp + pv/data/logicsegment.cpp pv/data/signaldata.cpp - pv/data/snapshot.cpp + pv/data/segment.cpp pv/dialogs/about.cpp pv/dialogs/connect.cpp pv/dialogs/storeprogress.cpp diff --git a/pv/data/analog.cpp b/pv/data/analog.cpp index 3f96dae1..c95fffaf 100644 --- a/pv/data/analog.cpp +++ b/pv/data/analog.cpp @@ -21,7 +21,7 @@ #include #include "analog.hpp" -#include "analogsnapshot.hpp" +#include "analogsegment.hpp" using std::deque; using std::max; @@ -36,31 +36,31 @@ Analog::Analog() : { } -void Analog::push_snapshot(shared_ptr &snapshot) +void Analog::push_segment(shared_ptr &segment) { - snapshots_.push_front(snapshot); + segments_.push_front(segment); } -const deque< shared_ptr >& Analog::analog_snapshots() const +const deque< shared_ptr >& Analog::analog_segments() const { - return snapshots_; + return segments_; } -vector< shared_ptr > Analog::snapshots() const +vector< shared_ptr > Analog::segments() const { - return vector< shared_ptr >( - snapshots_.begin(), snapshots_.end()); + return vector< shared_ptr >( + segments_.begin(), segments_.end()); } void Analog::clear() { - snapshots_.clear(); + segments_.clear(); } uint64_t Analog::get_max_sample_count() const { uint64_t l = 0; - for (const std::shared_ptr s : snapshots_) { + for (const std::shared_ptr s : segments_) { assert(s); l = max(l, s->get_sample_count()); } diff --git a/pv/data/analog.hpp b/pv/data/analog.hpp index 9551afff..2fe588e4 100644 --- a/pv/data/analog.hpp +++ b/pv/data/analog.hpp @@ -29,27 +29,27 @@ namespace pv { namespace data { -class AnalogSnapshot; +class AnalogSegment; class Analog : public SignalData { public: Analog(); - void push_snapshot( - std::shared_ptr &snapshot); + void push_segment( + std::shared_ptr &segment); - const std::deque< std::shared_ptr >& - analog_snapshots() const; + const std::deque< std::shared_ptr >& + analog_segments() const; - std::vector< std::shared_ptr > snapshots() const; + std::vector< std::shared_ptr > segments() const; void clear(); uint64_t get_max_sample_count() const; private: - std::deque< std::shared_ptr > snapshots_; + std::deque< std::shared_ptr > segments_; }; } // namespace data diff --git a/pv/data/analogsegment.cpp b/pv/data/analogsegment.cpp new file mode 100644 index 00000000..b970bebd --- /dev/null +++ b/pv/data/analogsegment.cpp @@ -0,0 +1,214 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include + +#include + +#include "analogsegment.hpp" + +using std::lock_guard; +using std::recursive_mutex; +using std::max; +using std::max_element; +using std::min; +using std::min_element; + +namespace pv { +namespace data { + +const int AnalogSegment::EnvelopeScalePower = 4; +const int AnalogSegment::EnvelopeScaleFactor = 1 << EnvelopeScalePower; +const float AnalogSegment::LogEnvelopeScaleFactor = + logf(EnvelopeScaleFactor); +const uint64_t AnalogSegment::EnvelopeDataUnit = 64*1024; // bytes + +AnalogSegment::AnalogSegment( + uint64_t samplerate, const uint64_t expected_num_samples) : + Segment(samplerate, sizeof(float)) +{ + set_capacity(expected_num_samples); + + lock_guard lock(mutex_); + memset(envelope_levels_, 0, sizeof(envelope_levels_)); +} + +AnalogSegment::~AnalogSegment() +{ + lock_guard lock(mutex_); + for (Envelope &e : envelope_levels_) + free(e.samples); +} + +void AnalogSegment::append_interleaved_samples(const float *data, + size_t sample_count, size_t stride) +{ + assert(unit_size_ == sizeof(float)); + + lock_guard lock(mutex_); + + data_.resize((sample_count_ + sample_count) * sizeof(float)); + + float *dst = (float*)data_.data() + sample_count_; + const float *dst_end = dst + sample_count; + while (dst != dst_end) + { + *dst++ = *data; + data += stride; + } + + sample_count_ += sample_count; + + // Generate the first mip-map from the data + append_payload_to_envelope_levels(); +} + +const float* AnalogSegment::get_samples( + int64_t start_sample, int64_t end_sample) const +{ + assert(start_sample >= 0); + assert(start_sample < (int64_t)sample_count_); + assert(end_sample >= 0); + assert(end_sample < (int64_t)sample_count_); + assert(start_sample <= end_sample); + + lock_guard lock(mutex_); + + float *const data = new float[end_sample - start_sample]; + memcpy(data, (float*)data_.data() + start_sample, sizeof(float) * + (end_sample - start_sample)); + return data; +} + +void AnalogSegment::get_envelope_section(EnvelopeSection &s, + uint64_t start, uint64_t end, float min_length) const +{ + assert(end <= get_sample_count()); + assert(start <= end); + assert(min_length > 0); + + lock_guard lock(mutex_); + + const unsigned int min_level = max((int)floorf(logf(min_length) / + LogEnvelopeScaleFactor) - 1, 0); + const unsigned int scale_power = (min_level + 1) * + EnvelopeScalePower; + start >>= scale_power; + end >>= scale_power; + + s.start = start << scale_power; + s.scale = 1 << scale_power; + s.length = end - start; + s.samples = new EnvelopeSample[s.length]; + memcpy(s.samples, envelope_levels_[min_level].samples + start, + s.length * sizeof(EnvelopeSample)); +} + +void AnalogSegment::reallocate_envelope(Envelope &e) +{ + const uint64_t new_data_length = ((e.length + EnvelopeDataUnit - 1) / + EnvelopeDataUnit) * EnvelopeDataUnit; + if (new_data_length > e.data_length) + { + e.data_length = new_data_length; + e.samples = (EnvelopeSample*)realloc(e.samples, + new_data_length * sizeof(EnvelopeSample)); + } +} + +void AnalogSegment::append_payload_to_envelope_levels() +{ + Envelope &e0 = envelope_levels_[0]; + uint64_t prev_length; + EnvelopeSample *dest_ptr; + + // Expand the data buffer to fit the new samples + prev_length = e0.length; + e0.length = sample_count_ / EnvelopeScaleFactor; + + // Break off if there are no new samples to compute + if (e0.length == prev_length) + return; + + reallocate_envelope(e0); + + dest_ptr = e0.samples + prev_length; + + // Iterate through the samples to populate the first level mipmap + const float *const end_src_ptr = (float*)data_.data() + + e0.length * EnvelopeScaleFactor; + for (const float *src_ptr = (float*)data_.data() + + prev_length * EnvelopeScaleFactor; + src_ptr < end_src_ptr; src_ptr += EnvelopeScaleFactor) + { + const EnvelopeSample sub_sample = { + *min_element(src_ptr, src_ptr + EnvelopeScaleFactor), + *max_element(src_ptr, src_ptr + EnvelopeScaleFactor), + }; + + *dest_ptr++ = sub_sample; + } + + // Compute higher level mipmaps + for (unsigned int level = 1; level < ScaleStepCount; level++) + { + Envelope &e = envelope_levels_[level]; + const Envelope &el = envelope_levels_[level-1]; + + // Expand the data buffer to fit the new samples + prev_length = e.length; + e.length = el.length / EnvelopeScaleFactor; + + // Break off if there are no more samples to computed + if (e.length == prev_length) + break; + + reallocate_envelope(e); + + // Subsample the level lower level + const EnvelopeSample *src_ptr = + el.samples + prev_length * EnvelopeScaleFactor; + const EnvelopeSample *const end_dest_ptr = e.samples + e.length; + for (dest_ptr = e.samples + prev_length; + dest_ptr < end_dest_ptr; dest_ptr++) + { + const EnvelopeSample *const end_src_ptr = + src_ptr + EnvelopeScaleFactor; + + EnvelopeSample sub_sample = *src_ptr++; + while (src_ptr < end_src_ptr) + { + sub_sample.min = min(sub_sample.min, src_ptr->min); + sub_sample.max = max(sub_sample.max, src_ptr->max); + src_ptr++; + } + + *dest_ptr = sub_sample; + } + } +} + +} // namespace data +} // namespace pv diff --git a/pv/data/analogsegment.hpp b/pv/data/analogsegment.hpp new file mode 100644 index 00000000..38922f59 --- /dev/null +++ b/pv/data/analogsegment.hpp @@ -0,0 +1,96 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H +#define PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H + +#include "segment.hpp" + +#include +#include + +namespace AnalogSegmentTest { +struct Basic; +} + +namespace pv { +namespace data { + +class AnalogSegment : public Segment +{ +public: + struct EnvelopeSample + { + float min; + float max; + }; + + struct EnvelopeSection + { + uint64_t start; + unsigned int scale; + uint64_t length; + EnvelopeSample *samples; + }; + +private: + struct Envelope + { + uint64_t length; + uint64_t data_length; + EnvelopeSample *samples; + }; + +private: + static const unsigned int ScaleStepCount = 10; + static const int EnvelopeScalePower; + static const int EnvelopeScaleFactor; + static const float LogEnvelopeScaleFactor; + static const uint64_t EnvelopeDataUnit; + +public: + AnalogSegment(uint64_t samplerate, uint64_t expected_num_samples = 0); + + virtual ~AnalogSegment(); + + void append_interleaved_samples(const float *data, + size_t sample_count, size_t stride); + + const float* get_samples(int64_t start_sample, + int64_t end_sample) const; + + void get_envelope_section(EnvelopeSection &s, + uint64_t start, uint64_t end, float min_length) const; + +private: + void reallocate_envelope(Envelope &l); + + void append_payload_to_envelope_levels(); + +private: + struct Envelope envelope_levels_[ScaleStepCount]; + + friend struct AnalogSegmentTest::Basic; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H diff --git a/pv/data/analogsnapshot.cpp b/pv/data/analogsnapshot.cpp deleted file mode 100644 index 5e995158..00000000 --- a/pv/data/analogsnapshot.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include -#include -#include -#include - -#include - -#include "analogsnapshot.hpp" - -using std::lock_guard; -using std::recursive_mutex; -using std::max; -using std::max_element; -using std::min; -using std::min_element; - -namespace pv { -namespace data { - -const int AnalogSnapshot::EnvelopeScalePower = 4; -const int AnalogSnapshot::EnvelopeScaleFactor = 1 << EnvelopeScalePower; -const float AnalogSnapshot::LogEnvelopeScaleFactor = - logf(EnvelopeScaleFactor); -const uint64_t AnalogSnapshot::EnvelopeDataUnit = 64*1024; // bytes - -AnalogSnapshot::AnalogSnapshot( - uint64_t samplerate, const uint64_t expected_num_samples) : - Snapshot(samplerate, sizeof(float)) -{ - set_capacity(expected_num_samples); - - lock_guard lock(mutex_); - memset(envelope_levels_, 0, sizeof(envelope_levels_)); -} - -AnalogSnapshot::~AnalogSnapshot() -{ - lock_guard lock(mutex_); - for (Envelope &e : envelope_levels_) - free(e.samples); -} - -void AnalogSnapshot::append_interleaved_samples(const float *data, - size_t sample_count, size_t stride) -{ - assert(unit_size_ == sizeof(float)); - - lock_guard lock(mutex_); - - data_.resize((sample_count_ + sample_count) * sizeof(float)); - - float *dst = (float*)data_.data() + sample_count_; - const float *dst_end = dst + sample_count; - while (dst != dst_end) - { - *dst++ = *data; - data += stride; - } - - sample_count_ += sample_count; - - // Generate the first mip-map from the data - append_payload_to_envelope_levels(); -} - -const float* AnalogSnapshot::get_samples( - int64_t start_sample, int64_t end_sample) const -{ - assert(start_sample >= 0); - assert(start_sample < (int64_t)sample_count_); - assert(end_sample >= 0); - assert(end_sample < (int64_t)sample_count_); - assert(start_sample <= end_sample); - - lock_guard lock(mutex_); - - float *const data = new float[end_sample - start_sample]; - memcpy(data, (float*)data_.data() + start_sample, sizeof(float) * - (end_sample - start_sample)); - return data; -} - -void AnalogSnapshot::get_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length) const -{ - assert(end <= get_sample_count()); - assert(start <= end); - assert(min_length > 0); - - lock_guard lock(mutex_); - - const unsigned int min_level = max((int)floorf(logf(min_length) / - LogEnvelopeScaleFactor) - 1, 0); - const unsigned int scale_power = (min_level + 1) * - EnvelopeScalePower; - start >>= scale_power; - end >>= scale_power; - - s.start = start << scale_power; - s.scale = 1 << scale_power; - s.length = end - start; - s.samples = new EnvelopeSample[s.length]; - memcpy(s.samples, envelope_levels_[min_level].samples + start, - s.length * sizeof(EnvelopeSample)); -} - -void AnalogSnapshot::reallocate_envelope(Envelope &e) -{ - const uint64_t new_data_length = ((e.length + EnvelopeDataUnit - 1) / - EnvelopeDataUnit) * EnvelopeDataUnit; - if (new_data_length > e.data_length) - { - e.data_length = new_data_length; - e.samples = (EnvelopeSample*)realloc(e.samples, - new_data_length * sizeof(EnvelopeSample)); - } -} - -void AnalogSnapshot::append_payload_to_envelope_levels() -{ - Envelope &e0 = envelope_levels_[0]; - uint64_t prev_length; - EnvelopeSample *dest_ptr; - - // Expand the data buffer to fit the new samples - prev_length = e0.length; - e0.length = sample_count_ / EnvelopeScaleFactor; - - // Break off if there are no new samples to compute - if (e0.length == prev_length) - return; - - reallocate_envelope(e0); - - dest_ptr = e0.samples + prev_length; - - // Iterate through the samples to populate the first level mipmap - const float *const end_src_ptr = (float*)data_.data() + - e0.length * EnvelopeScaleFactor; - for (const float *src_ptr = (float*)data_.data() + - prev_length * EnvelopeScaleFactor; - src_ptr < end_src_ptr; src_ptr += EnvelopeScaleFactor) - { - const EnvelopeSample sub_sample = { - *min_element(src_ptr, src_ptr + EnvelopeScaleFactor), - *max_element(src_ptr, src_ptr + EnvelopeScaleFactor), - }; - - *dest_ptr++ = sub_sample; - } - - // Compute higher level mipmaps - for (unsigned int level = 1; level < ScaleStepCount; level++) - { - Envelope &e = envelope_levels_[level]; - const Envelope &el = envelope_levels_[level-1]; - - // Expand the data buffer to fit the new samples - prev_length = e.length; - e.length = el.length / EnvelopeScaleFactor; - - // Break off if there are no more samples to computed - if (e.length == prev_length) - break; - - reallocate_envelope(e); - - // Subsample the level lower level - const EnvelopeSample *src_ptr = - el.samples + prev_length * EnvelopeScaleFactor; - const EnvelopeSample *const end_dest_ptr = e.samples + e.length; - for (dest_ptr = e.samples + prev_length; - dest_ptr < end_dest_ptr; dest_ptr++) - { - const EnvelopeSample *const end_src_ptr = - src_ptr + EnvelopeScaleFactor; - - EnvelopeSample sub_sample = *src_ptr++; - while (src_ptr < end_src_ptr) - { - sub_sample.min = min(sub_sample.min, src_ptr->min); - sub_sample.max = max(sub_sample.max, src_ptr->max); - src_ptr++; - } - - *dest_ptr = sub_sample; - } - } -} - -} // namespace data -} // namespace pv diff --git a/pv/data/analogsnapshot.hpp b/pv/data/analogsnapshot.hpp deleted file mode 100644 index 69c28a2a..00000000 --- a/pv/data/analogsnapshot.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H -#define PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H - -#include "snapshot.hpp" - -#include -#include - -namespace AnalogSnapshotTest { -struct Basic; -} - -namespace pv { -namespace data { - -class AnalogSnapshot : public Snapshot -{ -public: - struct EnvelopeSample - { - float min; - float max; - }; - - struct EnvelopeSection - { - uint64_t start; - unsigned int scale; - uint64_t length; - EnvelopeSample *samples; - }; - -private: - struct Envelope - { - uint64_t length; - uint64_t data_length; - EnvelopeSample *samples; - }; - -private: - static const unsigned int ScaleStepCount = 10; - static const int EnvelopeScalePower; - static const int EnvelopeScaleFactor; - static const float LogEnvelopeScaleFactor; - static const uint64_t EnvelopeDataUnit; - -public: - AnalogSnapshot(uint64_t samplerate, uint64_t expected_num_samples = 0); - - virtual ~AnalogSnapshot(); - - void append_interleaved_samples(const float *data, - size_t sample_count, size_t stride); - - const float* get_samples(int64_t start_sample, - int64_t end_sample) const; - - void get_envelope_section(EnvelopeSection &s, - uint64_t start, uint64_t end, float min_length) const; - -private: - void reallocate_envelope(Envelope &l); - - void append_payload_to_envelope_levels(); - -private: - struct Envelope envelope_levels_[ScaleStepCount]; - - friend struct AnalogSnapshotTest::Basic; -}; - -} // namespace data -} // namespace pv - -#endif // PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H diff --git a/pv/data/decoderstack.cpp b/pv/data/decoderstack.cpp index a764e452..e9876d21 100644 --- a/pv/data/decoderstack.cpp +++ b/pv/data/decoderstack.cpp @@ -27,7 +27,7 @@ #include "decoderstack.hpp" #include -#include +#include #include #include #include @@ -245,7 +245,7 @@ void DecoderStack::begin_decode() // We get the logic data of the first channel in the list. // This works because we are currently assuming all - // LogicSignals have the same data/snapshot + // LogicSignals have the same data/segment for (const shared_ptr &dec : stack_) if (dec && !dec->channels().empty() && ((logic_signal = (*dec->channels().begin()).second)) && @@ -255,16 +255,16 @@ void DecoderStack::begin_decode() if (!data) return; - // Check we have a snapshot of data - const deque< shared_ptr > &snapshots = - data->logic_snapshots(); - if (snapshots.empty()) + // Check we have a segment of data + const deque< shared_ptr > &segments = + data->logic_segments(); + if (segments.empty()) return; - snapshot_ = snapshots.front(); + segment_ = segments.front(); // Get the samplerate and start time - start_time_ = snapshot_->start_time(); - samplerate_ = snapshot_->samplerate(); + start_time_ = segment_->start_time(); + samplerate_ = segment_->samplerate(); if (samplerate_ == 0.0) samplerate_ = 1.0; @@ -301,7 +301,7 @@ void DecoderStack::decode_data( uint8_t chunk[DecodeChunkLength]; const unsigned int chunk_sample_count = - DecodeChunkLength / snapshot_->unit_size(); + DecodeChunkLength / segment_->unit_size(); for (int64_t i = 0; !interrupt_ && i < sample_count; i += chunk_sample_count) @@ -310,7 +310,7 @@ void DecoderStack::decode_data( const int64_t chunk_end = min( i + chunk_sample_count, sample_count); - snapshot_->get_samples(chunk, i, chunk_end); + segment_->get_samples(chunk, i, chunk_end); if (srd_session_send(session, i, i + sample_count, chunk, (chunk_end - i) * unit_size) != SRD_OK) { @@ -336,14 +336,14 @@ void DecoderStack::decode_proc() srd_session *session; srd_decoder_inst *prev_di = NULL; - assert(snapshot_); + assert(segment_); // Create the session srd_session_new(&session); assert(session); // Create the decoders - const unsigned int unit_size = snapshot_->unit_size(); + const unsigned int unit_size = segment_->unit_size(); for (const shared_ptr &dec : stack_) { @@ -365,7 +365,7 @@ void DecoderStack::decode_proc() // Get the intial sample count { unique_lock input_lock(input_mutex_); - sample_count = sample_count_ = snapshot_->get_sample_count(); + sample_count = sample_count_ = segment_->get_sample_count(); } // Start the session @@ -436,8 +436,8 @@ void DecoderStack::on_data_received() { { unique_lock lock(input_mutex_); - if (snapshot_) - sample_count_ = snapshot_->get_sample_count(); + if (segment_) + sample_count_ = segment_->get_sample_count(); } input_cond_.notify_one(); } @@ -446,7 +446,7 @@ void DecoderStack::on_frame_ended() { { unique_lock lock(input_mutex_); - if (snapshot_) + if (segment_) frame_complete_ = true; } input_cond_.notify_one(); diff --git a/pv/data/decoderstack.hpp b/pv/data/decoderstack.hpp index 39e507e8..38310990 100644 --- a/pv/data/decoderstack.hpp +++ b/pv/data/decoderstack.hpp @@ -58,7 +58,7 @@ class LogicSignal; namespace data { -class LogicSnapshot; +class LogicSegment; namespace decode { class Annotation; @@ -148,7 +148,7 @@ private: std::list< std::shared_ptr > stack_; - std::shared_ptr snapshot_; + std::shared_ptr segment_; mutable std::mutex input_mutex_; mutable std::condition_variable input_cond_; diff --git a/pv/data/logic.cpp b/pv/data/logic.cpp index 96f0d1fe..fe29aea4 100644 --- a/pv/data/logic.cpp +++ b/pv/data/logic.cpp @@ -21,7 +21,7 @@ #include #include "logic.hpp" -#include "logicsnapshot.hpp" +#include "logicsegment.hpp" using std::deque; using std::max; @@ -43,32 +43,32 @@ int Logic::get_num_channels() const return num_channels_; } -void Logic::push_snapshot( - shared_ptr &snapshot) +void Logic::push_segment( + shared_ptr &segment) { - snapshots_.push_front(snapshot); + segments_.push_front(segment); } -const deque< shared_ptr >& Logic::logic_snapshots() const +const deque< shared_ptr >& Logic::logic_segments() const { - return snapshots_; + return segments_; } -vector< shared_ptr > Logic::snapshots() const +vector< shared_ptr > Logic::segments() const { - return vector< shared_ptr >( - snapshots_.begin(), snapshots_.end()); + return vector< shared_ptr >( + segments_.begin(), segments_.end()); } void Logic::clear() { - snapshots_.clear(); + segments_.clear(); } uint64_t Logic::get_max_sample_count() const { uint64_t l = 0; - for (std::shared_ptr s : snapshots_) { + for (std::shared_ptr s : segments_) { assert(s); l = max(l, s->get_sample_count()); } diff --git a/pv/data/logic.hpp b/pv/data/logic.hpp index d57df0cf..9adc9750 100644 --- a/pv/data/logic.hpp +++ b/pv/data/logic.hpp @@ -28,7 +28,7 @@ namespace pv { namespace data { -class LogicSnapshot; +class LogicSegment; class Logic : public SignalData { @@ -37,13 +37,13 @@ public: int get_num_channels() const; - void push_snapshot( - std::shared_ptr &snapshot); + void push_segment( + std::shared_ptr &segment); - const std::deque< std::shared_ptr >& - logic_snapshots() const; + const std::deque< std::shared_ptr >& + logic_segments() const; - std::vector< std::shared_ptr > snapshots() const; + std::vector< std::shared_ptr > segments() const; void clear(); @@ -51,7 +51,7 @@ public: private: const unsigned int num_channels_; - std::deque< std::shared_ptr > snapshots_; + std::deque< std::shared_ptr > segments_; }; } // namespace data diff --git a/pv/data/logicsegment.cpp b/pv/data/logicsegment.cpp new file mode 100644 index 00000000..2b9d89bf --- /dev/null +++ b/pv/data/logicsegment.cpp @@ -0,0 +1,469 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include + +#include "logicsegment.hpp" + +#include + +using std::lock_guard; +using std::recursive_mutex; +using std::max; +using std::min; +using std::pair; +using std::shared_ptr; + +using sigrok::Logic; + +namespace pv { +namespace data { + +const int LogicSegment::MipMapScalePower = 4; +const int LogicSegment::MipMapScaleFactor = 1 << MipMapScalePower; +const float LogicSegment::LogMipMapScaleFactor = logf(MipMapScaleFactor); +const uint64_t LogicSegment::MipMapDataUnit = 64*1024; // bytes + +LogicSegment::LogicSegment(shared_ptr logic, uint64_t samplerate, + const uint64_t expected_num_samples) : + Segment(samplerate, logic->unit_size()), + last_append_sample_(0) +{ + set_capacity(expected_num_samples); + + lock_guard lock(mutex_); + memset(mip_map_, 0, sizeof(mip_map_)); + append_payload(logic); +} + +LogicSegment::~LogicSegment() +{ + lock_guard lock(mutex_); + for (MipMapLevel &l : mip_map_) + free(l.data); +} + +uint64_t LogicSegment::unpack_sample(const uint8_t *ptr) const +{ +#ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS + return *(uint64_t*)ptr; +#else + uint64_t value = 0; + switch(unit_size_) { + default: + value |= ((uint64_t)ptr[7]) << 56; + /* FALLTHRU */ + case 7: + value |= ((uint64_t)ptr[6]) << 48; + /* FALLTHRU */ + case 6: + value |= ((uint64_t)ptr[5]) << 40; + /* FALLTHRU */ + case 5: + value |= ((uint64_t)ptr[4]) << 32; + /* FALLTHRU */ + case 4: + value |= ((uint32_t)ptr[3]) << 24; + /* FALLTHRU */ + case 3: + value |= ((uint32_t)ptr[2]) << 16; + /* FALLTHRU */ + case 2: + value |= ptr[1] << 8; + /* FALLTHRU */ + case 1: + value |= ptr[0]; + /* FALLTHRU */ + case 0: + break; + } + return value; +#endif +} + +void LogicSegment::pack_sample(uint8_t *ptr, uint64_t value) +{ +#ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS + *(uint64_t*)ptr = value; +#else + switch(unit_size_) { + default: + ptr[7] = value >> 56; + /* FALLTHRU */ + case 7: + ptr[6] = value >> 48; + /* FALLTHRU */ + case 6: + ptr[5] = value >> 40; + /* FALLTHRU */ + case 5: + ptr[4] = value >> 32; + /* FALLTHRU */ + case 4: + ptr[3] = value >> 24; + /* FALLTHRU */ + case 3: + ptr[2] = value >> 16; + /* FALLTHRU */ + case 2: + ptr[1] = value >> 8; + /* FALLTHRU */ + case 1: + ptr[0] = value; + /* FALLTHRU */ + case 0: + break; + } +#endif +} + +void LogicSegment::append_payload(shared_ptr logic) +{ + assert(unit_size_ == logic->unit_size()); + assert((logic->data_length() % unit_size_) == 0); + + lock_guard lock(mutex_); + + append_data(logic->data_pointer(), + logic->data_length() / unit_size_); + + // Generate the first mip-map from the data + append_payload_to_mipmap(); +} + +void LogicSegment::get_samples(uint8_t *const data, + int64_t start_sample, int64_t end_sample) const +{ + assert(data); + assert(start_sample >= 0); + assert(start_sample <= (int64_t)sample_count_); + assert(end_sample >= 0); + assert(end_sample <= (int64_t)sample_count_); + assert(start_sample <= end_sample); + + lock_guard lock(mutex_); + + const size_t size = (end_sample - start_sample) * unit_size_; + memcpy(data, (const uint8_t*)data_.data() + start_sample * unit_size_, size); +} + +void LogicSegment::reallocate_mipmap_level(MipMapLevel &m) +{ + const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) / + MipMapDataUnit) * MipMapDataUnit; + if (new_data_length > m.data_length) + { + m.data_length = new_data_length; + + // Padding is added to allow for the uint64_t write word + m.data = realloc(m.data, new_data_length * unit_size_ + + sizeof(uint64_t)); + } +} + +void LogicSegment::append_payload_to_mipmap() +{ + MipMapLevel &m0 = mip_map_[0]; + uint64_t prev_length; + const uint8_t *src_ptr; + uint8_t *dest_ptr; + uint64_t accumulator; + unsigned int diff_counter; + + // Expand the data buffer to fit the new samples + prev_length = m0.length; + m0.length = sample_count_ / MipMapScaleFactor; + + // Break off if there are no new samples to compute + if (m0.length == prev_length) + return; + + reallocate_mipmap_level(m0); + + dest_ptr = (uint8_t*)m0.data + prev_length * unit_size_; + + // Iterate through the samples to populate the first level mipmap + const uint8_t *const end_src_ptr = (uint8_t*)data_.data() + + m0.length * unit_size_ * MipMapScaleFactor; + for (src_ptr = (uint8_t*)data_.data() + + prev_length * unit_size_ * MipMapScaleFactor; + src_ptr < end_src_ptr;) + { + // Accumulate transitions which have occurred in this sample + accumulator = 0; + diff_counter = MipMapScaleFactor; + while (diff_counter-- > 0) + { + const uint64_t sample = unpack_sample(src_ptr); + accumulator |= last_append_sample_ ^ sample; + last_append_sample_ = sample; + src_ptr += unit_size_; + } + + pack_sample(dest_ptr, accumulator); + dest_ptr += unit_size_; + } + + // Compute higher level mipmaps + for (unsigned int level = 1; level < ScaleStepCount; level++) + { + MipMapLevel &m = mip_map_[level]; + const MipMapLevel &ml = mip_map_[level-1]; + + // Expand the data buffer to fit the new samples + prev_length = m.length; + m.length = ml.length / MipMapScaleFactor; + + // Break off if there are no more samples to computed + if (m.length == prev_length) + break; + + reallocate_mipmap_level(m); + + // Subsample the level lower level + src_ptr = (uint8_t*)ml.data + + unit_size_ * prev_length * MipMapScaleFactor; + const uint8_t *const end_dest_ptr = + (uint8_t*)m.data + unit_size_ * m.length; + for (dest_ptr = (uint8_t*)m.data + + unit_size_ * prev_length; + dest_ptr < end_dest_ptr; + dest_ptr += unit_size_) + { + accumulator = 0; + diff_counter = MipMapScaleFactor; + while (diff_counter-- > 0) + { + accumulator |= unpack_sample(src_ptr); + src_ptr += unit_size_; + } + + pack_sample(dest_ptr, accumulator); + } + } +} + +uint64_t LogicSegment::get_sample(uint64_t index) const +{ + assert(index < sample_count_); + + return unpack_sample((uint8_t*)data_.data() + index * unit_size_); +} + +void LogicSegment::get_subsampled_edges( + std::vector &edges, + uint64_t start, uint64_t end, + float min_length, int sig_index) +{ + uint64_t index = start; + unsigned int level; + bool last_sample; + bool fast_forward; + + assert(end <= get_sample_count()); + assert(start <= end); + assert(min_length > 0); + assert(sig_index >= 0); + assert(sig_index < 64); + + lock_guard lock(mutex_); + + const uint64_t block_length = (uint64_t)max(min_length, 1.0f); + const unsigned int min_level = max((int)floorf(logf(min_length) / + LogMipMapScaleFactor) - 1, 0); + const uint64_t sig_mask = 1ULL << sig_index; + + // Store the initial state + last_sample = (get_sample(start) & sig_mask) != 0; + edges.push_back(pair(index++, last_sample)); + + while (index + block_length <= end) + { + //----- Continue to search -----// + level = min_level; + + // We cannot fast-forward if there is no mip-map data at + // at the minimum level. + fast_forward = (mip_map_[level].data != NULL); + + if (min_length < MipMapScaleFactor) + { + // Search individual samples up to the beginning of + // the next first level mip map block + const uint64_t final_index = min(end, + pow2_ceil(index, MipMapScalePower)); + + for (; index < final_index && + (index & ~(~0 << MipMapScalePower)) != 0; + index++) + { + const bool sample = + (get_sample(index) & sig_mask) != 0; + + // If there was a change we cannot fast forward + if (sample != last_sample) { + fast_forward = false; + break; + } + } + } + else + { + // If resolution is less than a mip map block, + // round up to the beginning of the mip-map block + // for this level of detail + const int min_level_scale_power = + (level + 1) * MipMapScalePower; + index = pow2_ceil(index, min_level_scale_power); + if (index >= end) + break; + + // We can fast forward only if there was no change + const bool sample = + (get_sample(index) & sig_mask) != 0; + if (last_sample != sample) + fast_forward = false; + } + + if (fast_forward) { + + // Fast forward: This involves zooming out to higher + // levels of the mip map searching for changes, then + // zooming in on them to find the point where the edge + // begins. + + // Slide right and zoom out at the beginnings of mip-map + // blocks until we encounter a change + while (1) { + const int level_scale_power = + (level + 1) * MipMapScalePower; + const uint64_t offset = + index >> level_scale_power; + + // Check if we reached the last block at this + // level, or if there was a change in this block + if (offset >= mip_map_[level].length || + (get_subsample(level, offset) & + sig_mask)) + break; + + if ((offset & ~(~0 << MipMapScalePower)) == 0) { + // If we are now at the beginning of a + // higher level mip-map block ascend one + // level + if (level + 1 >= ScaleStepCount || + !mip_map_[level + 1].data) + break; + + level++; + } else { + // Slide right to the beginning of the + // next mip map block + index = pow2_ceil(index + 1, + level_scale_power); + } + } + + // Zoom in, and slide right until we encounter a change, + // and repeat until we reach min_level + while (1) { + assert(mip_map_[level].data); + + const int level_scale_power = + (level + 1) * MipMapScalePower; + const uint64_t offset = + index >> level_scale_power; + + // Check if we reached the last block at this + // level, or if there was a change in this block + if (offset >= mip_map_[level].length || + (get_subsample(level, offset) & + sig_mask)) { + // Zoom in unless we reached the minimum + // zoom + if (level == min_level) + break; + + level--; + } else { + // Slide right to the beginning of the + // next mip map block + index = pow2_ceil(index + 1, + level_scale_power); + } + } + + // If individual samples within the limit of resolution, + // do a linear search for the next transition within the + // block + if (min_length < MipMapScaleFactor) { + for (; index < end; index++) { + const bool sample = (get_sample(index) & + sig_mask) != 0; + if (sample != last_sample) + break; + } + } + } + + //----- Store the edge -----// + + // Take the last sample of the quanization block + const int64_t final_index = index + block_length; + if (index + block_length > end) + break; + + // Store the final state + const bool final_sample = + (get_sample(final_index - 1) & sig_mask) != 0; + edges.push_back(pair(index, final_sample)); + + index = final_index; + last_sample = final_sample; + } + + // Add the final state + const bool end_sample = get_sample(end) & sig_mask; + if (last_sample != end_sample) + edges.push_back(pair(end, end_sample)); + edges.push_back(pair(end + 1, end_sample)); +} + +uint64_t LogicSegment::get_subsample(int level, uint64_t offset) const +{ + assert(level >= 0); + assert(mip_map_[level].data); + return unpack_sample((uint8_t*)mip_map_[level].data + + unit_size_ * offset); +} + +uint64_t LogicSegment::pow2_ceil(uint64_t x, unsigned int power) +{ + const uint64_t p = 1 << power; + return (x + p - 1) / p * p; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/logicsegment.hpp b/pv/data/logicsegment.hpp new file mode 100644 index 00000000..3e092c53 --- /dev/null +++ b/pv/data/logicsegment.hpp @@ -0,0 +1,119 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H +#define PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H + +#include "segment.hpp" + +#include +#include + +namespace sigrok { + class Logic; +} + +namespace LogicSegmentTest { +struct Pow2; +struct Basic; +struct LargeData; +struct Pulses; +struct LongPulses; +} + +namespace pv { +namespace data { + +class LogicSegment : public Segment +{ +private: + struct MipMapLevel + { + uint64_t length; + uint64_t data_length; + void *data; + }; + +private: + static const unsigned int ScaleStepCount = 10; + static const int MipMapScalePower; + static const int MipMapScaleFactor; + static const float LogMipMapScaleFactor; + static const uint64_t MipMapDataUnit; + +public: + typedef std::pair EdgePair; + +public: + LogicSegment(std::shared_ptr logic, + uint64_t samplerate, uint64_t expected_num_samples = 0); + + virtual ~LogicSegment(); + + void append_payload(std::shared_ptr logic); + + void get_samples(uint8_t *const data, + int64_t start_sample, int64_t end_sample) const; + +private: + uint64_t unpack_sample(const uint8_t *ptr) const; + void pack_sample(uint8_t *ptr, uint64_t value); + + void reallocate_mipmap_level(MipMapLevel &m); + + void append_payload_to_mipmap(); + + uint64_t get_sample(uint64_t index) const; + +public: + /** + * Parses a logic data segment to generate a list of transitions + * in a time interval to a given level of detail. + * @param[out] edges The vector to place the edges into. + * @param[in] start The start sample index. + * @param[in] end The end sample index. + * @param[in] min_length The minimum number of samples that + * can be resolved at this level of detail. + * @param[in] sig_index The index of the signal. + **/ + void get_subsampled_edges(std::vector &edges, + uint64_t start, uint64_t end, + float min_length, int sig_index); + +private: + uint64_t get_subsample(int level, uint64_t offset) const; + + static uint64_t pow2_ceil(uint64_t x, unsigned int power); + +private: + struct MipMapLevel mip_map_[ScaleStepCount]; + uint64_t last_append_sample_; + + friend struct LogicSegmentTest::Pow2; + friend struct LogicSegmentTest::Basic; + friend struct LogicSegmentTest::LargeData; + friend struct LogicSegmentTest::Pulses; + friend struct LogicSegmentTest::LongPulses; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H diff --git a/pv/data/logicsnapshot.cpp b/pv/data/logicsnapshot.cpp deleted file mode 100644 index a89c8f93..00000000 --- a/pv/data/logicsnapshot.cpp +++ /dev/null @@ -1,469 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include -#include -#include -#include - -#include "logicsnapshot.hpp" - -#include - -using std::lock_guard; -using std::recursive_mutex; -using std::max; -using std::min; -using std::pair; -using std::shared_ptr; - -using sigrok::Logic; - -namespace pv { -namespace data { - -const int LogicSnapshot::MipMapScalePower = 4; -const int LogicSnapshot::MipMapScaleFactor = 1 << MipMapScalePower; -const float LogicSnapshot::LogMipMapScaleFactor = logf(MipMapScaleFactor); -const uint64_t LogicSnapshot::MipMapDataUnit = 64*1024; // bytes - -LogicSnapshot::LogicSnapshot(shared_ptr logic, uint64_t samplerate, - const uint64_t expected_num_samples) : - Snapshot(samplerate, logic->unit_size()), - last_append_sample_(0) -{ - set_capacity(expected_num_samples); - - lock_guard lock(mutex_); - memset(mip_map_, 0, sizeof(mip_map_)); - append_payload(logic); -} - -LogicSnapshot::~LogicSnapshot() -{ - lock_guard lock(mutex_); - for (MipMapLevel &l : mip_map_) - free(l.data); -} - -uint64_t LogicSnapshot::unpack_sample(const uint8_t *ptr) const -{ -#ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS - return *(uint64_t*)ptr; -#else - uint64_t value = 0; - switch(unit_size_) { - default: - value |= ((uint64_t)ptr[7]) << 56; - /* FALLTHRU */ - case 7: - value |= ((uint64_t)ptr[6]) << 48; - /* FALLTHRU */ - case 6: - value |= ((uint64_t)ptr[5]) << 40; - /* FALLTHRU */ - case 5: - value |= ((uint64_t)ptr[4]) << 32; - /* FALLTHRU */ - case 4: - value |= ((uint32_t)ptr[3]) << 24; - /* FALLTHRU */ - case 3: - value |= ((uint32_t)ptr[2]) << 16; - /* FALLTHRU */ - case 2: - value |= ptr[1] << 8; - /* FALLTHRU */ - case 1: - value |= ptr[0]; - /* FALLTHRU */ - case 0: - break; - } - return value; -#endif -} - -void LogicSnapshot::pack_sample(uint8_t *ptr, uint64_t value) -{ -#ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS - *(uint64_t*)ptr = value; -#else - switch(unit_size_) { - default: - ptr[7] = value >> 56; - /* FALLTHRU */ - case 7: - ptr[6] = value >> 48; - /* FALLTHRU */ - case 6: - ptr[5] = value >> 40; - /* FALLTHRU */ - case 5: - ptr[4] = value >> 32; - /* FALLTHRU */ - case 4: - ptr[3] = value >> 24; - /* FALLTHRU */ - case 3: - ptr[2] = value >> 16; - /* FALLTHRU */ - case 2: - ptr[1] = value >> 8; - /* FALLTHRU */ - case 1: - ptr[0] = value; - /* FALLTHRU */ - case 0: - break; - } -#endif -} - -void LogicSnapshot::append_payload(shared_ptr logic) -{ - assert(unit_size_ == logic->unit_size()); - assert((logic->data_length() % unit_size_) == 0); - - lock_guard lock(mutex_); - - append_data(logic->data_pointer(), - logic->data_length() / unit_size_); - - // Generate the first mip-map from the data - append_payload_to_mipmap(); -} - -void LogicSnapshot::get_samples(uint8_t *const data, - int64_t start_sample, int64_t end_sample) const -{ - assert(data); - assert(start_sample >= 0); - assert(start_sample <= (int64_t)sample_count_); - assert(end_sample >= 0); - assert(end_sample <= (int64_t)sample_count_); - assert(start_sample <= end_sample); - - lock_guard lock(mutex_); - - const size_t size = (end_sample - start_sample) * unit_size_; - memcpy(data, (const uint8_t*)data_.data() + start_sample * unit_size_, size); -} - -void LogicSnapshot::reallocate_mipmap_level(MipMapLevel &m) -{ - const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) / - MipMapDataUnit) * MipMapDataUnit; - if (new_data_length > m.data_length) - { - m.data_length = new_data_length; - - // Padding is added to allow for the uint64_t write word - m.data = realloc(m.data, new_data_length * unit_size_ + - sizeof(uint64_t)); - } -} - -void LogicSnapshot::append_payload_to_mipmap() -{ - MipMapLevel &m0 = mip_map_[0]; - uint64_t prev_length; - const uint8_t *src_ptr; - uint8_t *dest_ptr; - uint64_t accumulator; - unsigned int diff_counter; - - // Expand the data buffer to fit the new samples - prev_length = m0.length; - m0.length = sample_count_ / MipMapScaleFactor; - - // Break off if there are no new samples to compute - if (m0.length == prev_length) - return; - - reallocate_mipmap_level(m0); - - dest_ptr = (uint8_t*)m0.data + prev_length * unit_size_; - - // Iterate through the samples to populate the first level mipmap - const uint8_t *const end_src_ptr = (uint8_t*)data_.data() + - m0.length * unit_size_ * MipMapScaleFactor; - for (src_ptr = (uint8_t*)data_.data() + - prev_length * unit_size_ * MipMapScaleFactor; - src_ptr < end_src_ptr;) - { - // Accumulate transitions which have occurred in this sample - accumulator = 0; - diff_counter = MipMapScaleFactor; - while (diff_counter-- > 0) - { - const uint64_t sample = unpack_sample(src_ptr); - accumulator |= last_append_sample_ ^ sample; - last_append_sample_ = sample; - src_ptr += unit_size_; - } - - pack_sample(dest_ptr, accumulator); - dest_ptr += unit_size_; - } - - // Compute higher level mipmaps - for (unsigned int level = 1; level < ScaleStepCount; level++) - { - MipMapLevel &m = mip_map_[level]; - const MipMapLevel &ml = mip_map_[level-1]; - - // Expand the data buffer to fit the new samples - prev_length = m.length; - m.length = ml.length / MipMapScaleFactor; - - // Break off if there are no more samples to computed - if (m.length == prev_length) - break; - - reallocate_mipmap_level(m); - - // Subsample the level lower level - src_ptr = (uint8_t*)ml.data + - unit_size_ * prev_length * MipMapScaleFactor; - const uint8_t *const end_dest_ptr = - (uint8_t*)m.data + unit_size_ * m.length; - for (dest_ptr = (uint8_t*)m.data + - unit_size_ * prev_length; - dest_ptr < end_dest_ptr; - dest_ptr += unit_size_) - { - accumulator = 0; - diff_counter = MipMapScaleFactor; - while (diff_counter-- > 0) - { - accumulator |= unpack_sample(src_ptr); - src_ptr += unit_size_; - } - - pack_sample(dest_ptr, accumulator); - } - } -} - -uint64_t LogicSnapshot::get_sample(uint64_t index) const -{ - assert(index < sample_count_); - - return unpack_sample((uint8_t*)data_.data() + index * unit_size_); -} - -void LogicSnapshot::get_subsampled_edges( - std::vector &edges, - uint64_t start, uint64_t end, - float min_length, int sig_index) -{ - uint64_t index = start; - unsigned int level; - bool last_sample; - bool fast_forward; - - assert(end <= get_sample_count()); - assert(start <= end); - assert(min_length > 0); - assert(sig_index >= 0); - assert(sig_index < 64); - - lock_guard lock(mutex_); - - const uint64_t block_length = (uint64_t)max(min_length, 1.0f); - const unsigned int min_level = max((int)floorf(logf(min_length) / - LogMipMapScaleFactor) - 1, 0); - const uint64_t sig_mask = 1ULL << sig_index; - - // Store the initial state - last_sample = (get_sample(start) & sig_mask) != 0; - edges.push_back(pair(index++, last_sample)); - - while (index + block_length <= end) - { - //----- Continue to search -----// - level = min_level; - - // We cannot fast-forward if there is no mip-map data at - // at the minimum level. - fast_forward = (mip_map_[level].data != NULL); - - if (min_length < MipMapScaleFactor) - { - // Search individual samples up to the beginning of - // the next first level mip map block - const uint64_t final_index = min(end, - pow2_ceil(index, MipMapScalePower)); - - for (; index < final_index && - (index & ~(~0 << MipMapScalePower)) != 0; - index++) - { - const bool sample = - (get_sample(index) & sig_mask) != 0; - - // If there was a change we cannot fast forward - if (sample != last_sample) { - fast_forward = false; - break; - } - } - } - else - { - // If resolution is less than a mip map block, - // round up to the beginning of the mip-map block - // for this level of detail - const int min_level_scale_power = - (level + 1) * MipMapScalePower; - index = pow2_ceil(index, min_level_scale_power); - if (index >= end) - break; - - // We can fast forward only if there was no change - const bool sample = - (get_sample(index) & sig_mask) != 0; - if (last_sample != sample) - fast_forward = false; - } - - if (fast_forward) { - - // Fast forward: This involves zooming out to higher - // levels of the mip map searching for changes, then - // zooming in on them to find the point where the edge - // begins. - - // Slide right and zoom out at the beginnings of mip-map - // blocks until we encounter a change - while (1) { - const int level_scale_power = - (level + 1) * MipMapScalePower; - const uint64_t offset = - index >> level_scale_power; - - // Check if we reached the last block at this - // level, or if there was a change in this block - if (offset >= mip_map_[level].length || - (get_subsample(level, offset) & - sig_mask)) - break; - - if ((offset & ~(~0 << MipMapScalePower)) == 0) { - // If we are now at the beginning of a - // higher level mip-map block ascend one - // level - if (level + 1 >= ScaleStepCount || - !mip_map_[level + 1].data) - break; - - level++; - } else { - // Slide right to the beginning of the - // next mip map block - index = pow2_ceil(index + 1, - level_scale_power); - } - } - - // Zoom in, and slide right until we encounter a change, - // and repeat until we reach min_level - while (1) { - assert(mip_map_[level].data); - - const int level_scale_power = - (level + 1) * MipMapScalePower; - const uint64_t offset = - index >> level_scale_power; - - // Check if we reached the last block at this - // level, or if there was a change in this block - if (offset >= mip_map_[level].length || - (get_subsample(level, offset) & - sig_mask)) { - // Zoom in unless we reached the minimum - // zoom - if (level == min_level) - break; - - level--; - } else { - // Slide right to the beginning of the - // next mip map block - index = pow2_ceil(index + 1, - level_scale_power); - } - } - - // If individual samples within the limit of resolution, - // do a linear search for the next transition within the - // block - if (min_length < MipMapScaleFactor) { - for (; index < end; index++) { - const bool sample = (get_sample(index) & - sig_mask) != 0; - if (sample != last_sample) - break; - } - } - } - - //----- Store the edge -----// - - // Take the last sample of the quanization block - const int64_t final_index = index + block_length; - if (index + block_length > end) - break; - - // Store the final state - const bool final_sample = - (get_sample(final_index - 1) & sig_mask) != 0; - edges.push_back(pair(index, final_sample)); - - index = final_index; - last_sample = final_sample; - } - - // Add the final state - const bool end_sample = get_sample(end) & sig_mask; - if (last_sample != end_sample) - edges.push_back(pair(end, end_sample)); - edges.push_back(pair(end + 1, end_sample)); -} - -uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const -{ - assert(level >= 0); - assert(mip_map_[level].data); - return unpack_sample((uint8_t*)mip_map_[level].data + - unit_size_ * offset); -} - -uint64_t LogicSnapshot::pow2_ceil(uint64_t x, unsigned int power) -{ - const uint64_t p = 1 << power; - return (x + p - 1) / p * p; -} - -} // namespace data -} // namespace pv diff --git a/pv/data/logicsnapshot.hpp b/pv/data/logicsnapshot.hpp deleted file mode 100644 index 8b1481ab..00000000 --- a/pv/data/logicsnapshot.hpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H -#define PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H - -#include "snapshot.hpp" - -#include -#include - -namespace sigrok { - class Logic; -} - -namespace LogicSnapshotTest { -struct Pow2; -struct Basic; -struct LargeData; -struct Pulses; -struct LongPulses; -} - -namespace pv { -namespace data { - -class LogicSnapshot : public Snapshot -{ -private: - struct MipMapLevel - { - uint64_t length; - uint64_t data_length; - void *data; - }; - -private: - static const unsigned int ScaleStepCount = 10; - static const int MipMapScalePower; - static const int MipMapScaleFactor; - static const float LogMipMapScaleFactor; - static const uint64_t MipMapDataUnit; - -public: - typedef std::pair EdgePair; - -public: - LogicSnapshot(std::shared_ptr logic, - uint64_t samplerate, uint64_t expected_num_samples = 0); - - virtual ~LogicSnapshot(); - - void append_payload(std::shared_ptr logic); - - void get_samples(uint8_t *const data, - int64_t start_sample, int64_t end_sample) const; - -private: - uint64_t unpack_sample(const uint8_t *ptr) const; - void pack_sample(uint8_t *ptr, uint64_t value); - - void reallocate_mipmap_level(MipMapLevel &m); - - void append_payload_to_mipmap(); - - uint64_t get_sample(uint64_t index) const; - -public: - /** - * Parses a logic data snapshot to generate a list of transitions - * in a time interval to a given level of detail. - * @param[out] edges The vector to place the edges into. - * @param[in] start The start sample index. - * @param[in] end The end sample index. - * @param[in] min_length The minimum number of samples that - * can be resolved at this level of detail. - * @param[in] sig_index The index of the signal. - **/ - void get_subsampled_edges(std::vector &edges, - uint64_t start, uint64_t end, - float min_length, int sig_index); - -private: - uint64_t get_subsample(int level, uint64_t offset) const; - - static uint64_t pow2_ceil(uint64_t x, unsigned int power); - -private: - struct MipMapLevel mip_map_[ScaleStepCount]; - uint64_t last_append_sample_; - - friend struct LogicSnapshotTest::Pow2; - friend struct LogicSnapshotTest::Basic; - friend struct LogicSnapshotTest::LargeData; - friend struct LogicSnapshotTest::Pulses; - friend struct LogicSnapshotTest::LongPulses; -}; - -} // namespace data -} // namespace pv - -#endif // PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H diff --git a/pv/data/segment.cpp b/pv/data/segment.cpp new file mode 100644 index 00000000..111b62b7 --- /dev/null +++ b/pv/data/segment.cpp @@ -0,0 +1,110 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "segment.hpp" + +#include +#include +#include + +using std::lock_guard; +using std::recursive_mutex; + +namespace pv { +namespace data { + +Segment::Segment(uint64_t samplerate, unsigned int unit_size) : + sample_count_(0), + start_time_(0), + samplerate_(samplerate), + capacity_(0), + unit_size_(unit_size) +{ + lock_guard lock(mutex_); + assert(unit_size_ > 0); +} + +Segment::~Segment() +{ + lock_guard lock(mutex_); +} + +uint64_t Segment::get_sample_count() const +{ + lock_guard lock(mutex_); + return sample_count_; +} + +double Segment::start_time() const +{ + return start_time_; +} + +double Segment::samplerate() const +{ + return samplerate_; +} + +void Segment::set_samplerate(double samplerate) +{ + samplerate_ = samplerate; +} + +unsigned int Segment::unit_size() const +{ + return unit_size_; +} + +void Segment::set_capacity(const uint64_t new_capacity) +{ + lock_guard lock(mutex_); + + assert(capacity_ >= sample_count_); + if (new_capacity > capacity_) { + capacity_ = new_capacity; + data_.resize((new_capacity * unit_size_) + sizeof(uint64_t)); + } +} + +uint64_t Segment::capacity() const +{ + lock_guard lock(mutex_); + return data_.size(); +} + +void Segment::append_data(void *data, uint64_t samples) +{ + lock_guard lock(mutex_); + + assert(capacity_ >= sample_count_); + + // Ensure there's enough capacity to copy. + const uint64_t free_space = capacity_ - sample_count_; + if (free_space < samples) { + set_capacity(sample_count_ + samples); + } + + memcpy((uint8_t*)data_.data() + sample_count_ * unit_size_, + data, samples * unit_size_); + sample_count_ += samples; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/segment.hpp b/pv/data/segment.hpp new file mode 100644 index 00000000..a754eab2 --- /dev/null +++ b/pv/data/segment.hpp @@ -0,0 +1,90 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_SNAPSHOT_H +#define PULSEVIEW_PV_DATA_SNAPSHOT_H + +#include +#include +#include + +namespace pv { +namespace data { + +class Segment +{ +public: + Segment(uint64_t samplerate, unsigned int unit_size); + + virtual ~Segment(); + + uint64_t get_sample_count() const; + + double start_time() const; + + double samplerate() const; + void set_samplerate(double samplerate); + + unsigned int unit_size() const; + + /** + * @brief Increase the capacity of the segment. + * + * Increasing the capacity allows samples to be appended without needing + * to reallocate memory. + * + * For the best efficiency @c set_capacity() should be called once before + * @c append_data() is called to set up the segment with the expected number + * of samples that will be appended in total. + * + * @note The capacity will automatically be increased when @c append_data() + * is called if there is not enough capacity in the buffer to store the samples. + * + * @param[in] new_capacity The new capacity of the segment. If this value is + * smaller or equal than the current capacity then the method has no effect. + */ + void set_capacity(uint64_t new_capacity); + + /** + * @brief Get the current capacity of the segment. + * + * The capacity can be increased by calling @c set_capacity(). + * + * @return The current capacity of the segment. + */ + uint64_t capacity() const; + +protected: + void append_data(void *data, uint64_t samples); + +protected: + mutable std::recursive_mutex mutex_; + std::vector data_; + uint64_t sample_count_; + double start_time_; + double samplerate_; + uint64_t capacity_; + unsigned int unit_size_; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_SNAPSHOT_H diff --git a/pv/data/signaldata.hpp b/pv/data/signaldata.hpp index 51589771..c49cb5c0 100644 --- a/pv/data/signaldata.hpp +++ b/pv/data/signaldata.hpp @@ -28,7 +28,7 @@ namespace pv { namespace data { -class Snapshot; +class Segment; class SignalData { @@ -37,7 +37,7 @@ public: virtual ~SignalData() {} public: - virtual std::vector< std::shared_ptr > snapshots() const = 0; + virtual std::vector< std::shared_ptr > segments() const = 0; virtual void clear() = 0; diff --git a/pv/data/snapshot.cpp b/pv/data/snapshot.cpp deleted file mode 100644 index 39fdc011..00000000 --- a/pv/data/snapshot.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "snapshot.hpp" - -#include -#include -#include - -using std::lock_guard; -using std::recursive_mutex; - -namespace pv { -namespace data { - -Snapshot::Snapshot(uint64_t samplerate, unsigned int unit_size) : - sample_count_(0), - start_time_(0), - samplerate_(samplerate), - capacity_(0), - unit_size_(unit_size) -{ - lock_guard lock(mutex_); - assert(unit_size_ > 0); -} - -Snapshot::~Snapshot() -{ - lock_guard lock(mutex_); -} - -uint64_t Snapshot::get_sample_count() const -{ - lock_guard lock(mutex_); - return sample_count_; -} - -double Snapshot::start_time() const -{ - return start_time_; -} - -double Snapshot::samplerate() const -{ - return samplerate_; -} - -void Snapshot::set_samplerate(double samplerate) -{ - samplerate_ = samplerate; -} - -unsigned int Snapshot::unit_size() const -{ - return unit_size_; -} - -void Snapshot::set_capacity(const uint64_t new_capacity) -{ - lock_guard lock(mutex_); - - assert(capacity_ >= sample_count_); - if (new_capacity > capacity_) { - capacity_ = new_capacity; - data_.resize((new_capacity * unit_size_) + sizeof(uint64_t)); - } -} - -uint64_t Snapshot::capacity() const -{ - lock_guard lock(mutex_); - return data_.size(); -} - -void Snapshot::append_data(void *data, uint64_t samples) -{ - lock_guard lock(mutex_); - - assert(capacity_ >= sample_count_); - - // Ensure there's enough capacity to copy. - const uint64_t free_space = capacity_ - sample_count_; - if (free_space < samples) { - set_capacity(sample_count_ + samples); - } - - memcpy((uint8_t*)data_.data() + sample_count_ * unit_size_, - data, samples * unit_size_); - sample_count_ += samples; -} - -} // namespace data -} // namespace pv diff --git a/pv/data/snapshot.hpp b/pv/data/snapshot.hpp deleted file mode 100644 index 6015de9e..00000000 --- a/pv/data/snapshot.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_DATA_SNAPSHOT_H -#define PULSEVIEW_PV_DATA_SNAPSHOT_H - -#include -#include -#include - -namespace pv { -namespace data { - -class Snapshot -{ -public: - Snapshot(uint64_t samplerate, unsigned int unit_size); - - virtual ~Snapshot(); - - uint64_t get_sample_count() const; - - double start_time() const; - - double samplerate() const; - void set_samplerate(double samplerate); - - unsigned int unit_size() const; - - /** - * @brief Increase the capacity of the snapshot. - * - * Increasing the capacity allows samples to be appended without needing - * to reallocate memory. - * - * For the best efficiency @c set_capacity() should be called once before - * @c append_data() is called to set up the snapshot with the expected number - * of samples that will be appended in total. - * - * @note The capacity will automatically be increased when @c append_data() - * is called if there is not enough capacity in the buffer to store the samples. - * - * @param[in] new_capacity The new capacity of the snapshot. If this value is - * smaller or equal than the current capacity then the method has no effect. - */ - void set_capacity(uint64_t new_capacity); - - /** - * @brief Get the current capacity of the snapshot. - * - * The capacity can be increased by calling @c set_capacity(). - * - * @return The current capacity of the snapshot. - */ - uint64_t capacity() const; - -protected: - void append_data(void *data, uint64_t samples); - -protected: - mutable std::recursive_mutex mutex_; - std::vector data_; - uint64_t sample_count_; - double start_time_; - double samplerate_; - uint64_t capacity_; - unsigned int unit_size_; -}; - -} // namespace data -} // namespace pv - -#endif // PULSEVIEW_PV_DATA_SNAPSHOT_H diff --git a/pv/session.cpp b/pv/session.cpp index 46af90cc..7bb9de8d 100644 --- a/pv/session.cpp +++ b/pv/session.cpp @@ -27,10 +27,10 @@ #include "devicemanager.hpp" #include "data/analog.hpp" -#include "data/analogsnapshot.hpp" +#include "data/analogsegment.hpp" #include "data/decoderstack.hpp" #include "data/logic.hpp" -#include "data/logicsnapshot.hpp" +#include "data/logicsegment.hpp" #include "data/decode/decoder.hpp" #include "view/analogsignal.hpp" @@ -364,7 +364,7 @@ void Session::update_signals(shared_ptr device) [] (shared_ptr channel) { return channel->type() == ChannelType::LOGIC; }); - // Create data containers for the logic data snapshots + // Create data containers for the logic data segments { lock_guard data_lock(data_mutex_); @@ -460,7 +460,7 @@ void Session::sample_thread_proc(shared_ptr device, set_capture_state(Stopped); // Confirm that SR_DF_END was received - if (cur_logic_snapshot_) + if (cur_logic_segment_) { qDebug("SR_DF_END was not received."); assert(0); @@ -493,7 +493,7 @@ void Session::feed_in_meta(shared_ptr device, void Session::feed_in_frame_begin() { - if (cur_logic_snapshot_ || !cur_analog_snapshots_.empty()) + if (cur_logic_segment_ || !cur_analog_segments_.empty()) frame_began(); } @@ -507,7 +507,7 @@ void Session::feed_in_logic(shared_ptr logic) return; } - if (!cur_logic_snapshot_) + if (!cur_logic_segment_) { // This could be the first packet after a trigger set_capture_state(Running); @@ -522,11 +522,11 @@ void Session::feed_in_logic(shared_ptr logic) VariantBase::cast_dynamic>( device_->config_get(ConfigKey::LIMIT_SAMPLES)).get() : 0; - // Create a new data snapshot - cur_logic_snapshot_ = shared_ptr( - new data::LogicSnapshot( + // Create a new data segment + cur_logic_segment_ = shared_ptr( + new data::LogicSegment( logic, cur_samplerate_, sample_limit)); - logic_data_->push_snapshot(cur_logic_snapshot_); + logic_data_->push_segment(cur_logic_segment_); // @todo Putting this here means that only listeners querying // for logic will be notified. Currently the only user of @@ -536,8 +536,8 @@ void Session::feed_in_logic(shared_ptr logic) } else { - // Append to the existing data snapshot - cur_logic_snapshot_->append_payload(logic); + // Append to the existing data segment + cur_logic_segment_->append_payload(logic); } data_received(); @@ -555,18 +555,18 @@ void Session::feed_in_analog(shared_ptr analog) for (auto channel : channels) { - shared_ptr snapshot; + shared_ptr segment; - // Try to get the snapshot of the channel - const map< shared_ptr, shared_ptr >:: - iterator iter = cur_analog_snapshots_.find(channel); - if (iter != cur_analog_snapshots_.end()) - snapshot = (*iter).second; + // Try to get the segment of the channel + const map< shared_ptr, shared_ptr >:: + iterator iter = cur_analog_segments_.find(channel); + if (iter != cur_analog_segments_.end()) + segment = (*iter).second; else { - // If no snapshot was found, this means we havn't + // If no segment was found, this means we havn't // created one yet. i.e. this is the first packet - // in the sweep containing this snapshot. + // in the sweep containing this segment. sweep_beginning = true; // Get sample limit. @@ -578,11 +578,11 @@ void Session::feed_in_analog(shared_ptr analog) sample_limit = 0; } - // Create a snapshot, keep it in the maps of channels - snapshot = shared_ptr( - new data::AnalogSnapshot( + // Create a segment, keep it in the maps of channels + segment = shared_ptr( + new data::AnalogSegment( cur_samplerate_, sample_limit)); - cur_analog_snapshots_[channel] = snapshot; + cur_analog_segments_[channel] = segment; // Find the annalog data associated with the channel shared_ptr sig = @@ -593,14 +593,14 @@ void Session::feed_in_analog(shared_ptr analog) shared_ptr data(sig->analog_data()); assert(data); - // Push the snapshot into the analog data. - data->push_snapshot(snapshot); + // Push the segment into the analog data. + data->push_segment(segment); } - assert(snapshot); + assert(segment); - // Append the samples in the snapshot - snapshot->append_interleaved_samples(data++, sample_count, + // Append the samples in the segment + segment->append_interleaved_samples(data++, sample_count, channel_count); } @@ -642,8 +642,8 @@ void Session::data_feed_in(shared_ptr device, shared_ptr packet) { { lock_guard lock(data_mutex_); - cur_logic_snapshot_.reset(); - cur_analog_snapshots_.clear(); + cur_logic_segment_.reset(); + cur_analog_segments_.clear(); } frame_ended(); break; diff --git a/pv/session.hpp b/pv/session.hpp index 556f54e5..ba07fdcf 100644 --- a/pv/session.hpp +++ b/pv/session.hpp @@ -53,9 +53,9 @@ class DeviceManager; namespace data { class Analog; -class AnalogSnapshot; +class AnalogSegment; class Logic; -class LogicSnapshot; +class LogicSegment; class SignalData; } @@ -167,9 +167,9 @@ private: mutable std::mutex data_mutex_; std::shared_ptr logic_data_; uint64_t cur_samplerate_; - std::shared_ptr cur_logic_snapshot_; - std::map< std::shared_ptr, std::shared_ptr > - cur_analog_snapshots_; + std::shared_ptr cur_logic_segment_; + std::map< std::shared_ptr, std::shared_ptr > + cur_analog_segments_; std::thread sampling_thread_; diff --git a/pv/storesession.cpp b/pv/storesession.cpp index af599db0..6ecde13a 100644 --- a/pv/storesession.cpp +++ b/pv/storesession.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include @@ -106,17 +106,17 @@ bool StoreSession::start() return false; } - // Get the snapshot - const deque< shared_ptr > &snapshots = - data->logic_snapshots(); + // Get the segment + const deque< shared_ptr > &segments = + data->logic_segments(); - if (snapshots.empty()) { - error_ = tr("No snapshots to save."); + if (segments.empty()) { + error_ = tr("No segments to save."); return false; } - const shared_ptr snapshot(snapshots.front()); - assert(snapshot); + const shared_ptr segment(segments.front()); + assert(segment); // Begin storing try { @@ -128,14 +128,14 @@ bool StoreSession::start() Glib::Variant::create(file_name_)}}); auto meta = context->create_meta_packet( {{ConfigKey::SAMPLERATE, Glib::Variant::create( - snapshot->samplerate())}}); + segment->samplerate())}}); output_->receive(meta); } catch (Error error) { error_ = tr("Error while saving."); return false; } - thread_ = std::thread(&StoreSession::store_proc, this, snapshot); + thread_ = std::thread(&StoreSession::store_proc, this, segment); return true; } @@ -150,9 +150,9 @@ void StoreSession::cancel() interrupt_ = true; } -void StoreSession::store_proc(shared_ptr snapshot) +void StoreSession::store_proc(shared_ptr segment) { - assert(snapshot); + assert(segment); uint64_t start_sample = 0, sample_count; unsigned progress_scale = 0; @@ -161,10 +161,10 @@ void StoreSession::store_proc(shared_ptr snapshot) uint8_t *const data = new uint8_t[BlockSize]; assert(data); - const int unit_size = snapshot->unit_size(); + const int unit_size = segment->unit_size(); assert(unit_size != 0); - sample_count = snapshot->get_sample_count(); + sample_count = segment->get_sample_count(); // Qt needs the progress values to fit inside an int. If they would // not, scale the current and max values down until they do. @@ -181,7 +181,7 @@ void StoreSession::store_proc(shared_ptr snapshot) const uint64_t end_sample = min( start_sample + samples_per_block, sample_count); - snapshot->get_samples(data, start_sample, end_sample); + segment->get_samples(data, start_sample, end_sample); size_t length = end_sample - start_sample; diff --git a/pv/storesession.hpp b/pv/storesession.hpp index 62cf1895..9094ca12 100644 --- a/pv/storesession.hpp +++ b/pv/storesession.hpp @@ -39,7 +39,7 @@ namespace pv { class Session; namespace data { -class LogicSnapshot; +class LogicSegment; } class StoreSession : public QObject @@ -66,7 +66,7 @@ public: void cancel(); private: - void store_proc(std::shared_ptr snapshot); + void store_proc(std::shared_ptr segment); Q_SIGNALS: void progress_updated(); diff --git a/pv/view/analogsignal.cpp b/pv/view/analogsignal.cpp index e559a4a4..5b6d8a50 100644 --- a/pv/view/analogsignal.cpp +++ b/pv/view/analogsignal.cpp @@ -25,7 +25,7 @@ #include "analogsignal.hpp" #include "pv/data/analog.hpp" -#include "pv/data/analogsnapshot.hpp" +#include "pv/data/analogsegment.hpp" #include "pv/view/view.hpp" #include @@ -103,18 +103,18 @@ void AnalogSignal::paint_mid(QPainter &p, const RowItemPaintParams &pp) if (!channel_->enabled()) return; - const deque< shared_ptr > &snapshots = - data_->analog_snapshots(); - if (snapshots.empty()) + const deque< shared_ptr > &segments = + data_->analog_segments(); + if (segments.empty()) return; - const shared_ptr &snapshot = - snapshots.front(); + const shared_ptr &segment = + segments.front(); const double pixels_offset = pp.pixels_offset(); - const double samplerate = snapshot->samplerate(); - const double start_time = snapshot->start_time(); - const int64_t last_sample = snapshot->get_sample_count() - 1; + const double samplerate = segment->samplerate(); + const double start_time = segment->start_time(); + const int64_t last_sample = segment->get_sample_count() - 1; const double samples_per_pixel = samplerate * pp.scale(); const double start = samplerate * (pp.offset() - start_time); const double end = start + samples_per_pixel * pp.width(); @@ -125,23 +125,23 @@ void AnalogSignal::paint_mid(QPainter &p, const RowItemPaintParams &pp) (int64_t)0), last_sample); if (samples_per_pixel < EnvelopeThreshold) - paint_trace(p, snapshot, y, pp.left(), + paint_trace(p, segment, y, pp.left(), start_sample, end_sample, pixels_offset, samples_per_pixel); else - paint_envelope(p, snapshot, y, pp.left(), + paint_envelope(p, segment, y, pp.left(), start_sample, end_sample, pixels_offset, samples_per_pixel); } void AnalogSignal::paint_trace(QPainter &p, - const shared_ptr &snapshot, + const shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel) { const int64_t sample_count = end - start; - const float *const samples = snapshot->get_samples(start, end); + const float *const samples = segment->get_samples(start, end); assert(samples); p.setPen(colour_); @@ -163,14 +163,14 @@ void AnalogSignal::paint_trace(QPainter &p, } void AnalogSignal::paint_envelope(QPainter &p, - const shared_ptr &snapshot, + const shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel) { - using pv::data::AnalogSnapshot; + using pv::data::AnalogSegment; - AnalogSnapshot::EnvelopeSection e; - snapshot->get_envelope_section(e, start, end, samples_per_pixel); + AnalogSegment::EnvelopeSection e; + segment->get_envelope_section(e, start, end, samples_per_pixel); if (e.length < 2) return; @@ -184,7 +184,7 @@ void AnalogSignal::paint_envelope(QPainter &p, for(uint64_t sample = 0; sample < e.length-1; sample++) { const float x = ((e.scale * sample + e.start) / samples_per_pixel - pixels_offset) + left; - const AnalogSnapshot::EnvelopeSample *const s = + const AnalogSegment::EnvelopeSample *const s = e.samples + sample; // We overlap this sample with the next so that vertical diff --git a/pv/view/analogsignal.hpp b/pv/view/analogsignal.hpp index c048371e..ad2b25ae 100644 --- a/pv/view/analogsignal.hpp +++ b/pv/view/analogsignal.hpp @@ -29,7 +29,7 @@ namespace pv { namespace data { class Analog; -class AnalogSnapshot; +class AnalogSegment; } namespace view { @@ -77,12 +77,12 @@ public: private: void paint_trace(QPainter &p, - const std::shared_ptr &snapshot, + const std::shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel); void paint_envelope(QPainter &p, - const std::shared_ptr &snapshot, + const std::shared_ptr &segment, int y, int left, const int64_t start, const int64_t end, const double pixels_offset, const double samples_per_pixel); diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp index bdae3952..5392b17e 100644 --- a/pv/view/decodetrace.cpp +++ b/pv/view/decodetrace.cpp @@ -45,7 +45,7 @@ extern "C" { #include #include #include -#include +#include #include #include #include @@ -474,20 +474,20 @@ void DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left, // We get the logic data of the first channel in the list. // This works because we are currently assuming all - // LogicSignals have the same data/snapshot + // LogicSignals have the same data/segment for (const shared_ptr &dec : stack) if (dec && !dec->channels().empty() && ((logic_signal = (*dec->channels().begin()).second)) && ((data = logic_signal->logic_data()))) break; - if (!data || data->logic_snapshots().empty()) + if (!data || data->logic_segments().empty()) return; - const shared_ptr snapshot = - data->logic_snapshots().front(); - assert(snapshot); - const int64_t sample_count = (int64_t)snapshot->get_sample_count(); + const shared_ptr segment = + data->logic_segments().front(); + assert(segment); + const int64_t sample_count = (int64_t)segment->get_sample_count(); if (sample_count == 0) return; diff --git a/pv/view/logicsignal.cpp b/pv/view/logicsignal.cpp index b1aaae8f..48d2debc 100644 --- a/pv/view/logicsignal.cpp +++ b/pv/view/logicsignal.cpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -169,28 +169,28 @@ void LogicSignal::paint_mid(QPainter &p, const RowItemPaintParams &pp) const float high_offset = y - SignalHeight + 0.5f; const float low_offset = y + 0.5f; - const deque< shared_ptr > &snapshots = - data_->logic_snapshots(); - if (snapshots.empty()) + const deque< shared_ptr > &segments = + data_->logic_segments(); + if (segments.empty()) return; - const shared_ptr &snapshot = - snapshots.front(); + const shared_ptr &segment = + segments.front(); - double samplerate = snapshot->samplerate(); + double samplerate = segment->samplerate(); // Show sample rate as 1Hz when it is unknown if (samplerate == 0.0) samplerate = 1.0; const double pixels_offset = pp.pixels_offset(); - const double start_time = snapshot->start_time(); - const int64_t last_sample = snapshot->get_sample_count() - 1; + const double start_time = segment->start_time(); + const int64_t last_sample = segment->get_sample_count() - 1; const double samples_per_pixel = samplerate * pp.scale(); const double start = samplerate * (pp.offset() - start_time); const double end = start + samples_per_pixel * pp.width(); - snapshot->get_subsampled_edges(edges, + segment->get_subsampled_edges(edges, min(max((int64_t)floor(start), (int64_t)0), last_sample), min(max((int64_t)ceil(end), (int64_t)0), last_sample), samples_per_pixel / Oversampling, channel_->index()); diff --git a/pv/view/view.cpp b/pv/view/view.cpp index e0c49c20..03848478 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -50,14 +50,14 @@ #include "pv/session.hpp" #include "pv/data/logic.hpp" -#include "pv/data/logicsnapshot.hpp" +#include "pv/data/logicsegment.hpp" #include "pv/util.hpp" using boost::shared_lock; using boost::shared_mutex; using pv::data::SignalData; -using pv::data::Snapshot; +using pv::data::Segment; using pv::util::format_time; using std::back_inserter; @@ -263,9 +263,9 @@ void View::zoom_one_to_one() double samplerate = 0.0; for (const shared_ptr d : visible_data) { assert(d); - const vector< shared_ptr > snapshots = - d->snapshots(); - for (const shared_ptr &s : snapshots) + const vector< shared_ptr > segments = + d->segments(); + for (const shared_ptr &s : segments) samplerate = max(samplerate, s->samplerate()); } @@ -314,9 +314,9 @@ pair View::get_time_extents() const const set< shared_ptr > visible_data = get_visible_data(); for (const shared_ptr d : visible_data) { - const vector< shared_ptr > snapshots = - d->snapshots(); - for (const shared_ptr &s : snapshots) { + const vector< shared_ptr > segments = + d->segments(); + for (const shared_ptr &s : segments) { double samplerate = s->samplerate(); samplerate = (samplerate <= 0.0) ? 1.0 : samplerate; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 891d22cb..b0b0b551 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,11 +24,11 @@ set(pulseview_TEST_SOURCES ${PROJECT_SOURCE_DIR}/pv/storesession.cpp ${PROJECT_SOURCE_DIR}/pv/util.cpp ${PROJECT_SOURCE_DIR}/pv/data/analog.cpp - ${PROJECT_SOURCE_DIR}/pv/data/analogsnapshot.cpp + ${PROJECT_SOURCE_DIR}/pv/data/analogsegment.cpp ${PROJECT_SOURCE_DIR}/pv/data/logic.cpp - ${PROJECT_SOURCE_DIR}/pv/data/logicsnapshot.cpp + ${PROJECT_SOURCE_DIR}/pv/data/logicsegment.cpp + ${PROJECT_SOURCE_DIR}/pv/data/segment.cpp ${PROJECT_SOURCE_DIR}/pv/data/signaldata.cpp - ${PROJECT_SOURCE_DIR}/pv/data/snapshot.cpp ${PROJECT_SOURCE_DIR}/pv/prop/bool.cpp ${PROJECT_SOURCE_DIR}/pv/prop/double.cpp ${PROJECT_SOURCE_DIR}/pv/prop/enum.cpp @@ -63,8 +63,8 @@ set(pulseview_TEST_SOURCES ${PROJECT_SOURCE_DIR}/pv/widgets/popuptoolbutton.cpp ${PROJECT_SOURCE_DIR}/pv/widgets/sweeptimingwidget.cpp ${PROJECT_SOURCE_DIR}/pv/widgets/wellarray.cpp - data/analogsnapshot.cpp - data/logicsnapshot.cpp + data/analogsegment.cpp + data/logicsegment.cpp test.cpp ) diff --git a/test/data/analogsegment.cpp b/test/data/analogsegment.cpp new file mode 100644 index 00000000..fd7b8870 --- /dev/null +++ b/test/data/analogsegment.cpp @@ -0,0 +1,116 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include + +#include + +#include + +using pv::data::AnalogSegment; + +#if 0 +BOOST_AUTO_TEST_SUITE(AnalogSegmentTest) + +void push_analog(AnalogSegment &s, unsigned int num_samples, + float value) +{ + float *const data = new float[num_samples]; + for (unsigned int i = 0; i < num_samples; i++) + data[i] = value; + + s.append_interleaved_samples(data, num_samples, 1); + delete[] data; +} + +BOOST_AUTO_TEST_CASE(Basic) +{ + // Create an empty AnalogSegment object + AnalogSegment s; + + //----- Test AnalogSegment::push_analog -----// + + BOOST_CHECK(s.get_sample_count() == 0); + for (unsigned int i = 0; i < AnalogSegment::ScaleStepCount; i++) + { + const AnalogSegment::Envelope &m = s.envelope_levels_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.samples == NULL); + } + + // Push 8 samples of all zeros + push_analog(s, 8, 0.0f); + + BOOST_CHECK(s.get_sample_count() == 8); + + // There should not be enough samples to have a single mip map sample + for (unsigned int i = 0; i < AnalogSegment::ScaleStepCount; i++) + { + const AnalogSegment::Envelope &m = s.envelope_levels_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.samples == NULL); + } + + // Push 8 samples of 1.0s to bring the total up to 16 + push_analog(s, 8, 1.0f); + + // There should now be enough data for exactly one sample + // in mip map level 0, and that sample should be 0 + const AnalogSegment::Envelope &e0 = s.envelope_levels_[0]; + BOOST_CHECK_EQUAL(e0.length, 1); + BOOST_CHECK_EQUAL(e0.data_length, AnalogSegment::EnvelopeDataUnit); + BOOST_REQUIRE(e0.samples != NULL); + BOOST_CHECK_EQUAL(e0.samples[0].min, 0.0f); + BOOST_CHECK_EQUAL(e0.samples[0].max, 1.0f); + + // The higher levels should still be empty + for (unsigned int i = 1; i < AnalogSegment::ScaleStepCount; i++) + { + const AnalogSegment::Envelope &m = s.envelope_levels_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.samples == NULL); + } + + // Push 240 samples of all zeros to bring the total up to 256 + push_analog(s, 240, -1.0f); + + BOOST_CHECK_EQUAL(e0.length, 16); + BOOST_CHECK_EQUAL(e0.data_length, AnalogSegment::EnvelopeDataUnit); + + for (unsigned int i = 1; i < e0.length; i++) { + BOOST_CHECK_EQUAL(e0.samples[i].min, -1.0f); + BOOST_CHECK_EQUAL(e0.samples[i].max, -1.0f); + } + + const AnalogSegment::Envelope &e1 = s.envelope_levels_[1]; + BOOST_CHECK_EQUAL(e1.length, 1); + BOOST_CHECK_EQUAL(e1.data_length, AnalogSegment::EnvelopeDataUnit); + BOOST_REQUIRE(e1.samples != NULL); + BOOST_CHECK_EQUAL(e1.samples[0].min, -1.0f); + BOOST_CHECK_EQUAL(e1.samples[0].max, 1.0f); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif diff --git a/test/data/analogsnapshot.cpp b/test/data/analogsnapshot.cpp deleted file mode 100644 index ff2b7208..00000000 --- a/test/data/analogsnapshot.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2013 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include - -#include - -#include - -using pv::data::AnalogSnapshot; - -#if 0 -BOOST_AUTO_TEST_SUITE(AnalogSnapshotTest) - -void push_analog(AnalogSnapshot &s, unsigned int num_samples, - float value) -{ - float *const data = new float[num_samples]; - for (unsigned int i = 0; i < num_samples; i++) - data[i] = value; - - s.append_interleaved_samples(data, num_samples, 1); - delete[] data; -} - -BOOST_AUTO_TEST_CASE(Basic) -{ - // Create an empty AnalogSnapshot object - AnalogSnapshot s; - - //----- Test AnalogSnapshot::push_analog -----// - - BOOST_CHECK(s.get_sample_count() == 0); - for (unsigned int i = 0; i < AnalogSnapshot::ScaleStepCount; i++) - { - const AnalogSnapshot::Envelope &m = s.envelope_levels_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.samples == NULL); - } - - // Push 8 samples of all zeros - push_analog(s, 8, 0.0f); - - BOOST_CHECK(s.get_sample_count() == 8); - - // There should not be enough samples to have a single mip map sample - for (unsigned int i = 0; i < AnalogSnapshot::ScaleStepCount; i++) - { - const AnalogSnapshot::Envelope &m = s.envelope_levels_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.samples == NULL); - } - - // Push 8 samples of 1.0s to bring the total up to 16 - push_analog(s, 8, 1.0f); - - // There should now be enough data for exactly one sample - // in mip map level 0, and that sample should be 0 - const AnalogSnapshot::Envelope &e0 = s.envelope_levels_[0]; - BOOST_CHECK_EQUAL(e0.length, 1); - BOOST_CHECK_EQUAL(e0.data_length, AnalogSnapshot::EnvelopeDataUnit); - BOOST_REQUIRE(e0.samples != NULL); - BOOST_CHECK_EQUAL(e0.samples[0].min, 0.0f); - BOOST_CHECK_EQUAL(e0.samples[0].max, 1.0f); - - // The higher levels should still be empty - for (unsigned int i = 1; i < AnalogSnapshot::ScaleStepCount; i++) - { - const AnalogSnapshot::Envelope &m = s.envelope_levels_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.samples == NULL); - } - - // Push 240 samples of all zeros to bring the total up to 256 - push_analog(s, 240, -1.0f); - - BOOST_CHECK_EQUAL(e0.length, 16); - BOOST_CHECK_EQUAL(e0.data_length, AnalogSnapshot::EnvelopeDataUnit); - - for (unsigned int i = 1; i < e0.length; i++) { - BOOST_CHECK_EQUAL(e0.samples[i].min, -1.0f); - BOOST_CHECK_EQUAL(e0.samples[i].max, -1.0f); - } - - const AnalogSnapshot::Envelope &e1 = s.envelope_levels_[1]; - BOOST_CHECK_EQUAL(e1.length, 1); - BOOST_CHECK_EQUAL(e1.data_length, AnalogSnapshot::EnvelopeDataUnit); - BOOST_REQUIRE(e1.samples != NULL); - BOOST_CHECK_EQUAL(e1.samples[0].min, -1.0f); - BOOST_CHECK_EQUAL(e1.samples[0].max, 1.0f); -} - -BOOST_AUTO_TEST_SUITE_END() -#endif diff --git a/test/data/logicsegment.cpp b/test/data/logicsegment.cpp new file mode 100644 index 00000000..29bffdda --- /dev/null +++ b/test/data/logicsegment.cpp @@ -0,0 +1,544 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include + +#include + +#include + +using pv::data::LogicSegment; +using std::vector; + +// Dummy, remove again when unit tests are fixed. +BOOST_AUTO_TEST_SUITE(DummyTestSuite) +BOOST_AUTO_TEST_CASE(DummyTestCase) +{ + BOOST_CHECK_EQUAL(1, 1); +} +BOOST_AUTO_TEST_SUITE_END() + +#if 0 +BOOST_AUTO_TEST_SUITE(LogicSegmentTest) + +void push_logic(LogicSegment &s, unsigned int length, uint8_t value) +{ + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = length; + logic.data = new uint8_t[length]; + memset(logic.data, value, length * logic.unitsize); + s.append_payload(logic); + delete[] (uint8_t*)logic.data; +} + +BOOST_AUTO_TEST_CASE(Pow2) +{ + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(0, 0), 0); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(1, 0), 1); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(2, 0), 2); + + BOOST_CHECK_EQUAL( + LogicSegment::pow2_ceil(INT64_MIN, 0), INT64_MIN); + BOOST_CHECK_EQUAL( + LogicSegment::pow2_ceil(INT64_MAX, 0), INT64_MAX); + + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(0, 1), 0); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(1, 1), 2); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(2, 1), 2); + BOOST_CHECK_EQUAL(LogicSegment::pow2_ceil(3, 1), 4); +} + +BOOST_AUTO_TEST_CASE(Basic) +{ + // Create an empty LogicSegment object + sr_datafeed_logic logic; + logic.length = 0; + logic.unitsize = 1; + logic.data = NULL; + + LogicSegment s(logic); + + //----- Test LogicSegment::push_logic -----// + + BOOST_CHECK(s.get_sample_count() == 0); + for (unsigned int i = 0; i < LogicSegment::ScaleStepCount; i++) + { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + // Push 8 samples of all zeros + push_logic(s, 8, 0); + + BOOST_CHECK(s.get_sample_count() == 8); + + // There should not be enough samples to have a single mip map sample + for (unsigned int i = 0; i < LogicSegment::ScaleStepCount; i++) + { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + // Push 8 samples of 0x11s to bring the total up to 16 + push_logic(s, 8, 0x11); + + // There should now be enough data for exactly one sample + // in mip map level 0, and that sample should be 0 + const LogicSegment::MipMapLevel &m0 = s.mip_map_[0]; + BOOST_CHECK_EQUAL(m0.length, 1); + BOOST_CHECK_EQUAL(m0.data_length, LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(m0.data != NULL); + BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[0], 0x11); + + // The higher levels should still be empty + for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) + { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + // Push 240 samples of all zeros to bring the total up to 256 + push_logic(s, 240, 0); + + BOOST_CHECK_EQUAL(m0.length, 16); + BOOST_CHECK_EQUAL(m0.data_length, LogicSegment::MipMapDataUnit); + + BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[1], 0x11); + for (unsigned int i = 2; i < m0.length; i++) + BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[i], 0); + + const LogicSegment::MipMapLevel &m1 = s.mip_map_[1]; + BOOST_CHECK_EQUAL(m1.length, 1); + BOOST_CHECK_EQUAL(m1.data_length, LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(m1.data != NULL); + BOOST_CHECK_EQUAL(((uint8_t*)m1.data)[0], 0x11); + + //----- Test LogicSegment::get_subsampled_edges -----// + + // Test a full view at full zoom. + vector edges; + s.get_subsampled_edges(edges, 0, 255, 1, 0); + BOOST_REQUIRE_EQUAL(edges.size(), 4); + + BOOST_CHECK_EQUAL(edges[0].first, 0); + BOOST_CHECK_EQUAL(edges[1].first, 8); + BOOST_CHECK_EQUAL(edges[2].first, 16); + BOOST_CHECK_EQUAL(edges[3].first, 256); + + // Test a subset at high zoom + edges.clear(); + s.get_subsampled_edges(edges, 6, 17, 0.05f, 0); + BOOST_REQUIRE_EQUAL(edges.size(), 4); + + BOOST_CHECK_EQUAL(edges[0].first, 6); + BOOST_CHECK_EQUAL(edges[1].first, 8); + BOOST_CHECK_EQUAL(edges[2].first, 16); + BOOST_CHECK_EQUAL(edges[3].first, 18); +} + +BOOST_AUTO_TEST_CASE(LargeData) +{ + uint8_t prev_sample; + const unsigned int Length = 1000000; + + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = Length; + logic.data = new uint8_t[Length]; + uint8_t *data = (uint8_t*)logic.data; + + for (unsigned int i = 0; i < Length; i++) + *data++ = (uint8_t)(i >> 8); + + LogicSegment s(logic); + delete[] (uint8_t*)logic.data; + + BOOST_CHECK(s.get_sample_count() == Length); + + // Check mip map level 0 + BOOST_CHECK_EQUAL(s.mip_map_[0].length, 62500); + BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, + LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(s.mip_map_[0].data != NULL); + + prev_sample = 0; + for (unsigned int i = 0; i < s.mip_map_[0].length;) + { + BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); + + const uint8_t sample = (uint8_t)((i*16) >> 8); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, + prev_sample ^ sample); + prev_sample = sample; + + for (int j = 1; i < s.mip_map_[0].length && j < 16; j++) + { + BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0); + } + } + + // Check mip map level 1 + BOOST_CHECK_EQUAL(s.mip_map_[1].length, 3906); + BOOST_CHECK_EQUAL(s.mip_map_[1].data_length, + LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(s.mip_map_[1].data != NULL); + + prev_sample = 0; + for (unsigned int i = 0; i < s.mip_map_[1].length; i++) + { + BOOST_TEST_MESSAGE("Testing mip_map[1].data[" << i << "]"); + + const uint8_t sample = i; + const uint8_t expected = sample ^ prev_sample; + prev_sample = i; + + BOOST_CHECK_EQUAL(s.get_subsample(1, i) & 0xFF, expected); + } + + // Check mip map level 2 + BOOST_CHECK_EQUAL(s.mip_map_[2].length, 244); + BOOST_CHECK_EQUAL(s.mip_map_[2].data_length, + LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(s.mip_map_[2].data != NULL); + + prev_sample = 0; + for (unsigned int i = 0; i < s.mip_map_[2].length; i++) + { + BOOST_TEST_MESSAGE("Testing mip_map[2].data[" << i << "]"); + + const uint8_t sample = i << 4; + const uint8_t expected = (sample ^ prev_sample) | 0x0F; + prev_sample = sample; + + BOOST_CHECK_EQUAL(s.get_subsample(2, i) & 0xFF, expected); + } + + // Check mip map level 3 + BOOST_CHECK_EQUAL(s.mip_map_[3].length, 15); + BOOST_CHECK_EQUAL(s.mip_map_[3].data_length, + LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(s.mip_map_[3].data != NULL); + + for (unsigned int i = 0; i < s.mip_map_[3].length; i++) + BOOST_CHECK_EQUAL(*((uint8_t*)s.mip_map_[3].data + i), + 0xFF); + + // Check the higher levels + for (unsigned int i = 4; i < LogicSegment::ScaleStepCount; i++) + { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + //----- Test LogicSegment::get_subsampled_edges -----// + // Check in normal case + vector edges; + s.get_subsampled_edges(edges, 0, Length-1, 1, 7); + + BOOST_CHECK_EQUAL(edges.size(), 32); + + for (unsigned int i = 0; i < edges.size() - 1; i++) + { + BOOST_CHECK_EQUAL(edges[i].first, i * 32768); + BOOST_CHECK_EQUAL(edges[i].second, i & 1); + } + + BOOST_CHECK_EQUAL(edges[31].first, 1000000); + + // Check in very low zoom case + edges.clear(); + s.get_subsampled_edges(edges, 0, Length-1, 50e6f, 7); + + BOOST_CHECK_EQUAL(edges.size(), 2); +} + +BOOST_AUTO_TEST_CASE(Pulses) +{ + const int Cycles = 3; + const int Period = 64; + const int Length = Cycles * Period; + + vector edges; + + //----- Create a LogicSegment -----// + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = Length; + logic.data = (uint64_t*)new uint8_t[Length]; + uint8_t *p = (uint8_t*)logic.data; + + for (int i = 0; i < Cycles; i++) { + *p++ = 0xFF; + for (int j = 1; j < Period; j++) + *p++ = 0x00; + } + + LogicSegment s(logic); + delete[] (uint8_t*)logic.data; + + //----- Check the mip-map -----// + // Check mip map level 0 + BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12); + BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, + LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(s.mip_map_[0].data != NULL); + + for (unsigned int i = 0; i < s.mip_map_[0].length;) { + BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0xFF); + + for (int j = 1; + i < s.mip_map_[0].length && + j < Period/LogicSegment::MipMapScaleFactor; j++) { + BOOST_TEST_MESSAGE( + "Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0x00); + } + } + + // Check the higher levels are all inactive + for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + //----- Test get_subsampled_edges at reduced scale -----// + s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2); + BOOST_REQUIRE_EQUAL(edges.size(), Cycles + 2); + + BOOST_CHECK_EQUAL(0, false); + for (unsigned int i = 1; i < edges.size(); i++) + BOOST_CHECK_EQUAL(edges[i].second, false); +} + +BOOST_AUTO_TEST_CASE(LongPulses) +{ + const int Cycles = 3; + const int Period = 64; + const int PulseWidth = 16; + const int Length = Cycles * Period; + + int j; + vector edges; + + //----- Create a LogicSegment -----// + sr_datafeed_logic logic; + logic.unitsize = 8; + logic.length = Length * 8; + logic.data = (uint64_t*)new uint64_t[Length]; + uint64_t *p = (uint64_t*)logic.data; + + for (int i = 0; i < Cycles; i++) { + for (j = 0; j < PulseWidth; j++) + *p++ = ~0; + for (; j < Period; j++) + *p++ = 0; + } + + LogicSegment s(logic); + delete[] (uint64_t*)logic.data; + + //----- Check the mip-map -----// + // Check mip map level 0 + BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12); + BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, + LogicSegment::MipMapDataUnit); + BOOST_REQUIRE(s.mip_map_[0].data != NULL); + + for (unsigned int i = 0; i < s.mip_map_[0].length;) { + for (j = 0; i < s.mip_map_[0].length && j < 2; j++) { + BOOST_TEST_MESSAGE( + "Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++), ~0); + } + + for (; i < s.mip_map_[0].length && + j < Period/LogicSegment::MipMapScaleFactor; j++) { + BOOST_TEST_MESSAGE( + "Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++), 0); + } + } + + // Check the higher levels are all inactive + for (unsigned int i = 1; i < LogicSegment::ScaleStepCount; i++) { + const LogicSegment::MipMapLevel &m = s.mip_map_[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + //----- Test get_subsampled_edges at a full scale -----// + s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2); + BOOST_REQUIRE_EQUAL(edges.size(), Cycles * 2 + 1); + + for (int i = 0; i < Cycles; i++) { + BOOST_CHECK_EQUAL(edges[i*2].first, i * Period); + BOOST_CHECK_EQUAL(edges[i*2].second, true); + BOOST_CHECK_EQUAL(edges[i*2+1].first, i * Period + PulseWidth); + BOOST_CHECK_EQUAL(edges[i*2+1].second, false); + } + + BOOST_CHECK_EQUAL(edges.back().first, Length); + BOOST_CHECK_EQUAL(edges.back().second, false); + + //----- Test get_subsampled_edges at a simplified scale -----// + edges.clear(); + s.get_subsampled_edges(edges, 0, Length-1, 17.0f, 2); + + BOOST_CHECK_EQUAL(edges[0].first, 0); + BOOST_CHECK_EQUAL(edges[0].second, true); + BOOST_CHECK_EQUAL(edges[1].first, 16); + BOOST_CHECK_EQUAL(edges[1].second, false); + + for (int i = 1; i < Cycles; i++) { + BOOST_CHECK_EQUAL(edges[i+1].first, i * Period); + BOOST_CHECK_EQUAL(edges[i+1].second, false); + } + + BOOST_CHECK_EQUAL(edges.back().first, Length); + BOOST_CHECK_EQUAL(edges.back().second, false); +} + +BOOST_AUTO_TEST_CASE(LisaMUsbHid) +{ + /* This test was created from the beginning of the USB_DM signal in + * sigrok-dumps-usb/lisa_m_usbhid/lisa_m_usbhid.sr + */ + + const int Edges[] = { + 7028, 7033, 7036, 7041, 7044, 7049, 7053, 7066, 7073, 7079, + 7086, 7095, 7103, 7108, 7111, 7116, 7119, 7124, 7136, 7141, + 7148, 7162, 7500 + }; + const int Length = Edges[countof(Edges) - 1]; + + bool state = false; + int lastEdgePos = 0; + + //----- Create a LogicSegment -----// + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = Length; + logic.data = new uint8_t[Length]; + uint8_t *data = (uint8_t*)logic.data; + + for (unsigned int i = 0; i < countof(Edges); i++) { + const int edgePos = Edges[i]; + memset(&data[lastEdgePos], state ? 0x02 : 0, + edgePos - lastEdgePos - 1); + + lastEdgePos = edgePos; + state = !state; + } + + LogicSegment s(logic); + delete[] (uint64_t*)logic.data; + + vector edges; + + + /* The trailing edge of the pulse train is falling in the source data. + * Check this is always true at different scales + */ + + edges.clear(); + s.get_subsampled_edges(edges, 0, Length-1, 33.333332f, 1); + BOOST_CHECK_EQUAL(edges[edges.size() - 2].second, false); +} + +/* + * This test checks the rendering of wide data (more than 8 channels) + * Probe signals are either all-high, or all-low, but are interleaved such that + * they would toggle during every sample if treated like 8 channels. + * The packet contains a large number of samples, so the mipmap generation kicks + * in. + * + * The signals should not toggle (have exactly two edges: the start and end) + */ +BOOST_AUTO_TEST_CASE(WideData) +{ + const int Length = 512<<10; + uint16_t *data = new uint16_t[Length]; + + sr_datafeed_logic logic; + logic.unitsize = sizeof(data[0]); + logic.length = Length * sizeof(data[0]); + logic.data = data; + + for (int i = 0; i < Length; i++) + data[i] = 0x0FF0; + + LogicSegment s(logic); + + vector edges; + + edges.clear(); + s.get_subsampled_edges(edges, 0, Length-1, 1, 0); + BOOST_CHECK_EQUAL(edges.size(), 2); + + edges.clear(); + s.get_subsampled_edges(edges, 0, Length-1, 1, 8); + BOOST_CHECK_EQUAL(edges.size(), 2); + + // Cleanup + delete [] data; +} + +/* + * This test is a replica of sixteen.sr attached to Bug #33. + */ +BOOST_AUTO_TEST_CASE(Sixteen) +{ + const int Length = 8; + uint16_t data[Length]; + + sr_datafeed_logic logic; + logic.unitsize = sizeof(data[0]); + logic.length = Length * sizeof(data[0]); + logic.data = data; + + for (int i = 0; i < Length; i++) + data[i] = 0xFFFE; + + LogicSegment s(logic); + + vector edges; + s.get_subsampled_edges(edges, 0, 2, 0.0004, 1); + + BOOST_CHECK_EQUAL(edges.size(), 2); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif diff --git a/test/data/logicsnapshot.cpp b/test/data/logicsnapshot.cpp deleted file mode 100644 index 9f973932..00000000 --- a/test/data/logicsnapshot.cpp +++ /dev/null @@ -1,544 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include - -#include - -#include - -using pv::data::LogicSnapshot; -using std::vector; - -// Dummy, remove again when unit tests are fixed. -BOOST_AUTO_TEST_SUITE(DummyTestSuite) -BOOST_AUTO_TEST_CASE(DummyTestCase) -{ - BOOST_CHECK_EQUAL(1, 1); -} -BOOST_AUTO_TEST_SUITE_END() - -#if 0 -BOOST_AUTO_TEST_SUITE(LogicSnapshotTest) - -void push_logic(LogicSnapshot &s, unsigned int length, uint8_t value) -{ - sr_datafeed_logic logic; - logic.unitsize = 1; - logic.length = length; - logic.data = new uint8_t[length]; - memset(logic.data, value, length * logic.unitsize); - s.append_payload(logic); - delete[] (uint8_t*)logic.data; -} - -BOOST_AUTO_TEST_CASE(Pow2) -{ - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(0, 0), 0); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(1, 0), 1); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(2, 0), 2); - - BOOST_CHECK_EQUAL( - LogicSnapshot::pow2_ceil(INT64_MIN, 0), INT64_MIN); - BOOST_CHECK_EQUAL( - LogicSnapshot::pow2_ceil(INT64_MAX, 0), INT64_MAX); - - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(0, 1), 0); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(1, 1), 2); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(2, 1), 2); - BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(3, 1), 4); -} - -BOOST_AUTO_TEST_CASE(Basic) -{ - // Create an empty LogicSnapshot object - sr_datafeed_logic logic; - logic.length = 0; - logic.unitsize = 1; - logic.data = NULL; - - LogicSnapshot s(logic); - - //----- Test LogicSnapshot::push_logic -----// - - BOOST_CHECK(s.get_sample_count() == 0); - for (unsigned int i = 0; i < LogicSnapshot::ScaleStepCount; i++) - { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.data == NULL); - } - - // Push 8 samples of all zeros - push_logic(s, 8, 0); - - BOOST_CHECK(s.get_sample_count() == 8); - - // There should not be enough samples to have a single mip map sample - for (unsigned int i = 0; i < LogicSnapshot::ScaleStepCount; i++) - { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.data == NULL); - } - - // Push 8 samples of 0x11s to bring the total up to 16 - push_logic(s, 8, 0x11); - - // There should now be enough data for exactly one sample - // in mip map level 0, and that sample should be 0 - const LogicSnapshot::MipMapLevel &m0 = s.mip_map_[0]; - BOOST_CHECK_EQUAL(m0.length, 1); - BOOST_CHECK_EQUAL(m0.data_length, LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(m0.data != NULL); - BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[0], 0x11); - - // The higher levels should still be empty - for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) - { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.data == NULL); - } - - // Push 240 samples of all zeros to bring the total up to 256 - push_logic(s, 240, 0); - - BOOST_CHECK_EQUAL(m0.length, 16); - BOOST_CHECK_EQUAL(m0.data_length, LogicSnapshot::MipMapDataUnit); - - BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[1], 0x11); - for (unsigned int i = 2; i < m0.length; i++) - BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[i], 0); - - const LogicSnapshot::MipMapLevel &m1 = s.mip_map_[1]; - BOOST_CHECK_EQUAL(m1.length, 1); - BOOST_CHECK_EQUAL(m1.data_length, LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(m1.data != NULL); - BOOST_CHECK_EQUAL(((uint8_t*)m1.data)[0], 0x11); - - //----- Test LogicSnapshot::get_subsampled_edges -----// - - // Test a full view at full zoom. - vector edges; - s.get_subsampled_edges(edges, 0, 255, 1, 0); - BOOST_REQUIRE_EQUAL(edges.size(), 4); - - BOOST_CHECK_EQUAL(edges[0].first, 0); - BOOST_CHECK_EQUAL(edges[1].first, 8); - BOOST_CHECK_EQUAL(edges[2].first, 16); - BOOST_CHECK_EQUAL(edges[3].first, 256); - - // Test a subset at high zoom - edges.clear(); - s.get_subsampled_edges(edges, 6, 17, 0.05f, 0); - BOOST_REQUIRE_EQUAL(edges.size(), 4); - - BOOST_CHECK_EQUAL(edges[0].first, 6); - BOOST_CHECK_EQUAL(edges[1].first, 8); - BOOST_CHECK_EQUAL(edges[2].first, 16); - BOOST_CHECK_EQUAL(edges[3].first, 18); -} - -BOOST_AUTO_TEST_CASE(LargeData) -{ - uint8_t prev_sample; - const unsigned int Length = 1000000; - - sr_datafeed_logic logic; - logic.unitsize = 1; - logic.length = Length; - logic.data = new uint8_t[Length]; - uint8_t *data = (uint8_t*)logic.data; - - for (unsigned int i = 0; i < Length; i++) - *data++ = (uint8_t)(i >> 8); - - LogicSnapshot s(logic); - delete[] (uint8_t*)logic.data; - - BOOST_CHECK(s.get_sample_count() == Length); - - // Check mip map level 0 - BOOST_CHECK_EQUAL(s.mip_map_[0].length, 62500); - BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, - LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(s.mip_map_[0].data != NULL); - - prev_sample = 0; - for (unsigned int i = 0; i < s.mip_map_[0].length;) - { - BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); - - const uint8_t sample = (uint8_t)((i*16) >> 8); - BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, - prev_sample ^ sample); - prev_sample = sample; - - for (int j = 1; i < s.mip_map_[0].length && j < 16; j++) - { - BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); - BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0); - } - } - - // Check mip map level 1 - BOOST_CHECK_EQUAL(s.mip_map_[1].length, 3906); - BOOST_CHECK_EQUAL(s.mip_map_[1].data_length, - LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(s.mip_map_[1].data != NULL); - - prev_sample = 0; - for (unsigned int i = 0; i < s.mip_map_[1].length; i++) - { - BOOST_TEST_MESSAGE("Testing mip_map[1].data[" << i << "]"); - - const uint8_t sample = i; - const uint8_t expected = sample ^ prev_sample; - prev_sample = i; - - BOOST_CHECK_EQUAL(s.get_subsample(1, i) & 0xFF, expected); - } - - // Check mip map level 2 - BOOST_CHECK_EQUAL(s.mip_map_[2].length, 244); - BOOST_CHECK_EQUAL(s.mip_map_[2].data_length, - LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(s.mip_map_[2].data != NULL); - - prev_sample = 0; - for (unsigned int i = 0; i < s.mip_map_[2].length; i++) - { - BOOST_TEST_MESSAGE("Testing mip_map[2].data[" << i << "]"); - - const uint8_t sample = i << 4; - const uint8_t expected = (sample ^ prev_sample) | 0x0F; - prev_sample = sample; - - BOOST_CHECK_EQUAL(s.get_subsample(2, i) & 0xFF, expected); - } - - // Check mip map level 3 - BOOST_CHECK_EQUAL(s.mip_map_[3].length, 15); - BOOST_CHECK_EQUAL(s.mip_map_[3].data_length, - LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(s.mip_map_[3].data != NULL); - - for (unsigned int i = 0; i < s.mip_map_[3].length; i++) - BOOST_CHECK_EQUAL(*((uint8_t*)s.mip_map_[3].data + i), - 0xFF); - - // Check the higher levels - for (unsigned int i = 4; i < LogicSnapshot::ScaleStepCount; i++) - { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.data == NULL); - } - - //----- Test LogicSnapshot::get_subsampled_edges -----// - // Check in normal case - vector edges; - s.get_subsampled_edges(edges, 0, Length-1, 1, 7); - - BOOST_CHECK_EQUAL(edges.size(), 32); - - for (unsigned int i = 0; i < edges.size() - 1; i++) - { - BOOST_CHECK_EQUAL(edges[i].first, i * 32768); - BOOST_CHECK_EQUAL(edges[i].second, i & 1); - } - - BOOST_CHECK_EQUAL(edges[31].first, 1000000); - - // Check in very low zoom case - edges.clear(); - s.get_subsampled_edges(edges, 0, Length-1, 50e6f, 7); - - BOOST_CHECK_EQUAL(edges.size(), 2); -} - -BOOST_AUTO_TEST_CASE(Pulses) -{ - const int Cycles = 3; - const int Period = 64; - const int Length = Cycles * Period; - - vector edges; - - //----- Create a LogicSnapshot -----// - sr_datafeed_logic logic; - logic.unitsize = 1; - logic.length = Length; - logic.data = (uint64_t*)new uint8_t[Length]; - uint8_t *p = (uint8_t*)logic.data; - - for (int i = 0; i < Cycles; i++) { - *p++ = 0xFF; - for (int j = 1; j < Period; j++) - *p++ = 0x00; - } - - LogicSnapshot s(logic); - delete[] (uint8_t*)logic.data; - - //----- Check the mip-map -----// - // Check mip map level 0 - BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12); - BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, - LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(s.mip_map_[0].data != NULL); - - for (unsigned int i = 0; i < s.mip_map_[0].length;) { - BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); - BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0xFF); - - for (int j = 1; - i < s.mip_map_[0].length && - j < Period/LogicSnapshot::MipMapScaleFactor; j++) { - BOOST_TEST_MESSAGE( - "Testing mip_map[0].data[" << i << "]"); - BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0x00); - } - } - - // Check the higher levels are all inactive - for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.data == NULL); - } - - //----- Test get_subsampled_edges at reduced scale -----// - s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2); - BOOST_REQUIRE_EQUAL(edges.size(), Cycles + 2); - - BOOST_CHECK_EQUAL(0, false); - for (unsigned int i = 1; i < edges.size(); i++) - BOOST_CHECK_EQUAL(edges[i].second, false); -} - -BOOST_AUTO_TEST_CASE(LongPulses) -{ - const int Cycles = 3; - const int Period = 64; - const int PulseWidth = 16; - const int Length = Cycles * Period; - - int j; - vector edges; - - //----- Create a LogicSnapshot -----// - sr_datafeed_logic logic; - logic.unitsize = 8; - logic.length = Length * 8; - logic.data = (uint64_t*)new uint64_t[Length]; - uint64_t *p = (uint64_t*)logic.data; - - for (int i = 0; i < Cycles; i++) { - for (j = 0; j < PulseWidth; j++) - *p++ = ~0; - for (; j < Period; j++) - *p++ = 0; - } - - LogicSnapshot s(logic); - delete[] (uint64_t*)logic.data; - - //----- Check the mip-map -----// - // Check mip map level 0 - BOOST_CHECK_EQUAL(s.mip_map_[0].length, 12); - BOOST_CHECK_EQUAL(s.mip_map_[0].data_length, - LogicSnapshot::MipMapDataUnit); - BOOST_REQUIRE(s.mip_map_[0].data != NULL); - - for (unsigned int i = 0; i < s.mip_map_[0].length;) { - for (j = 0; i < s.mip_map_[0].length && j < 2; j++) { - BOOST_TEST_MESSAGE( - "Testing mip_map[0].data[" << i << "]"); - BOOST_CHECK_EQUAL(s.get_subsample(0, i++), ~0); - } - - for (; i < s.mip_map_[0].length && - j < Period/LogicSnapshot::MipMapScaleFactor; j++) { - BOOST_TEST_MESSAGE( - "Testing mip_map[0].data[" << i << "]"); - BOOST_CHECK_EQUAL(s.get_subsample(0, i++), 0); - } - } - - // Check the higher levels are all inactive - for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) { - const LogicSnapshot::MipMapLevel &m = s.mip_map_[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.data == NULL); - } - - //----- Test get_subsampled_edges at a full scale -----// - s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2); - BOOST_REQUIRE_EQUAL(edges.size(), Cycles * 2 + 1); - - for (int i = 0; i < Cycles; i++) { - BOOST_CHECK_EQUAL(edges[i*2].first, i * Period); - BOOST_CHECK_EQUAL(edges[i*2].second, true); - BOOST_CHECK_EQUAL(edges[i*2+1].first, i * Period + PulseWidth); - BOOST_CHECK_EQUAL(edges[i*2+1].second, false); - } - - BOOST_CHECK_EQUAL(edges.back().first, Length); - BOOST_CHECK_EQUAL(edges.back().second, false); - - //----- Test get_subsampled_edges at a simplified scale -----// - edges.clear(); - s.get_subsampled_edges(edges, 0, Length-1, 17.0f, 2); - - BOOST_CHECK_EQUAL(edges[0].first, 0); - BOOST_CHECK_EQUAL(edges[0].second, true); - BOOST_CHECK_EQUAL(edges[1].first, 16); - BOOST_CHECK_EQUAL(edges[1].second, false); - - for (int i = 1; i < Cycles; i++) { - BOOST_CHECK_EQUAL(edges[i+1].first, i * Period); - BOOST_CHECK_EQUAL(edges[i+1].second, false); - } - - BOOST_CHECK_EQUAL(edges.back().first, Length); - BOOST_CHECK_EQUAL(edges.back().second, false); -} - -BOOST_AUTO_TEST_CASE(LisaMUsbHid) -{ - /* This test was created from the beginning of the USB_DM signal in - * sigrok-dumps-usb/lisa_m_usbhid/lisa_m_usbhid.sr - */ - - const int Edges[] = { - 7028, 7033, 7036, 7041, 7044, 7049, 7053, 7066, 7073, 7079, - 7086, 7095, 7103, 7108, 7111, 7116, 7119, 7124, 7136, 7141, - 7148, 7162, 7500 - }; - const int Length = Edges[countof(Edges) - 1]; - - bool state = false; - int lastEdgePos = 0; - - //----- Create a LogicSnapshot -----// - sr_datafeed_logic logic; - logic.unitsize = 1; - logic.length = Length; - logic.data = new uint8_t[Length]; - uint8_t *data = (uint8_t*)logic.data; - - for (unsigned int i = 0; i < countof(Edges); i++) { - const int edgePos = Edges[i]; - memset(&data[lastEdgePos], state ? 0x02 : 0, - edgePos - lastEdgePos - 1); - - lastEdgePos = edgePos; - state = !state; - } - - LogicSnapshot s(logic); - delete[] (uint64_t*)logic.data; - - vector edges; - - - /* The trailing edge of the pulse train is falling in the source data. - * Check this is always true at different scales - */ - - edges.clear(); - s.get_subsampled_edges(edges, 0, Length-1, 33.333332f, 1); - BOOST_CHECK_EQUAL(edges[edges.size() - 2].second, false); -} - -/* - * This test checks the rendering of wide data (more than 8 channels) - * Probe signals are either all-high, or all-low, but are interleaved such that - * they would toggle during every sample if treated like 8 channels. - * The packet contains a large number of samples, so the mipmap generation kicks - * in. - * - * The signals should not toggle (have exactly two edges: the start and end) - */ -BOOST_AUTO_TEST_CASE(WideData) -{ - const int Length = 512<<10; - uint16_t *data = new uint16_t[Length]; - - sr_datafeed_logic logic; - logic.unitsize = sizeof(data[0]); - logic.length = Length * sizeof(data[0]); - logic.data = data; - - for (int i = 0; i < Length; i++) - data[i] = 0x0FF0; - - LogicSnapshot s(logic); - - vector edges; - - edges.clear(); - s.get_subsampled_edges(edges, 0, Length-1, 1, 0); - BOOST_CHECK_EQUAL(edges.size(), 2); - - edges.clear(); - s.get_subsampled_edges(edges, 0, Length-1, 1, 8); - BOOST_CHECK_EQUAL(edges.size(), 2); - - // Cleanup - delete [] data; -} - -/* - * This test is a replica of sixteen.sr attached to Bug #33. - */ -BOOST_AUTO_TEST_CASE(Sixteen) -{ - const int Length = 8; - uint16_t data[Length]; - - sr_datafeed_logic logic; - logic.unitsize = sizeof(data[0]); - logic.length = Length * sizeof(data[0]); - logic.data = data; - - for (int i = 0; i < Length; i++) - data[i] = 0xFFFE; - - LogicSnapshot s(logic); - - vector edges; - s.get_subsampled_edges(edges, 0, 2, 0.0004, 1); - - BOOST_CHECK_EQUAL(edges.size(), 2); -} - -BOOST_AUTO_TEST_SUITE_END() -#endif