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
#include <cassert>
#include "analog.hpp"
-#include "analogsnapshot.hpp"
+#include "analogsegment.hpp"
using std::deque;
using std::max;
{
}
-void Analog::push_snapshot(shared_ptr<AnalogSnapshot> &snapshot)
+void Analog::push_segment(shared_ptr<AnalogSegment> &segment)
{
- snapshots_.push_front(snapshot);
+ segments_.push_front(segment);
}
-const deque< shared_ptr<AnalogSnapshot> >& Analog::analog_snapshots() const
+const deque< shared_ptr<AnalogSegment> >& Analog::analog_segments() const
{
- return snapshots_;
+ return segments_;
}
-vector< shared_ptr<Snapshot> > Analog::snapshots() const
+vector< shared_ptr<Segment> > Analog::segments() const
{
- return vector< shared_ptr<Snapshot> >(
- snapshots_.begin(), snapshots_.end());
+ return vector< shared_ptr<Segment> >(
+ 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<AnalogSnapshot> s : snapshots_) {
+ for (const std::shared_ptr<AnalogSegment> s : segments_) {
assert(s);
l = max(l, s->get_sample_count());
}
namespace pv {
namespace data {
-class AnalogSnapshot;
+class AnalogSegment;
class Analog : public SignalData
{
public:
Analog();
- void push_snapshot(
- std::shared_ptr<AnalogSnapshot> &snapshot);
+ void push_segment(
+ std::shared_ptr<AnalogSegment> &segment);
- const std::deque< std::shared_ptr<AnalogSnapshot> >&
- analog_snapshots() const;
+ const std::deque< std::shared_ptr<AnalogSegment> >&
+ analog_segments() const;
- std::vector< std::shared_ptr<Snapshot> > snapshots() const;
+ std::vector< std::shared_ptr<Segment> > segments() const;
void clear();
uint64_t get_max_sample_count() const;
private:
- std::deque< std::shared_ptr<AnalogSnapshot> > snapshots_;
+ std::deque< std::shared_ptr<AnalogSegment> > segments_;
};
} // namespace data
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <extdef.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <algorithm>
+
+#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<recursive_mutex> lock(mutex_);
+ memset(envelope_levels_, 0, sizeof(envelope_levels_));
+}
+
+AnalogSegment::~AnalogSegment()
+{
+ lock_guard<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> 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
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <utility>
+#include <vector>
+
+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
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <extdef.h>
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include <algorithm>
-
-#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<recursive_mutex> lock(mutex_);
- memset(envelope_levels_, 0, sizeof(envelope_levels_));
-}
-
-AnalogSnapshot::~AnalogSnapshot()
-{
- lock_guard<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> 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
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <utility>
-#include <vector>
-
-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
#include "decoderstack.hpp"
#include <pv/data/logic.hpp>
-#include <pv/data/logicsnapshot.hpp>
+#include <pv/data/logicsegment.hpp>
#include <pv/data/decode/decoder.hpp>
#include <pv/data/decode/annotation.hpp>
#include <pv/session.hpp>
// 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<decode::Decoder> &dec : stack_)
if (dec && !dec->channels().empty() &&
((logic_signal = (*dec->channels().begin()).second)) &&
if (!data)
return;
- // Check we have a snapshot of data
- const deque< shared_ptr<pv::data::LogicSnapshot> > &snapshots =
- data->logic_snapshots();
- if (snapshots.empty())
+ // Check we have a segment of data
+ const deque< shared_ptr<pv::data::LogicSegment> > &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;
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)
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) {
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<decode::Decoder> &dec : stack_)
{
// Get the intial sample count
{
unique_lock<mutex> input_lock(input_mutex_);
- sample_count = sample_count_ = snapshot_->get_sample_count();
+ sample_count = sample_count_ = segment_->get_sample_count();
}
// Start the session
{
{
unique_lock<mutex> lock(input_mutex_);
- if (snapshot_)
- sample_count_ = snapshot_->get_sample_count();
+ if (segment_)
+ sample_count_ = segment_->get_sample_count();
}
input_cond_.notify_one();
}
{
{
unique_lock<mutex> lock(input_mutex_);
- if (snapshot_)
+ if (segment_)
frame_complete_ = true;
}
input_cond_.notify_one();
namespace data {
-class LogicSnapshot;
+class LogicSegment;
namespace decode {
class Annotation;
std::list< std::shared_ptr<decode::Decoder> > stack_;
- std::shared_ptr<pv::data::LogicSnapshot> snapshot_;
+ std::shared_ptr<pv::data::LogicSegment> segment_;
mutable std::mutex input_mutex_;
mutable std::condition_variable input_cond_;
#include <cassert>
#include "logic.hpp"
-#include "logicsnapshot.hpp"
+#include "logicsegment.hpp"
using std::deque;
using std::max;
return num_channels_;
}
-void Logic::push_snapshot(
- shared_ptr<LogicSnapshot> &snapshot)
+void Logic::push_segment(
+ shared_ptr<LogicSegment> &segment)
{
- snapshots_.push_front(snapshot);
+ segments_.push_front(segment);
}
-const deque< shared_ptr<LogicSnapshot> >& Logic::logic_snapshots() const
+const deque< shared_ptr<LogicSegment> >& Logic::logic_segments() const
{
- return snapshots_;
+ return segments_;
}
-vector< shared_ptr<Snapshot> > Logic::snapshots() const
+vector< shared_ptr<Segment> > Logic::segments() const
{
- return vector< shared_ptr<Snapshot> >(
- snapshots_.begin(), snapshots_.end());
+ return vector< shared_ptr<Segment> >(
+ 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<LogicSnapshot> s : snapshots_) {
+ for (std::shared_ptr<LogicSegment> s : segments_) {
assert(s);
l = max(l, s->get_sample_count());
}
namespace pv {
namespace data {
-class LogicSnapshot;
+class LogicSegment;
class Logic : public SignalData
{
int get_num_channels() const;
- void push_snapshot(
- std::shared_ptr<LogicSnapshot> &snapshot);
+ void push_segment(
+ std::shared_ptr<LogicSegment> &segment);
- const std::deque< std::shared_ptr<LogicSnapshot> >&
- logic_snapshots() const;
+ const std::deque< std::shared_ptr<LogicSegment> >&
+ logic_segments() const;
- std::vector< std::shared_ptr<Snapshot> > snapshots() const;
+ std::vector< std::shared_ptr<Segment> > segments() const;
void clear();
private:
const unsigned int num_channels_;
- std::deque< std::shared_ptr<LogicSnapshot> > snapshots_;
+ std::deque< std::shared_ptr<LogicSegment> > segments_;
};
} // namespace data
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <extdef.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "logicsegment.hpp"
+
+#include <libsigrok/libsigrok.hpp>
+
+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> 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<recursive_mutex> lock(mutex_);
+ memset(mip_map_, 0, sizeof(mip_map_));
+ append_payload(logic);
+}
+
+LogicSegment::~LogicSegment()
+{
+ lock_guard<recursive_mutex> 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> logic)
+{
+ assert(unit_size_ == logic->unit_size());
+ assert((logic->data_length() % unit_size_) == 0);
+
+ lock_guard<recursive_mutex> 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<recursive_mutex> 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<EdgePair> &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<recursive_mutex> 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<int64_t, bool>(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<int64_t, bool>(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<int64_t, bool>(end, end_sample));
+ edges.push_back(pair<int64_t, bool>(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
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <utility>
+#include <vector>
+
+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<int64_t, bool> EdgePair;
+
+public:
+ LogicSegment(std::shared_ptr<sigrok::Logic> logic,
+ uint64_t samplerate, uint64_t expected_num_samples = 0);
+
+ virtual ~LogicSegment();
+
+ void append_payload(std::shared_ptr<sigrok::Logic> 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<EdgePair> &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
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <extdef.h>
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "logicsnapshot.hpp"
-
-#include <libsigrok/libsigrok.hpp>
-
-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> 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<recursive_mutex> lock(mutex_);
- memset(mip_map_, 0, sizeof(mip_map_));
- append_payload(logic);
-}
-
-LogicSnapshot::~LogicSnapshot()
-{
- lock_guard<recursive_mutex> 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> logic)
-{
- assert(unit_size_ == logic->unit_size());
- assert((logic->data_length() % unit_size_) == 0);
-
- lock_guard<recursive_mutex> 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<recursive_mutex> 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<EdgePair> &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<recursive_mutex> 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<int64_t, bool>(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<int64_t, bool>(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<int64_t, bool>(end, end_sample));
- edges.push_back(pair<int64_t, bool>(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
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <utility>
-#include <vector>
-
-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<int64_t, bool> EdgePair;
-
-public:
- LogicSnapshot(std::shared_ptr<sigrok::Logic> logic,
- uint64_t samplerate, uint64_t expected_num_samples = 0);
-
- virtual ~LogicSnapshot();
-
- void append_payload(std::shared_ptr<sigrok::Logic> 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<EdgePair> &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
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+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<recursive_mutex> lock(mutex_);
+ assert(unit_size_ > 0);
+}
+
+Segment::~Segment()
+{
+ lock_guard<recursive_mutex> lock(mutex_);
+}
+
+uint64_t Segment::get_sample_count() const
+{
+ lock_guard<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> lock(mutex_);
+ return data_.size();
+}
+
+void Segment::append_data(void *data, uint64_t samples)
+{
+ lock_guard<recursive_mutex> 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
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <thread>
+#include <mutex>
+#include <vector>
+
+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<uint8_t> 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
namespace pv {
namespace data {
-class Snapshot;
+class Segment;
class SignalData
{
virtual ~SignalData() {}
public:
- virtual std::vector< std::shared_ptr<Snapshot> > snapshots() const = 0;
+ virtual std::vector< std::shared_ptr<Segment> > segments() const = 0;
virtual void clear() = 0;
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-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<recursive_mutex> lock(mutex_);
- assert(unit_size_ > 0);
-}
-
-Snapshot::~Snapshot()
-{
- lock_guard<recursive_mutex> lock(mutex_);
-}
-
-uint64_t Snapshot::get_sample_count() const
-{
- lock_guard<recursive_mutex> 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<recursive_mutex> 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<recursive_mutex> lock(mutex_);
- return data_.size();
-}
-
-void Snapshot::append_data(void *data, uint64_t samples)
-{
- lock_guard<recursive_mutex> 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
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <thread>
-#include <mutex>
-#include <vector>
-
-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<uint8_t> 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
#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"
[] (shared_ptr<Channel> channel) {
return channel->type() == ChannelType::LOGIC; });
- // Create data containers for the logic data snapshots
+ // Create data containers for the logic data segments
{
lock_guard<mutex> data_lock(data_mutex_);
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);
void Session::feed_in_frame_begin()
{
- if (cur_logic_snapshot_ || !cur_analog_snapshots_.empty())
+ if (cur_logic_segment_ || !cur_analog_segments_.empty())
frame_began();
}
return;
}
- if (!cur_logic_snapshot_)
+ if (!cur_logic_segment_)
{
// This could be the first packet after a trigger
set_capture_state(Running);
VariantBase::cast_dynamic<Variant<guint64>>(
device_->config_get(ConfigKey::LIMIT_SAMPLES)).get() : 0;
- // Create a new data snapshot
- cur_logic_snapshot_ = shared_ptr<data::LogicSnapshot>(
- new data::LogicSnapshot(
+ // Create a new data segment
+ cur_logic_segment_ = shared_ptr<data::LogicSegment>(
+ 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
}
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();
for (auto channel : channels)
{
- shared_ptr<data::AnalogSnapshot> snapshot;
+ shared_ptr<data::AnalogSegment> segment;
- // Try to get the snapshot of the channel
- const map< shared_ptr<Channel>, shared_ptr<data::AnalogSnapshot> >::
- 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<Channel>, shared_ptr<data::AnalogSegment> >::
+ 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.
sample_limit = 0;
}
- // Create a snapshot, keep it in the maps of channels
- snapshot = shared_ptr<data::AnalogSnapshot>(
- new data::AnalogSnapshot(
+ // Create a segment, keep it in the maps of channels
+ segment = shared_ptr<data::AnalogSegment>(
+ 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<view::AnalogSignal> sig =
shared_ptr<data::Analog> 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);
}
{
{
lock_guard<mutex> lock(data_mutex_);
- cur_logic_snapshot_.reset();
- cur_analog_snapshots_.clear();
+ cur_logic_segment_.reset();
+ cur_analog_segments_.clear();
}
frame_ended();
break;
namespace data {
class Analog;
-class AnalogSnapshot;
+class AnalogSegment;
class Logic;
-class LogicSnapshot;
+class LogicSegment;
class SignalData;
}
mutable std::mutex data_mutex_;
std::shared_ptr<data::Logic> logic_data_;
uint64_t cur_samplerate_;
- std::shared_ptr<data::LogicSnapshot> cur_logic_snapshot_;
- std::map< std::shared_ptr<sigrok::Channel>, std::shared_ptr<data::AnalogSnapshot> >
- cur_analog_snapshots_;
+ std::shared_ptr<data::LogicSegment> cur_logic_segment_;
+ std::map< std::shared_ptr<sigrok::Channel>, std::shared_ptr<data::AnalogSegment> >
+ cur_analog_segments_;
std::thread sampling_thread_;
#include <pv/session.hpp>
#include <pv/data/logic.hpp>
-#include <pv/data/logicsnapshot.hpp>
+#include <pv/data/logicsegment.hpp>
#include <pv/view/signal.hpp>
#include <libsigrok/libsigrok.hpp>
return false;
}
- // Get the snapshot
- const deque< shared_ptr<data::LogicSnapshot> > &snapshots =
- data->logic_snapshots();
+ // Get the segment
+ const deque< shared_ptr<data::LogicSegment> > &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<data::LogicSnapshot> snapshot(snapshots.front());
- assert(snapshot);
+ const shared_ptr<data::LogicSegment> segment(segments.front());
+ assert(segment);
// Begin storing
try {
Glib::Variant<Glib::ustring>::create(file_name_)}});
auto meta = context->create_meta_packet(
{{ConfigKey::SAMPLERATE, Glib::Variant<guint64>::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;
}
interrupt_ = true;
}
-void StoreSession::store_proc(shared_ptr<data::LogicSnapshot> snapshot)
+void StoreSession::store_proc(shared_ptr<data::LogicSegment> segment)
{
- assert(snapshot);
+ assert(segment);
uint64_t start_sample = 0, sample_count;
unsigned progress_scale = 0;
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.
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;
class Session;
namespace data {
-class LogicSnapshot;
+class LogicSegment;
}
class StoreSession : public QObject
void cancel();
private:
- void store_proc(std::shared_ptr<pv::data::LogicSnapshot> snapshot);
+ void store_proc(std::shared_ptr<pv::data::LogicSegment> segment);
Q_SIGNALS:
void progress_updated();
#include "analogsignal.hpp"
#include "pv/data/analog.hpp"
-#include "pv/data/analogsnapshot.hpp"
+#include "pv/data/analogsegment.hpp"
#include "pv/view/view.hpp"
#include <libsigrok/libsigrok.hpp>
if (!channel_->enabled())
return;
- const deque< shared_ptr<pv::data::AnalogSnapshot> > &snapshots =
- data_->analog_snapshots();
- if (snapshots.empty())
+ const deque< shared_ptr<pv::data::AnalogSegment> > &segments =
+ data_->analog_segments();
+ if (segments.empty())
return;
- const shared_ptr<pv::data::AnalogSnapshot> &snapshot =
- snapshots.front();
+ const shared_ptr<pv::data::AnalogSegment> &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();
(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<pv::data::AnalogSnapshot> &snapshot,
+ const shared_ptr<pv::data::AnalogSegment> &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_);
}
void AnalogSignal::paint_envelope(QPainter &p,
- const shared_ptr<pv::data::AnalogSnapshot> &snapshot,
+ const shared_ptr<pv::data::AnalogSegment> &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;
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
namespace data {
class Analog;
-class AnalogSnapshot;
+class AnalogSegment;
}
namespace view {
private:
void paint_trace(QPainter &p,
- const std::shared_ptr<pv::data::AnalogSnapshot> &snapshot,
+ const std::shared_ptr<pv::data::AnalogSegment> &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<pv::data::AnalogSnapshot> &snapshot,
+ const std::shared_ptr<pv::data::AnalogSegment> &segment,
int y, int left, const int64_t start, const int64_t end,
const double pixels_offset, const double samples_per_pixel);
#include <pv/data/decoderstack.hpp>
#include <pv/data/decode/decoder.hpp>
#include <pv/data/logic.hpp>
-#include <pv/data/logicsnapshot.hpp>
+#include <pv/data/logicsegment.hpp>
#include <pv/data/decode/annotation.hpp>
#include <pv/view/logicsignal.hpp>
#include <pv/view/view.hpp>
// 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<Decoder> &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<LogicSnapshot> snapshot =
- data->logic_snapshots().front();
- assert(snapshot);
- const int64_t sample_count = (int64_t)snapshot->get_sample_count();
+ const shared_ptr<LogicSegment> segment =
+ data->logic_segments().front();
+ assert(segment);
+ const int64_t sample_count = (int64_t)segment->get_sample_count();
if (sample_count == 0)
return;
#include <pv/session.hpp>
#include <pv/devicemanager.hpp>
#include <pv/data/logic.hpp>
-#include <pv/data/logicsnapshot.hpp>
+#include <pv/data/logicsegment.hpp>
#include <pv/view/view.hpp>
#include <libsigrok/libsigrok.hpp>
const float high_offset = y - SignalHeight + 0.5f;
const float low_offset = y + 0.5f;
- const deque< shared_ptr<pv::data::LogicSnapshot> > &snapshots =
- data_->logic_snapshots();
- if (snapshots.empty())
+ const deque< shared_ptr<pv::data::LogicSegment> > &segments =
+ data_->logic_segments();
+ if (segments.empty())
return;
- const shared_ptr<pv::data::LogicSnapshot> &snapshot =
- snapshots.front();
+ const shared_ptr<pv::data::LogicSegment> &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());
#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;
double samplerate = 0.0;
for (const shared_ptr<SignalData> d : visible_data) {
assert(d);
- const vector< shared_ptr<Snapshot> > snapshots =
- d->snapshots();
- for (const shared_ptr<Snapshot> &s : snapshots)
+ const vector< shared_ptr<Segment> > segments =
+ d->segments();
+ for (const shared_ptr<Segment> &s : segments)
samplerate = max(samplerate, s->samplerate());
}
const set< shared_ptr<SignalData> > visible_data = get_visible_data();
for (const shared_ptr<SignalData> d : visible_data)
{
- const vector< shared_ptr<Snapshot> > snapshots =
- d->snapshots();
- for (const shared_ptr<Snapshot> &s : snapshots) {
+ const vector< shared_ptr<Segment> > segments =
+ d->segments();
+ for (const shared_ptr<Segment> &s : segments) {
double samplerate = s->samplerate();
samplerate = (samplerate <= 0.0) ? 1.0 : samplerate;
${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
${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
)
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <extdef.h>
+
+#include <stdint.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <pv/data/analogsegment.hpp>
+
+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
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <extdef.h>
-
-#include <stdint.h>
-
-#include <boost/test/unit_test.hpp>
-
-#include <pv/data/analogsnapshot.hpp>
-
-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
--- /dev/null
+/*
+ * This file is part of the PulseView project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * 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 <extdef.h>
+
+#include <stdint.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <pv/data/logicsegment.hpp>
+
+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<LogicSegment::EdgePair> 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<LogicSegment::EdgePair> 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<LogicSegment::EdgePair> 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<LogicSegment::EdgePair> 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<LogicSegment::EdgePair> 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<LogicSegment::EdgePair> 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<LogicSegment::EdgePair> edges;
+ s.get_subsampled_edges(edges, 0, 2, 0.0004, 1);
+
+ BOOST_CHECK_EQUAL(edges.size(), 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+#endif
+++ /dev/null
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
- *
- * 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 <extdef.h>
-
-#include <stdint.h>
-
-#include <boost/test/unit_test.hpp>
-
-#include <pv/data/logicsnapshot.hpp>
-
-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<LogicSnapshot::EdgePair> 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<LogicSnapshot::EdgePair> 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<LogicSnapshot::EdgePair> 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<LogicSnapshot::EdgePair> 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<LogicSnapshot::EdgePair> 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<LogicSnapshot::EdgePair> 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<LogicSnapshot::EdgePair> edges;
- s.get_subsampled_edges(edges, 0, 2, 0.0004, 1);
-
- BOOST_CHECK_EQUAL(edges.size(), 2);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-#endif