From: Joel Holdsworth Date: Thu, 20 Dec 2012 21:34:43 +0000 (+0000) Subject: Moved data and snapshot classes into pv::data namespace X-Git-Tag: pulseview-0.1.0~186 X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=commitdiff_plain;h=1b1ec774978b65209ce2b454cbf81da499b797d2 Moved data and snapshot classes into pv::data namespace --- diff --git a/CMakeLists.txt b/CMakeLists.txt index e1893b6c..e9ae0e76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,15 +80,15 @@ configure_file ( set(pulseview_SOURCES main.cpp - pv/analogdata.cpp - pv/analogdatasnapshot.cpp - pv/datasnapshot.cpp - pv/logicdata.cpp - pv/logicdatasnapshot.cpp pv/mainwindow.cpp pv/samplingbar.cpp - pv/signaldata.cpp pv/sigsession.cpp + pv/data/analog.cpp + pv/data/analogsnapshot.cpp + pv/data/logic.cpp + pv/data/logicsnapshot.cpp + pv/data/signaldata.cpp + pv/data/snapshot.cpp pv/dialogs/about.cpp pv/view/analogsignal.cpp pv/view/cursor.cpp diff --git a/pv/analogdata.cpp b/pv/analogdata.cpp deleted file mode 100644 index 8cfa7a69..00000000 --- a/pv/analogdata.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "analogdata.h" -#include "analogdatasnapshot.h" - -using namespace boost; -using namespace std; - -namespace pv { - -AnalogData::AnalogData(const sr_datafeed_meta_analog &meta, - uint64_t samplerate) : - SignalData(samplerate) -{ -} - -void AnalogData::push_snapshot( - boost::shared_ptr &snapshot) -{ - _snapshots.push_front(snapshot); -} - -deque< shared_ptr >& AnalogData::get_snapshots() -{ - return _snapshots; -} - -} // namespace pv diff --git a/pv/analogdata.h b/pv/analogdata.h deleted file mode 100644 index e1c4ee62..00000000 --- a/pv/analogdata.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_ANALOGDATA_H -#define PULSEVIEW_PV_ANALOGDATA_H - -#include "signaldata.h" - -#include -#include - -extern "C" { -#include -} - -namespace pv { - -class AnalogDataSnapshot; - -class AnalogData : public SignalData -{ -public: - AnalogData(const sr_datafeed_meta_analog &meta, - uint64_t samplerate); - - void push_snapshot( - boost::shared_ptr &snapshot); - - std::deque< boost::shared_ptr >& - get_snapshots(); - -private: - std::deque< boost::shared_ptr > - _snapshots; -}; - -} // namespace pv - -#endif // PULSEVIEW_PV_ANALOGDATA_H diff --git a/pv/analogdatasnapshot.cpp b/pv/analogdatasnapshot.cpp deleted file mode 100644 index c66e9b9c..00000000 --- a/pv/analogdatasnapshot.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include -#include -#include -#include - -#include - -#include "analogdatasnapshot.h" - -using namespace boost; -using namespace std; - -namespace pv { - -AnalogDataSnapshot::AnalogDataSnapshot( - const sr_datafeed_analog &analog) : - DataSnapshot(sizeof(float)) -{ - lock_guard lock(_mutex); - append_payload(analog); -} - -void AnalogDataSnapshot::append_payload( - const sr_datafeed_analog &analog) -{ - lock_guard lock(_mutex); - append_data(analog.data, analog.num_samples); -} - -const float* AnalogDataSnapshot::get_samples() const -{ - return (const float*)_data; -} - -} // namespace pv diff --git a/pv/analogdatasnapshot.h b/pv/analogdatasnapshot.h deleted file mode 100644 index ce8a99da..00000000 --- a/pv/analogdatasnapshot.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_ANALOGDATASNAPSHOT_H -#define PULSEVIEW_PV_ANALOGDATASNAPSHOT_H - -#include "datasnapshot.h" - -#include -#include - -namespace pv { - -class AnalogDataSnapshot : public DataSnapshot -{ -public: - AnalogDataSnapshot(const sr_datafeed_analog &analog); - - void append_payload(const sr_datafeed_analog &analog); - - const float* get_samples() const; -}; - -} // namespace pv - -#endif // PULSEVIEW_PV_ANALOGDATASNAPSHOT_H diff --git a/pv/data/analog.cpp b/pv/data/analog.cpp new file mode 100644 index 00000000..9e43e866 --- /dev/null +++ b/pv/data/analog.cpp @@ -0,0 +1,47 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "analog.h" +#include "analogsnapshot.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +Analog::Analog(const sr_datafeed_meta_analog &meta, + uint64_t samplerate) : + SignalData(samplerate) +{ +} + +void Analog::push_snapshot(shared_ptr &snapshot) +{ + _snapshots.push_front(snapshot); +} + +deque< shared_ptr >& Analog::get_snapshots() +{ + return _snapshots; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/analog.h b/pv/data/analog.h new file mode 100644 index 00000000..2e2ade69 --- /dev/null +++ b/pv/data/analog.h @@ -0,0 +1,57 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_ANALOG_H +#define PULSEVIEW_PV_DATA_ANALOG_H + +#include "signaldata.h" + +#include +#include + +extern "C" { +#include +} + +namespace pv { +namespace data { + +class AnalogSnapshot; + +class Analog : public SignalData +{ +public: + Analog(const sr_datafeed_meta_analog &meta, + uint64_t samplerate); + + void push_snapshot( + boost::shared_ptr &snapshot); + + std::deque< boost::shared_ptr >& + get_snapshots(); + +private: + std::deque< boost::shared_ptr > _snapshots; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_ANALOG_H diff --git a/pv/data/analogsnapshot.cpp b/pv/data/analogsnapshot.cpp new file mode 100644 index 00000000..2bcb99f3 --- /dev/null +++ b/pv/data/analogsnapshot.cpp @@ -0,0 +1,58 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include + +#include + +#include "analogsnapshot.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +AnalogSnapshot::AnalogSnapshot(const sr_datafeed_analog &analog) : + Snapshot(sizeof(float)) +{ + lock_guard lock(_mutex); + append_payload(analog); +} + +void AnalogSnapshot::append_payload( + const sr_datafeed_analog &analog) +{ + lock_guard lock(_mutex); + append_data(analog.data, analog.num_samples); +} + +const float* AnalogSnapshot::get_samples() const +{ + return (const float*)_data; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/analogsnapshot.h b/pv/data/analogsnapshot.h new file mode 100644 index 00000000..9ca08f1e --- /dev/null +++ b/pv/data/analogsnapshot.h @@ -0,0 +1,45 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H +#define PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H + +#include "snapshot.h" + +#include +#include + +namespace pv { +namespace data { + +class AnalogSnapshot : public Snapshot +{ +public: + AnalogSnapshot(const sr_datafeed_analog &analog); + + void append_payload(const sr_datafeed_analog &analog); + + const float* get_samples() const; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_ANALOGSNAPSHOT_H diff --git a/pv/data/logic.cpp b/pv/data/logic.cpp new file mode 100644 index 00000000..7b42e474 --- /dev/null +++ b/pv/data/logic.cpp @@ -0,0 +1,54 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "logic.h" +#include "logicsnapshot.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +Logic::Logic(const sr_datafeed_meta_logic &meta, + uint64_t samplerate) : + SignalData(samplerate), + _num_probes(meta.num_probes) +{ +} + +int Logic::get_num_probes() const +{ + return _num_probes; +} + +void Logic::push_snapshot( + shared_ptr &snapshot) +{ + _snapshots.push_front(snapshot); +} + +deque< shared_ptr >& Logic::get_snapshots() +{ + return _snapshots; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/logic.h b/pv/data/logic.h new file mode 100644 index 00000000..4b70b8f9 --- /dev/null +++ b/pv/data/logic.h @@ -0,0 +1,59 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_LOGIC_H +#define PULSEVIEW_PV_DATA_LOGIC_H + +#include "signaldata.h" + +#include +#include + +extern "C" { +#include +} + +namespace pv { +namespace data { + +class LogicSnapshot; + +class Logic : public SignalData +{ +public: + Logic(const sr_datafeed_meta_logic &meta, uint64_t samplerate); + + int get_num_probes() const; + + void push_snapshot( + boost::shared_ptr &snapshot); + + std::deque< boost::shared_ptr >& + get_snapshots(); + +private: + const int _num_probes; + std::deque< boost::shared_ptr > _snapshots; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_LOGIC_H diff --git a/pv/data/logicsnapshot.cpp b/pv/data/logicsnapshot.cpp new file mode 100644 index 00000000..03e6a54f --- /dev/null +++ b/pv/data/logicsnapshot.cpp @@ -0,0 +1,366 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include +#include + +#include + +#include "logicsnapshot.h" + +using namespace boost; +using namespace std; + +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(const sr_datafeed_logic &logic) : + Snapshot(logic.unitsize), + _last_append_sample(0) +{ + lock_guard lock(_mutex); + memset(_mip_map, 0, sizeof(_mip_map)); + append_payload(logic); +} + +LogicSnapshot::~LogicSnapshot() +{ + lock_guard lock(_mutex); + BOOST_FOREACH(MipMapLevel &l, _mip_map) + free(l.data); +} + +void LogicSnapshot::append_payload( + const sr_datafeed_logic &logic) +{ + assert(_unit_size == logic.unitsize); + + lock_guard lock(_mutex); + + append_data(logic.data, logic.length); + + // Generate the first mip-map from the data + append_payload_to_mipmap(); +} + +void LogicSnapshot::reallocate_mip_map(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; + m.data = realloc(m.data, new_data_length * _unit_size); + } +} + +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_mip_map(m0); + + dest_ptr = (uint8_t*)m0.data + prev_length * _unit_size; + + // Iterate through the samples to populate the first level mipmap + accumulator = 0; + diff_counter = MipMapScaleFactor; + const uint8_t *end_src_ptr = (uint8_t*)_data + + m0.length * _unit_size * MipMapScaleFactor; + for (src_ptr = (uint8_t*)_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 = *(uint64_t*)src_ptr; + accumulator |= _last_append_sample ^ sample; + _last_append_sample = sample; + src_ptr += _unit_size; + } + + *(uint64_t*)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_mip_map(m); + + // Subsample the level lower level + src_ptr = (uint8_t*)ml.data + + _unit_size * prev_length * MipMapScaleFactor; + const uint8_t *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 |= *(uint64_t*)src_ptr; + src_ptr += _unit_size; + } + + *(uint64_t*)dest_ptr = accumulator; + } + } +} + +uint64_t LogicSnapshot::get_sample(uint64_t index) const +{ + assert(_data); + assert(index >= 0 && index < _sample_count); + + return *(uint64_t*)((uint8_t*)_data + index * _unit_size); +} + +void LogicSnapshot::get_subsampled_edges( + std::vector &edges, + uint64_t start, uint64_t end, + float min_length, int sig_index) +{ + uint64_t index = start; + unsigned int level; + bool last_sample; + bool fast_forward; + + assert(start >= 0); + assert(end <= get_sample_count()); + assert(start <= end); + assert(min_length > 0); + assert(sig_index >= 0); + assert(sig_index < SR_MAX_NUM_PROBES); + + lock_guard lock(_mutex); + + const uint64_t block_length = (uint64_t)max(min_length, 1.0f); + const unsigned int min_level = max((int)floorf(logf(min_length) / + LogMipMapScaleFactor) - 1, 0); + const uint64_t sig_mask = 1ULL << sig_index; + + // Store the initial state + last_sample = (get_sample(start) & sig_mask) != 0; + edges.push_back(pair(index++, last_sample)); + + while (index + block_length <= end) + { + //----- Continue to search -----// + level = min_level; + fast_forward = true; + + 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; + fast_forward = last_sample == sample; + } + + 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; + assert(offset >= 0); + + // 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; + assert(offset >= 0); + + // Check if we reached the last block at this + // level, or if there was a change in this block + if (offset >= _mip_map[level].length || + (get_subsample(level, offset) & + sig_mask)) { + // Zoom in unless we reached the minimum + // zoom + if (level == min_level) + break; + + level--; + } else { + // Slide right to the beginning of the + // next mip map block + index = pow2_ceil(index + 1, + level_scale_power); + } + } + + // If individual samples within the limit of resolution, + // do a linear search for the next transition within the + // block + if (min_length < MipMapScaleFactor) { + for (; index < end; index++) { + const bool sample = (get_sample(index) & + sig_mask) != 0; + if (sample != last_sample) + break; + } + } + } + + //----- Store the edge -----// + + // Take the last sample of the quanization block + const int64_t final_index = index + block_length; + if (index + block_length > end) + break; + + // Store the final state + const bool final_sample = + (get_sample(final_index - 1) & sig_mask) != 0; + edges.push_back(pair(index, final_sample)); + + index = final_index; + last_sample = final_sample; + } + + // Add the final state + edges.push_back(pair(end, + get_sample(end) & sig_mask)); +} + +uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const +{ + assert(level >= 0); + assert(_mip_map[level].data); + return *(uint64_t*)((uint8_t*)_mip_map[level].data + + _unit_size * offset); +} + +uint64_t LogicSnapshot::pow2_ceil(uint64_t x, unsigned int power) +{ + const uint64_t p = 1 << power; + return (x + p - 1) / p * p; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/logicsnapshot.h b/pv/data/logicsnapshot.h new file mode 100644 index 00000000..8a851ac2 --- /dev/null +++ b/pv/data/logicsnapshot.h @@ -0,0 +1,108 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H +#define PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H + +#include "snapshot.h" + +#include +#include + +namespace LogicSnapshotTest { + class Pow2; + class Basic; + class LargeData; + class Pulses; + class LongPulses; +} + +namespace pv { +namespace data { + +class LogicSnapshot : public Snapshot +{ +private: + struct MipMapLevel + { + uint64_t length; + uint64_t data_length; + void *data; + }; + +private: + static const unsigned int ScaleStepCount = 10; + static const int MipMapScalePower; + static const int MipMapScaleFactor; + static const float LogMipMapScaleFactor; + static const uint64_t MipMapDataUnit; + +public: + typedef std::pair EdgePair; + +public: + LogicSnapshot(const sr_datafeed_logic &logic); + + virtual ~LogicSnapshot(); + + void append_payload(const sr_datafeed_logic &logic); + +private: + void reallocate_mip_map(MipMapLevel &m); + + void append_payload_to_mipmap(); + + uint64_t get_sample(uint64_t index) const; + +public: + /** + * Parses a logic data snapshot to generate a list of transitions + * in a time interval to a given level of detail. + * @param[out] edges The vector to place the edges into. + * @param[in] start The start sample index. + * @param[in] end The end sample index. + * @param[in] min_length The minimum number of samples that + * can be resolved at this level of detail. + * @param[in] sig_index The index of the signal. + **/ + void get_subsampled_edges(std::vector &edges, + uint64_t start, uint64_t end, + float min_length, int sig_index); + +private: + uint64_t get_subsample(int level, uint64_t offset) const; + + static uint64_t pow2_ceil(uint64_t x, unsigned int power); + +private: + struct MipMapLevel _mip_map[ScaleStepCount]; + uint64_t _last_append_sample; + + friend class LogicSnapshotTest::Pow2; + friend class LogicSnapshotTest::Basic; + friend class LogicSnapshotTest::LargeData; + friend class LogicSnapshotTest::Pulses; + friend class LogicSnapshotTest::LongPulses; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_LOGICSNAPSHOT_H diff --git a/pv/data/signaldata.cpp b/pv/data/signaldata.cpp new file mode 100644 index 00000000..2c6e3c66 --- /dev/null +++ b/pv/data/signaldata.cpp @@ -0,0 +1,43 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "signaldata.h" + +namespace pv { +namespace data { + +SignalData::SignalData(double samplerate) : + _samplerate(samplerate), + _start_time(0) +{ +} + +double SignalData::get_samplerate() const +{ + return _samplerate; +} + +double SignalData::get_start_time() const +{ + return _start_time; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/signaldata.h b/pv/data/signaldata.h new file mode 100644 index 00000000..7f64bdb4 --- /dev/null +++ b/pv/data/signaldata.h @@ -0,0 +1,46 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_SIGNALDATA_H +#define PULSEVIEW_PV_DATA_SIGNALDATA_H + +#include + +namespace pv { +namespace data { + +class SignalData +{ +public: + SignalData(double samplerate); + +public: + double get_samplerate() const; + double get_start_time() const; + +protected: + const double _samplerate; + const double _start_time; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_SIGNALDATA_H diff --git a/pv/data/snapshot.cpp b/pv/data/snapshot.cpp new file mode 100644 index 00000000..f3855e06 --- /dev/null +++ b/pv/data/snapshot.cpp @@ -0,0 +1,63 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "snapshot.h" + +#include +#include +#include + +using namespace boost; + +namespace pv { +namespace data { + +Snapshot::Snapshot(int unit_size) : + _data(NULL), + _sample_count(0), + _unit_size(unit_size) +{ + lock_guard lock(_mutex); + assert(_unit_size > 0); +} + +Snapshot::~Snapshot() +{ + lock_guard lock(_mutex); + free(_data); +} + +uint64_t Snapshot::get_sample_count() +{ + lock_guard lock(_mutex); + return _sample_count; +} + +void Snapshot::append_data(void *data, uint64_t samples) +{ + lock_guard lock(_mutex); + _data = realloc(_data, (_sample_count + samples) * _unit_size); + memcpy((uint8_t*)_data + _sample_count * _unit_size, + data, samples * _unit_size); + _sample_count += samples; +} + +} // namespace data +} // namespace pv diff --git a/pv/data/snapshot.h b/pv/data/snapshot.h new file mode 100644 index 00000000..7f36ee78 --- /dev/null +++ b/pv/data/snapshot.h @@ -0,0 +1,55 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_DATA_SNAPSHOT_H +#define PULSEVIEW_PV_DATA_SNAPSHOT_H + +extern "C" { +#include +} + +#include + +namespace pv { +namespace data { + +class Snapshot +{ +public: + Snapshot(int unit_size); + + virtual ~Snapshot(); + + uint64_t get_sample_count(); + +protected: + void append_data(void *data, uint64_t samples); + +protected: + mutable boost::recursive_mutex _mutex; + void *_data; + uint64_t _sample_count; + int _unit_size; +}; + +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_DATA_SNAPSHOT_H diff --git a/pv/datasnapshot.cpp b/pv/datasnapshot.cpp deleted file mode 100644 index 040d506a..00000000 --- a/pv/datasnapshot.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "datasnapshot.h" - -#include -#include -#include - -using namespace boost; - -namespace pv { - -DataSnapshot::DataSnapshot(int unit_size) : - _data(NULL), - _sample_count(0), - _unit_size(unit_size) -{ - lock_guard lock(_mutex); - assert(_unit_size > 0); -} - -DataSnapshot::~DataSnapshot() -{ - lock_guard lock(_mutex); - free(_data); -} - -uint64_t DataSnapshot::get_sample_count() -{ - lock_guard lock(_mutex); - return _sample_count; -} - -void DataSnapshot::append_data(void *data, uint64_t samples) -{ - lock_guard lock(_mutex); - _data = realloc(_data, (_sample_count + samples) * _unit_size); - memcpy((uint8_t*)_data + _sample_count * _unit_size, - data, samples * _unit_size); - _sample_count += samples; -} - -} // namespace pv diff --git a/pv/datasnapshot.h b/pv/datasnapshot.h deleted file mode 100644 index 2a6651e8..00000000 --- a/pv/datasnapshot.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_DATASNAPSHOT_H -#define PULSEVIEW_PV_DATASNAPSHOT_H - -extern "C" { -#include -} - -#include - -namespace pv { - -class DataSnapshot -{ -public: - DataSnapshot(int unit_size); - - virtual ~DataSnapshot(); - - uint64_t get_sample_count(); - -protected: - void append_data(void *data, uint64_t samples); - -protected: - mutable boost::recursive_mutex _mutex; - void *_data; - uint64_t _sample_count; - int _unit_size; -}; - -} // namespace pv - -#endif // PULSEVIEW_PV_DATASNAPSHOT_H diff --git a/pv/logicdata.cpp b/pv/logicdata.cpp deleted file mode 100644 index 492961fb..00000000 --- a/pv/logicdata.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "logicdata.h" -#include "logicdatasnapshot.h" - -using namespace boost; -using namespace std; - -namespace pv { - -LogicData::LogicData(const sr_datafeed_meta_logic &meta, - uint64_t samplerate) : - SignalData(samplerate), - _num_probes(meta.num_probes) -{ -} - -int LogicData::get_num_probes() const -{ - return _num_probes; -} - -void LogicData::push_snapshot( - boost::shared_ptr &snapshot) -{ - _snapshots.push_front(snapshot); -} - -deque< shared_ptr >& LogicData::get_snapshots() -{ - return _snapshots; -} - -} // namespace pv diff --git a/pv/logicdata.h b/pv/logicdata.h deleted file mode 100644 index af1d32ee..00000000 --- a/pv/logicdata.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_LOGICDATA_H -#define PULSEVIEW_PV_LOGICDATA_H - -#include "signaldata.h" - -#include -#include - -extern "C" { -#include -} - -namespace pv { - -class LogicDataSnapshot; - -class LogicData : public SignalData -{ -public: - LogicData(const sr_datafeed_meta_logic &meta, uint64_t samplerate); - - int get_num_probes() const; - - void push_snapshot( - boost::shared_ptr &snapshot); - - std::deque< boost::shared_ptr >& - get_snapshots(); - -private: - const int _num_probes; - std::deque< boost::shared_ptr > - _snapshots; -}; - -} // namespace pv - -#endif // PULSEVIEW_PV_LOGICDATA_H diff --git a/pv/logicdatasnapshot.cpp b/pv/logicdatasnapshot.cpp deleted file mode 100644 index bd2404a6..00000000 --- a/pv/logicdatasnapshot.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include -#include -#include -#include - -#include - -#include "logicdatasnapshot.h" - -using namespace boost; -using namespace std; - -namespace pv { - -const int LogicDataSnapshot::MipMapScalePower = 4; -const int LogicDataSnapshot::MipMapScaleFactor = 1 << MipMapScalePower; -const float LogicDataSnapshot::LogMipMapScaleFactor = logf(MipMapScaleFactor); -const uint64_t LogicDataSnapshot::MipMapDataUnit = 64*1024; // bytes - -LogicDataSnapshot::LogicDataSnapshot( - const sr_datafeed_logic &logic) : - DataSnapshot(logic.unitsize), - _last_append_sample(0) -{ - lock_guard lock(_mutex); - memset(_mip_map, 0, sizeof(_mip_map)); - append_payload(logic); -} - -LogicDataSnapshot::~LogicDataSnapshot() -{ - lock_guard lock(_mutex); - BOOST_FOREACH(MipMapLevel &l, _mip_map) - free(l.data); -} - -void LogicDataSnapshot::append_payload( - const sr_datafeed_logic &logic) -{ - assert(_unit_size == logic.unitsize); - - lock_guard lock(_mutex); - - append_data(logic.data, logic.length); - - // Generate the first mip-map from the data - append_payload_to_mipmap(); -} - -void LogicDataSnapshot::reallocate_mip_map(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; - m.data = realloc(m.data, new_data_length * _unit_size); - } -} - -void LogicDataSnapshot::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_mip_map(m0); - - dest_ptr = (uint8_t*)m0.data + prev_length * _unit_size; - - // Iterate through the samples to populate the first level mipmap - accumulator = 0; - diff_counter = MipMapScaleFactor; - const uint8_t *end_src_ptr = (uint8_t*)_data + - m0.length * _unit_size * MipMapScaleFactor; - for (src_ptr = (uint8_t*)_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 = *(uint64_t*)src_ptr; - accumulator |= _last_append_sample ^ sample; - _last_append_sample = sample; - src_ptr += _unit_size; - } - - *(uint64_t*)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_mip_map(m); - - // Subsample the level lower level - src_ptr = (uint8_t*)ml.data + - _unit_size * prev_length * MipMapScaleFactor; - const uint8_t *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 |= *(uint64_t*)src_ptr; - src_ptr += _unit_size; - } - - *(uint64_t*)dest_ptr = accumulator; - } - } -} - -uint64_t LogicDataSnapshot::get_sample(uint64_t index) const -{ - assert(_data); - assert(index >= 0 && index < _sample_count); - - return *(uint64_t*)((uint8_t*)_data + index * _unit_size); -} - -void LogicDataSnapshot::get_subsampled_edges( - std::vector &edges, - uint64_t start, uint64_t end, - float min_length, int sig_index) -{ - uint64_t index = start; - unsigned int level; - bool last_sample; - bool fast_forward; - - assert(start >= 0); - assert(end <= get_sample_count()); - assert(start <= end); - assert(min_length > 0); - assert(sig_index >= 0); - assert(sig_index < SR_MAX_NUM_PROBES); - - lock_guard lock(_mutex); - - const uint64_t block_length = (uint64_t)max(min_length, 1.0f); - const unsigned int min_level = max((int)floorf(logf(min_length) / - LogMipMapScaleFactor) - 1, 0); - const uint64_t sig_mask = 1ULL << sig_index; - - // Store the initial state - last_sample = (get_sample(start) & sig_mask) != 0; - edges.push_back(pair(index++, last_sample)); - - while (index + block_length <= end) - { - //----- Continue to search -----// - level = min_level; - fast_forward = true; - - 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; - fast_forward = last_sample == sample; - } - - 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; - assert(offset >= 0); - - // 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; - assert(offset >= 0); - - // Check if we reached the last block at this - // level, or if there was a change in this block - if (offset >= _mip_map[level].length || - (get_subsample(level, offset) & - sig_mask)) { - // Zoom in unless we reached the minimum - // zoom - if (level == min_level) - break; - - level--; - } else { - // Slide right to the beginning of the - // next mip map block - index = pow2_ceil(index + 1, - level_scale_power); - } - } - - // If individual samples within the limit of resolution, - // do a linear search for the next transition within the - // block - if (min_length < MipMapScaleFactor) { - for (; index < end; index++) { - const bool sample = (get_sample(index) & - sig_mask) != 0; - if (sample != last_sample) - break; - } - } - } - - //----- Store the edge -----// - - // Take the last sample of the quanization block - const int64_t final_index = index + block_length; - if (index + block_length > end) - break; - - // Store the final state - const bool final_sample = - (get_sample(final_index - 1) & sig_mask) != 0; - edges.push_back(pair(index, final_sample)); - - index = final_index; - last_sample = final_sample; - } - - // Add the final state - edges.push_back(pair(end, - get_sample(end) & sig_mask)); -} - -uint64_t LogicDataSnapshot::get_subsample(int level, uint64_t offset) const -{ - assert(level >= 0); - assert(_mip_map[level].data); - return *(uint64_t*)((uint8_t*)_mip_map[level].data + - _unit_size * offset); -} - -uint64_t LogicDataSnapshot::pow2_ceil(uint64_t x, unsigned int power) -{ - const uint64_t p = 1 << power; - return (x + p - 1) / p * p; -} - -} // namespace pv diff --git a/pv/logicdatasnapshot.h b/pv/logicdatasnapshot.h deleted file mode 100644 index 63680200..00000000 --- a/pv/logicdatasnapshot.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_LOGICDATASNAPSHOT_H -#define PULSEVIEW_PV_LOGICDATASNAPSHOT_H - -#include "datasnapshot.h" - -#include -#include - -namespace LogicDataSnapshotTest { - class Pow2; - class Basic; - class LargeData; - class Pulses; - class LongPulses; -} - -namespace pv { - -class LogicDataSnapshot : public DataSnapshot -{ -private: - struct MipMapLevel - { - uint64_t length; - uint64_t data_length; - void *data; - }; - -private: - static const unsigned int ScaleStepCount = 10; - static const int MipMapScalePower; - static const int MipMapScaleFactor; - static const float LogMipMapScaleFactor; - static const uint64_t MipMapDataUnit; - -public: - typedef std::pair EdgePair; - -public: - LogicDataSnapshot(const sr_datafeed_logic &logic); - - virtual ~LogicDataSnapshot(); - - void append_payload(const sr_datafeed_logic &logic); - -private: - void reallocate_mip_map(MipMapLevel &m); - - void append_payload_to_mipmap(); - - uint64_t get_sample(uint64_t index) const; - -public: - /** - * Parses a logic data snapshot to generate a list of transitions - * in a time interval to a given level of detail. - * @param[out] edges The vector to place the edges into. - * @param[in] start The start sample index. - * @param[in] end The end sample index. - * @param[in] min_length The minimum number of samples that - * can be resolved at this level of detail. - * @param[in] sig_index The index of the signal. - **/ - void get_subsampled_edges(std::vector &edges, - uint64_t start, uint64_t end, - float min_length, int sig_index); - -private: - uint64_t get_subsample(int level, uint64_t offset) const; - - static uint64_t pow2_ceil(uint64_t x, unsigned int power); - -private: - struct MipMapLevel _mip_map[ScaleStepCount]; - uint64_t _last_append_sample; - - friend class LogicDataSnapshotTest::Pow2; - friend class LogicDataSnapshotTest::Basic; - friend class LogicDataSnapshotTest::LargeData; - friend class LogicDataSnapshotTest::Pulses; - friend class LogicDataSnapshotTest::LongPulses; -}; - -} // namespace pv - -#endif // PULSEVIEW_PV_LOGICDATASNAPSHOT_H diff --git a/pv/signaldata.cpp b/pv/signaldata.cpp deleted file mode 100644 index 1763b41b..00000000 --- a/pv/signaldata.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "signaldata.h" - -namespace pv { - -SignalData::SignalData(double samplerate) : - _samplerate(samplerate), - _start_time(0) -{ -} - -double SignalData::get_samplerate() const -{ - return _samplerate; -} - -double SignalData::get_start_time() const -{ - return _start_time; -} - -} // namespace pv diff --git a/pv/signaldata.h b/pv/signaldata.h deleted file mode 100644 index 94268aec..00000000 --- a/pv/signaldata.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_SIGNALDATA_H -#define PULSEVIEW_PV_SIGNALDATA_H - -#include - -namespace pv { - -class SignalData -{ -public: - SignalData(double samplerate); - -public: - double get_samplerate() const; - double get_start_time() const; - -protected: - const double _samplerate; - const double _start_time; -}; - -} // namespace pv - -#endif // PULSEVIEW_PV_SIGNALDATA_H diff --git a/pv/sigsession.cpp b/pv/sigsession.cpp index b7e910e3..03cf238a 100644 --- a/pv/sigsession.cpp +++ b/pv/sigsession.cpp @@ -20,10 +20,10 @@ #include "sigsession.h" -#include "analogdata.h" -#include "analogdatasnapshot.h" -#include "logicdata.h" -#include "logicdatasnapshot.h" +#include "data/analog.h" +#include "data/analogsnapshot.h" +#include "data/logic.h" +#include "data/logicsnapshot.h" #include "view/analogsignal.h" #include "view/logicsignal.h" @@ -103,7 +103,7 @@ vector< shared_ptr > SigSession::get_signals() return _signals; } -boost::shared_ptr SigSession::get_data() +boost::shared_ptr SigSession::get_data() { return _logic_data; } @@ -188,8 +188,8 @@ void SigSession::feed_in_meta_logic(const struct sr_dev_inst *sdi, lock_guard data_lock(_data_mutex); lock_guard sampling_lock(_sampling_mutex); - // Create an empty LogicData for coming data snapshots - _logic_data.reset(new LogicData(meta_logic, _sample_rate)); + // Create an empty data::Logic for coming data snapshots + _logic_data.reset(new data::Logic(meta_logic, _sample_rate)); assert(_logic_data); if (!_logic_data) return; @@ -224,8 +224,8 @@ void SigSession::feed_in_meta_analog(const struct sr_dev_inst *sdi, lock_guard data_lock(_data_mutex); lock_guard sampling_lock(_sampling_mutex); - // Create an empty AnalogData for coming data snapshots - _analog_data.reset(new AnalogData( + // Create an empty data::Analog for coming data snapshots + _analog_data.reset(new data::Analog( meta_analog, _sample_rate)); assert(_analog_data); if (!_analog_data) @@ -250,8 +250,8 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic) if (!_cur_logic_snapshot) { // Create a new data snapshot - _cur_logic_snapshot = shared_ptr( - new LogicDataSnapshot(logic)); + _cur_logic_snapshot = shared_ptr( + new data::LogicSnapshot(logic)); _logic_data->push_snapshot(_cur_logic_snapshot); } else @@ -269,8 +269,8 @@ void SigSession::feed_in_analog(const sr_datafeed_analog &analog) if (!_cur_analog_snapshot) { // Create a new data snapshot - _cur_analog_snapshot = shared_ptr( - new AnalogDataSnapshot(analog)); + _cur_analog_snapshot = shared_ptr( + new data::AnalogSnapshot(analog)); _analog_data->push_snapshot(_cur_analog_snapshot); } else diff --git a/pv/sigsession.h b/pv/sigsession.h index 308b0827..d5ec200a 100644 --- a/pv/sigsession.h +++ b/pv/sigsession.h @@ -36,10 +36,12 @@ extern "C" { namespace pv { -class AnalogData; -class AnalogDataSnapshot; -class LogicData; -class LogicDataSnapshot; +namespace data { +class Analog; +class AnalogSnapshot; +class Logic; +class LogicSnapshot; +} namespace view { class Signal; @@ -72,7 +74,7 @@ public: std::vector< boost::shared_ptr > get_signals(); - boost::shared_ptr get_data(); + boost::shared_ptr get_data(); private: void set_capture_state(capture_state state); @@ -108,10 +110,10 @@ private: std::vector< boost::shared_ptr > _signals; mutable boost::mutex _data_mutex; - boost::shared_ptr _logic_data; - boost::shared_ptr _cur_logic_snapshot; - boost::shared_ptr _analog_data; - boost::shared_ptr _cur_analog_snapshot; + boost::shared_ptr _logic_data; + boost::shared_ptr _cur_logic_snapshot; + boost::shared_ptr _analog_data; + boost::shared_ptr _cur_analog_snapshot; std::auto_ptr _sampling_thread; diff --git a/pv/view/analogsignal.cpp b/pv/view/analogsignal.cpp index 126ecb1f..fb5eba61 100644 --- a/pv/view/analogsignal.cpp +++ b/pv/view/analogsignal.cpp @@ -23,8 +23,8 @@ #include #include "analogsignal.h" -#include "../analogdata.h" -#include "../analogdatasnapshot.h" +#include "pv/data/analog.h" +#include "pv/data/analogsnapshot.h" using namespace boost; using namespace std; @@ -32,7 +32,7 @@ using namespace std; namespace pv { namespace view { -AnalogSignal::AnalogSignal(QString name, shared_ptr data) : +AnalogSignal::AnalogSignal(QString name, shared_ptr data) : Signal(name), _data(data) { @@ -45,12 +45,12 @@ void AnalogSignal::paint(QPainter &p, const QRect &rect, double scale, assert(scale > 0); assert(_data); - const deque< shared_ptr > &snapshots = + const deque< shared_ptr > &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; - const shared_ptr &snapshot = + const shared_ptr &snapshot = snapshots.front(); const double pixels_offset = offset / scale; diff --git a/pv/view/analogsignal.h b/pv/view/analogsignal.h index b3cafd2f..7bc0ed6e 100644 --- a/pv/view/analogsignal.h +++ b/pv/view/analogsignal.h @@ -27,7 +27,9 @@ namespace pv { -class AnalogData; +namespace data { +class Analog; +} namespace view { @@ -35,7 +37,7 @@ class AnalogSignal : public Signal { public: AnalogSignal(QString name, - boost::shared_ptr data); + boost::shared_ptr data); /** * Paints the signal with a QPainter @@ -57,7 +59,7 @@ private: int get_nominal_offset(const QRect &rect) const; private: - boost::shared_ptr _data; + boost::shared_ptr _data; }; } // namespace view diff --git a/pv/view/logicsignal.cpp b/pv/view/logicsignal.cpp index 03d6aa25..d23da5bb 100644 --- a/pv/view/logicsignal.cpp +++ b/pv/view/logicsignal.cpp @@ -23,8 +23,8 @@ #include #include "logicsignal.h" -#include "../logicdata.h" -#include "../logicdatasnapshot.h" +#include "pv/data/logic.h" +#include "pv/data/logicsnapshot.h" using namespace boost; using namespace std; @@ -51,7 +51,7 @@ const QColor LogicSignal::LogicSignalColours[10] = { QColor(0xEE, 0xEE, 0xEC), // White }; -LogicSignal::LogicSignal(QString name, shared_ptr data, +LogicSignal::LogicSignal(QString name, shared_ptr data, int probe_index) : Signal(name), _probe_index(probe_index), @@ -75,12 +75,12 @@ void LogicSignal::paint(QPainter &p, const QRect &rect, double scale, const float high_offset = rect.top() + 0.5f; const float low_offset = rect.bottom() + 0.5f; - const deque< shared_ptr > &snapshots = + const deque< shared_ptr > &snapshots = _data->get_snapshots(); if (snapshots.empty()) return; - const shared_ptr &snapshot = + const shared_ptr &snapshot = snapshots.front(); const double pixels_offset = offset / scale; @@ -102,7 +102,7 @@ void LogicSignal::paint(QPainter &p, const QRect &rect, double scale, QLineF *const edge_lines = new QLineF[edge_count]; line = edge_lines; - for (vector::const_iterator i = + for (vector::const_iterator i = edges.begin() + 1; i != edges.end() - 1; i++) { const float x = ((*i).first / samples_per_pixel - @@ -135,7 +135,7 @@ void LogicSignal::paint_caps(QPainter &p, QLineF *const lines, { QLineF *line = lines; - for (vector::const_iterator i = + for (vector::const_iterator i = edges.begin(); i != (edges.end() - 1); i++) if ((*i).second == level) { *line++ = QLineF( diff --git a/pv/view/logicsignal.h b/pv/view/logicsignal.h index 4241f801..e20f13c7 100644 --- a/pv/view/logicsignal.h +++ b/pv/view/logicsignal.h @@ -27,7 +27,9 @@ namespace pv { -class LogicData; +namespace data { +class Logic; +} namespace view { @@ -44,7 +46,7 @@ private: public: LogicSignal(QString name, - boost::shared_ptr data, + boost::shared_ptr data, int probe_index); /** @@ -72,7 +74,7 @@ private: private: int _probe_index; - boost::shared_ptr _data; + boost::shared_ptr _data; }; } // namespace view diff --git a/pv/view/signal.h b/pv/view/signal.h index 72d42cc2..72019032 100644 --- a/pv/view/signal.h +++ b/pv/view/signal.h @@ -32,7 +32,9 @@ namespace pv { +namespace data { class SignalData; +} namespace view { diff --git a/pv/view/view.cpp b/pv/view/view.cpp index 8fca4be2..64ecf83a 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -34,9 +34,9 @@ #include "view.h" #include "viewport.h" -#include "../logicdata.h" -#include "../logicdatasnapshot.h" -#include "../sigsession.h" +#include "pv/sigsession.h" +#include "pv/data/logic.h" +#include "pv/data/logicsnapshot.h" using namespace boost; using namespace std; @@ -189,7 +189,7 @@ void View::normalize_layout() void View::get_scroll_layout(double &length, double &offset) const { - const shared_ptr sig_data = _session.get_data(); + const shared_ptr sig_data = _session.get_data(); if (!sig_data) return; @@ -319,11 +319,11 @@ void View::data_updated() { // Get the new data length _data_length = 0; - shared_ptr sig_data = _session.get_data(); + shared_ptr sig_data = _session.get_data(); if (sig_data) { - deque< shared_ptr > &snapshots = + deque< shared_ptr > &snapshots = sig_data->get_snapshots(); - BOOST_FOREACH(shared_ptr s, snapshots) + BOOST_FOREACH(shared_ptr s, snapshots) if (s) _data_length = max(_data_length, s->get_sample_count()); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6da1a247..5fff12b0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,9 +21,9 @@ find_package(Boost 1.46 COMPONENTS unit_test_framework REQUIRED) set(pulseview_TEST_SOURCES - ${PROJECT_SOURCE_DIR}/pv/datasnapshot.cpp - ${PROJECT_SOURCE_DIR}/pv/logicdatasnapshot.cpp - logicdatasnapshot.cpp + ${PROJECT_SOURCE_DIR}/pv/data/snapshot.cpp + ${PROJECT_SOURCE_DIR}/pv/data/logicsnapshot.cpp + data/logicsnapshot.cpp test.cpp ) diff --git a/test/data/logicsnapshot.cpp b/test/data/logicsnapshot.cpp new file mode 100644 index 00000000..1c536791 --- /dev/null +++ b/test/data/logicsnapshot.cpp @@ -0,0 +1,475 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#define __STDC_LIMIT_MACROS +#include + +#include + +#include "../../pv/data/logicsnapshot.h" + +using namespace std; + +using pv::data::LogicSnapshot; + +BOOST_AUTO_TEST_SUITE(LogicSnapshotTest) + +void push_logic(LogicSnapshot &s, unsigned int length, uint8_t value) +{ + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = length; + logic.data = new uint8_t[length]; + memset(logic.data, value, length * logic.unitsize); + s.append_payload(logic); + delete[] (uint8_t*)logic.data; +} + +BOOST_AUTO_TEST_CASE(Pow2) +{ + BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(0, 0), 0); + BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(1, 0), 1); + BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(2, 0), 2); + + BOOST_CHECK_EQUAL( + LogicSnapshot::pow2_ceil(INT64_MIN, 0), INT64_MIN); + BOOST_CHECK_EQUAL( + LogicSnapshot::pow2_ceil(INT64_MAX, 0), INT64_MAX); + + BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(0, 1), 0); + BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(1, 1), 2); + BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(2, 1), 2); + BOOST_CHECK_EQUAL(LogicSnapshot::pow2_ceil(3, 1), 4); +} + +BOOST_AUTO_TEST_CASE(Basic) +{ + // Create an empty LogicSnapshot object + sr_datafeed_logic logic; + logic.length = 0; + logic.unitsize = 1; + logic.data = NULL; + + LogicSnapshot s(logic); + + //----- Test LogicSnapshot::push_logic -----// + + BOOST_CHECK(s.get_sample_count() == 0); + for (unsigned int i = 0; i < LogicSnapshot::ScaleStepCount; i++) + { + const LogicSnapshot::MipMapLevel &m = s._mip_map[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + // Push 8 samples of all zeros + push_logic(s, 8, 0); + + BOOST_CHECK(s.get_sample_count() == 8); + + // There should not be enough samples to have a single mip map sample + for (unsigned int i = 0; i < LogicSnapshot::ScaleStepCount; i++) + { + const LogicSnapshot::MipMapLevel &m = s._mip_map[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + // Push 8 samples of 0x11s to bring the total up to 16 + push_logic(s, 8, 0x11); + + // There should now be enough data for exactly one sample + // in mip map level 0, and that sample should be 0 + const LogicSnapshot::MipMapLevel &m0 = s._mip_map[0]; + BOOST_CHECK_EQUAL(m0.length, 1); + BOOST_CHECK_EQUAL(m0.data_length, LogicSnapshot::MipMapDataUnit); + BOOST_REQUIRE(m0.data != NULL); + BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[0], 0x11); + + // The higher levels should still be empty + for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) + { + const LogicSnapshot::MipMapLevel &m = s._mip_map[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + // Push 240 samples of all zeros to bring the total up to 256 + push_logic(s, 240, 0); + + BOOST_CHECK_EQUAL(m0.length, 16); + BOOST_CHECK_EQUAL(m0.data_length, LogicSnapshot::MipMapDataUnit); + + BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[1], 0x11); + for (unsigned int i = 2; i < m0.length; i++) + BOOST_CHECK_EQUAL(((uint8_t*)m0.data)[i], 0); + + const LogicSnapshot::MipMapLevel &m1 = s._mip_map[1]; + BOOST_CHECK_EQUAL(m1.length, 1); + BOOST_CHECK_EQUAL(m1.data_length, LogicSnapshot::MipMapDataUnit); + BOOST_REQUIRE(m1.data != NULL); + BOOST_CHECK_EQUAL(((uint8_t*)m1.data)[0], 0x11); + + //----- Test LogicSnapshot::get_subsampled_edges -----// + + // Test a full view at full zoom. + vector edges; + s.get_subsampled_edges(edges, 0, 255, 1, 0); + BOOST_REQUIRE_EQUAL(edges.size(), 4); + + BOOST_CHECK_EQUAL(edges[0].first, 0); + BOOST_CHECK_EQUAL(edges[1].first, 8); + BOOST_CHECK_EQUAL(edges[2].first, 16); + BOOST_CHECK_EQUAL(edges[3].first, 255); + + // 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, 17); +} + +BOOST_AUTO_TEST_CASE(LargeData) +{ + uint8_t prev_sample; + const unsigned int Length = 1000000; + + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = Length; + logic.data = new uint8_t[Length]; + uint8_t *data = (uint8_t*)logic.data; + + for (unsigned int i = 0; i < Length; i++) + *data++ = (uint8_t)(i >> 8); + + LogicSnapshot s(logic); + delete[] (uint8_t*)logic.data; + + BOOST_CHECK(s.get_sample_count() == Length); + + // Check mip map level 0 + BOOST_CHECK_EQUAL(s._mip_map[0].length, 62500); + BOOST_CHECK_EQUAL(s._mip_map[0].data_length, + LogicSnapshot::MipMapDataUnit); + BOOST_REQUIRE(s._mip_map[0].data != NULL); + + prev_sample = 0; + for (unsigned int i = 0; i < s._mip_map[0].length;) + { + BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); + + const uint8_t sample = (uint8_t)((i*16) >> 8); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, + prev_sample ^ sample); + prev_sample = sample; + + for (int j = 1; i < s._mip_map[0].length && j < 16; j++) + { + BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0); + } + } + + // Check mip map level 1 + BOOST_CHECK_EQUAL(s._mip_map[1].length, 3906); + BOOST_CHECK_EQUAL(s._mip_map[1].data_length, + LogicSnapshot::MipMapDataUnit); + BOOST_REQUIRE(s._mip_map[1].data != NULL); + + prev_sample = 0; + for (unsigned int i = 0; i < s._mip_map[1].length; i++) + { + BOOST_TEST_MESSAGE("Testing mip_map[1].data[" << i << "]"); + + const uint8_t sample = i; + const uint8_t expected = sample ^ prev_sample; + prev_sample = i; + + BOOST_CHECK_EQUAL(s.get_subsample(1, i) & 0xFF, expected); + } + + // Check mip map level 2 + BOOST_CHECK_EQUAL(s._mip_map[2].length, 244); + BOOST_CHECK_EQUAL(s._mip_map[2].data_length, + LogicSnapshot::MipMapDataUnit); + BOOST_REQUIRE(s._mip_map[2].data != NULL); + + prev_sample = 0; + for (unsigned int i = 0; i < s._mip_map[2].length; i++) + { + BOOST_TEST_MESSAGE("Testing mip_map[2].data[" << i << "]"); + + const uint8_t sample = i << 4; + const uint8_t expected = (sample ^ prev_sample) | 0x0F; + prev_sample = sample; + + BOOST_CHECK_EQUAL(s.get_subsample(2, i) & 0xFF, expected); + } + + // Check mip map level 3 + BOOST_CHECK_EQUAL(s._mip_map[3].length, 15); + BOOST_CHECK_EQUAL(s._mip_map[3].data_length, + LogicSnapshot::MipMapDataUnit); + BOOST_REQUIRE(s._mip_map[3].data != NULL); + + for (unsigned int i = 0; i < s._mip_map[3].length; i++) + BOOST_CHECK_EQUAL(*((uint8_t*)s._mip_map[3].data + i), + 0xFF); + + // Check the higher levels + for (unsigned int i = 4; i < LogicSnapshot::ScaleStepCount; i++) + { + const LogicSnapshot::MipMapLevel &m = s._mip_map[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + //----- Test LogicSnapshot::get_subsampled_edges -----// + // Check in normal case + vector edges; + s.get_subsampled_edges(edges, 0, Length-1, 1, 7); + + BOOST_CHECK_EQUAL(edges.size(), 32); + + for (unsigned int i = 0; i < edges.size() - 1; i++) + { + BOOST_CHECK_EQUAL(edges[i].first, i * 32768); + BOOST_CHECK_EQUAL(edges[i].second, i & 1); + } + + BOOST_CHECK_EQUAL(edges[31].first, 999999); + + // Check in very low zoom case + edges.clear(); + s.get_subsampled_edges(edges, 0, Length-1, 50e6f, 7); + + BOOST_CHECK_EQUAL(edges.size(), 2); +} + +BOOST_AUTO_TEST_CASE(Pulses) +{ + const int Cycles = 3; + const int Period = 64; + const int Length = Cycles * Period; + + vector edges; + + //----- Create a LogicSnapshot -----// + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = Length; + logic.data = (uint64_t*)new uint8_t[Length]; + uint8_t *p = (uint8_t*)logic.data; + + for (int i = 0; i < Cycles; i++) { + *p++ = 0xFF; + for (int j = 1; j < Period; j++) + *p++ = 0x00; + } + + LogicSnapshot s(logic); + delete[] (uint8_t*)logic.data; + + //----- Check the mip-map -----// + // Check mip map level 0 + BOOST_CHECK_EQUAL(s._mip_map[0].length, 12); + BOOST_CHECK_EQUAL(s._mip_map[0].data_length, + LogicSnapshot::MipMapDataUnit); + BOOST_REQUIRE(s._mip_map[0].data != NULL); + + for (unsigned int i = 0; i < s._mip_map[0].length;) { + BOOST_TEST_MESSAGE("Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0xFF); + + for (int j = 1; + i < s._mip_map[0].length && + j < Period/LogicSnapshot::MipMapScaleFactor; j++) { + BOOST_TEST_MESSAGE( + "Testing mip_map[0].data[" << i << "]"); + BOOST_CHECK_EQUAL(s.get_subsample(0, i++) & 0xFF, 0x00); + } + } + + // Check the higher levels are all inactive + for (unsigned int i = 1; i < LogicSnapshot::ScaleStepCount; i++) { + const LogicSnapshot::MipMapLevel &m = s._mip_map[i]; + BOOST_CHECK_EQUAL(m.length, 0); + BOOST_CHECK_EQUAL(m.data_length, 0); + BOOST_CHECK(m.data == NULL); + } + + //----- Test get_subsampled_edges at reduced scale -----// + s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2); + BOOST_REQUIRE_EQUAL(edges.size(), Cycles + 2); + + BOOST_CHECK_EQUAL(0, false); + for (unsigned int i = 1; i < edges.size(); i++) + BOOST_CHECK_EQUAL(edges[i].second, false); +} + +BOOST_AUTO_TEST_CASE(LongPulses) +{ + const int Cycles = 3; + const int Period = 64; + const int PulseWidth = 16; + const int Length = Cycles * Period; + + int j; + vector edges; + + //----- Create a LogicSnapshot -----// + sr_datafeed_logic logic; + logic.unitsize = 8; + logic.length = Length; + 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-1); + 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-1); + BOOST_CHECK_EQUAL(edges.back().second, false); +} + +BOOST_AUTO_TEST_CASE(LisaMUsbHid) +{ + /* This test was created from the beginning of the USB_DM signal in + * sigrok-dumps-usb/lisa_m_usbhid/lisa_m_usbhid.sr + */ + + const int Edges[] = { + 7028, 7033, 7036, 7041, 7044, 7049, 7053, 7066, 7073, 7079, + 7086, 7095, 7103, 7108, 7111, 7116, 7119, 7124, 7136, 7141, + 7148, 7162, 7500 + }; + const int Length = Edges[countof(Edges) - 1]; + + bool state = false; + int lastEdgePos = 0; + + //----- Create a LogicSnapshot -----// + sr_datafeed_logic logic; + logic.unitsize = 1; + logic.length = Length; + logic.data = new uint8_t[Length]; + uint8_t *data = (uint8_t*)logic.data; + + for (unsigned int i = 0; i < countof(Edges); i++) { + const int edgePos = Edges[i]; + memset(&data[lastEdgePos], state ? 0x02 : 0, + edgePos - lastEdgePos - 1); + + lastEdgePos = edgePos; + state = !state; + } + + LogicSnapshot s(logic); + delete[] (uint64_t*)logic.data; + + vector edges; + + + /* The trailing edge of the pulse train is falling in the source data. + * Check this is always true at different scales + */ + + edges.clear(); + s.get_subsampled_edges(edges, 0, Length-1, 33.333332f, 1); + BOOST_CHECK_EQUAL(edges[edges.size() - 2].second, false); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/logicdatasnapshot.cpp b/test/logicdatasnapshot.cpp deleted file mode 100644 index 07d34f28..00000000 --- a/test/logicdatasnapshot.cpp +++ /dev/null @@ -1,475 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#define __STDC_LIMIT_MACROS -#include - -#include - -#include "../pv/logicdatasnapshot.h" - -using namespace std; - -using pv::LogicDataSnapshot; - -BOOST_AUTO_TEST_SUITE(LogicDataSnapshotTest) - -void push_logic(LogicDataSnapshot &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(LogicDataSnapshot::pow2_ceil(0, 0), 0); - BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(1, 0), 1); - BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(2, 0), 2); - - BOOST_CHECK_EQUAL( - LogicDataSnapshot::pow2_ceil(INT64_MIN, 0), INT64_MIN); - BOOST_CHECK_EQUAL( - LogicDataSnapshot::pow2_ceil(INT64_MAX, 0), INT64_MAX); - - BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(0, 1), 0); - BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(1, 1), 2); - BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(2, 1), 2); - BOOST_CHECK_EQUAL(LogicDataSnapshot::pow2_ceil(3, 1), 4); -} - -BOOST_AUTO_TEST_CASE(Basic) -{ - // Create an empty LogicDataSnapshot object - sr_datafeed_logic logic; - logic.length = 0; - logic.unitsize = 1; - logic.data = NULL; - - LogicDataSnapshot s(logic); - - //----- Test LogicDataSnapshot::push_logic -----// - - BOOST_CHECK(s.get_sample_count() == 0); - for (unsigned int i = 0; i < LogicDataSnapshot::ScaleStepCount; i++) - { - const LogicDataSnapshot::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 < LogicDataSnapshot::ScaleStepCount; i++) - { - const LogicDataSnapshot::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 LogicDataSnapshot::MipMapLevel &m0 = s._mip_map[0]; - BOOST_CHECK_EQUAL(m0.length, 1); - BOOST_CHECK_EQUAL(m0.data_length, LogicDataSnapshot::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 < LogicDataSnapshot::ScaleStepCount; i++) - { - const LogicDataSnapshot::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, LogicDataSnapshot::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 LogicDataSnapshot::MipMapLevel &m1 = s._mip_map[1]; - BOOST_CHECK_EQUAL(m1.length, 1); - BOOST_CHECK_EQUAL(m1.data_length, LogicDataSnapshot::MipMapDataUnit); - BOOST_REQUIRE(m1.data != NULL); - BOOST_CHECK_EQUAL(((uint8_t*)m1.data)[0], 0x11); - - //----- Test LogicDataSnapshot::get_subsampled_edges -----// - - // Test a full view at full zoom. - vector edges; - s.get_subsampled_edges(edges, 0, 255, 1, 0); - BOOST_REQUIRE_EQUAL(edges.size(), 4); - - BOOST_CHECK_EQUAL(edges[0].first, 0); - BOOST_CHECK_EQUAL(edges[1].first, 8); - BOOST_CHECK_EQUAL(edges[2].first, 16); - BOOST_CHECK_EQUAL(edges[3].first, 255); - - // 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, 17); -} - -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); - - LogicDataSnapshot 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, - LogicDataSnapshot::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, - LogicDataSnapshot::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, - LogicDataSnapshot::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, - LogicDataSnapshot::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 < LogicDataSnapshot::ScaleStepCount; i++) - { - const LogicDataSnapshot::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 LogicDataSnapshot::get_subsampled_edges -----// - // Check in normal case - vector edges; - s.get_subsampled_edges(edges, 0, Length-1, 1, 7); - - BOOST_CHECK_EQUAL(edges.size(), 32); - - for (unsigned int i = 0; i < edges.size() - 1; i++) - { - BOOST_CHECK_EQUAL(edges[i].first, i * 32768); - BOOST_CHECK_EQUAL(edges[i].second, i & 1); - } - - BOOST_CHECK_EQUAL(edges[31].first, 999999); - - // Check in very low zoom case - edges.clear(); - s.get_subsampled_edges(edges, 0, Length-1, 50e6f, 7); - - BOOST_CHECK_EQUAL(edges.size(), 2); -} - -BOOST_AUTO_TEST_CASE(Pulses) -{ - const int Cycles = 3; - const int Period = 64; - const int Length = Cycles * Period; - - vector edges; - - //----- Create a LogicDataSnapshot -----// - 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; - } - - LogicDataSnapshot 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, - LogicDataSnapshot::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/LogicDataSnapshot::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 < LogicDataSnapshot::ScaleStepCount; i++) { - const LogicDataSnapshot::MipMapLevel &m = s._mip_map[i]; - BOOST_CHECK_EQUAL(m.length, 0); - BOOST_CHECK_EQUAL(m.data_length, 0); - BOOST_CHECK(m.data == NULL); - } - - //----- Test get_subsampled_edges at reduced scale -----// - s.get_subsampled_edges(edges, 0, Length-1, 16.0f, 2); - BOOST_REQUIRE_EQUAL(edges.size(), Cycles + 2); - - BOOST_CHECK_EQUAL(0, false); - for (unsigned int i = 1; i < edges.size(); i++) - BOOST_CHECK_EQUAL(edges[i].second, false); -} - -BOOST_AUTO_TEST_CASE(LongPulses) -{ - const int Cycles = 3; - const int Period = 64; - const int PulseWidth = 16; - const int Length = Cycles * Period; - - int j; - vector edges; - - //----- Create a LogicDataSnapshot -----// - sr_datafeed_logic logic; - logic.unitsize = 8; - logic.length = Length; - 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; - } - - LogicDataSnapshot 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, - LogicDataSnapshot::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/LogicDataSnapshot::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 < LogicDataSnapshot::ScaleStepCount; i++) { - const LogicDataSnapshot::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-1); - 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-1); - 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 LogicDataSnapshot -----// - 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; - } - - LogicDataSnapshot s(logic); - delete[] (uint64_t*)logic.data; - - vector edges; - - - /* The trailing edge of the pulse train is falling in the source data. - * Check this is always true at different scales - */ - - edges.clear(); - s.get_subsampled_edges(edges, 0, Length-1, 33.333332f, 1); - BOOST_CHECK_EQUAL(edges[edges.size() - 2].second, false); -} - - -BOOST_AUTO_TEST_SUITE_END()