/* * This file is part of the DSLogic-gui project. * DSLogic-gui is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth * Copyright (C) 2013 DreamSourceLab * * 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 #include "analogsnapshot.h" using namespace boost; using namespace std; namespace pv { namespace data { const int AnalogSnapshot::EnvelopeScalePower = 4; const int AnalogSnapshot::EnvelopeScaleFactor = 1 << EnvelopeScalePower; const float AnalogSnapshot::LogEnvelopeScaleFactor = logf(EnvelopeScaleFactor); const uint64_t AnalogSnapshot::EnvelopeDataUnit = 64*1024; // bytes AnalogSnapshot::AnalogSnapshot(const sr_datafeed_analog &analog, uint64_t _total_sample_len, unsigned int channel_num) : Snapshot(sizeof(uint16_t), _total_sample_len, channel_num) { boost::lock_guard lock(_mutex); memset(_envelope_levels, 0, sizeof(_envelope_levels)); init(_total_sample_len * channel_num); append_payload(analog); } AnalogSnapshot::~AnalogSnapshot() { boost::lock_guard lock(_mutex); BOOST_FOREACH(Envelope &e, _envelope_levels[0]) free(e.samples); } void AnalogSnapshot::append_payload( const sr_datafeed_analog &analog) { boost::lock_guard lock(_mutex); append_data(analog.data, analog.num_samples); // Generate the first mip-map from the data append_payload_to_envelope_levels(); } const uint16_t* AnalogSnapshot::get_samples( int64_t start_sample, int64_t end_sample) const { assert(start_sample >= 0); assert(start_sample < (int64_t)get_sample_count()); assert(end_sample >= 0); assert(end_sample < (int64_t)get_sample_count()); assert(start_sample <= end_sample); boost::lock_guard lock(_mutex); // uint16_t *const data = new uint16_t[end_sample - start_sample]; // memcpy(data, (uint16_t*)_data + start_sample, sizeof(uint16_t) * // (end_sample - start_sample)); // return data; return (uint16_t*)_data + start_sample * _channel_num; } void AnalogSnapshot::get_envelope_section(EnvelopeSection &s, uint64_t start, uint64_t end, float min_length, int probe_index) const { assert(end <= get_sample_count()); assert(start <= end); assert(min_length > 0); boost::lock_guard lock(_mutex); const unsigned int min_level = max((int)floorf(logf(min_length) / LogEnvelopeScaleFactor) - 1, 0); const unsigned int scale_power = (min_level + 1) * EnvelopeScalePower; start >>= scale_power; end >>= scale_power; s.start = start << scale_power; s.scale = 1 << scale_power; s.length = end - start; // s.samples = new EnvelopeSample[s.length]; // memcpy(s.samples, _envelope_levels[min_level].samples + start, // s.length * sizeof(EnvelopeSample)); s.samples = _envelope_levels[probe_index][min_level].samples + start; } void AnalogSnapshot::reallocate_envelope(Envelope &e) { const uint64_t new_data_length = ((e.length + EnvelopeDataUnit - 1) / EnvelopeDataUnit) * EnvelopeDataUnit; if (new_data_length > e.data_length) { e.data_length = new_data_length; e.samples = (EnvelopeSample*)realloc(e.samples, new_data_length * sizeof(EnvelopeSample)); } } void AnalogSnapshot::append_payload_to_envelope_levels() { int i; for (i = 0; i < (int)_channel_num; i++) { Envelope &e0 = _envelope_levels[i][0]; uint64_t prev_length; EnvelopeSample *dest_ptr; // Expand the data buffer to fit the new samples prev_length = e0.length; e0.length = get_sample_count() / EnvelopeScaleFactor; // Break off if there are no new samples to compute // if (e0.length == prev_length) // return; if (e0.length == 0) return; if (e0.length == prev_length) prev_length = 0; reallocate_envelope(e0); dest_ptr = e0.samples + prev_length; // Iterate through the samples to populate the first level mipmap const uint16_t *const stop_src_ptr = (uint16_t*)_data + e0.length * EnvelopeScaleFactor * _channel_num; // for (const uint16_t *src_ptr = (uint16_t*)_data + // prev_length * EnvelopeScaleFactor; // src_ptr < end_src_ptr; src_ptr += EnvelopeScaleFactor) // { // const EnvelopeSample sub_sample = { // *min_element(src_ptr, src_ptr + EnvelopeScaleFactor), // *max_element(src_ptr, src_ptr + EnvelopeScaleFactor), // }; // *dest_ptr++ = sub_sample; // } for (const uint16_t *src_ptr = (uint16_t*)_data + prev_length * EnvelopeScaleFactor * _channel_num + i; src_ptr < stop_src_ptr; src_ptr += EnvelopeScaleFactor * _channel_num) { const uint16_t * begin_src_ptr = src_ptr; const uint16_t *const end_src_ptr = src_ptr + EnvelopeScaleFactor * _channel_num; EnvelopeSample sub_sample; sub_sample.min = *begin_src_ptr; sub_sample.max = *begin_src_ptr; begin_src_ptr += _channel_num; while (begin_src_ptr < end_src_ptr) { sub_sample.min = min(sub_sample.min, *begin_src_ptr); sub_sample.max = max(sub_sample.max, *begin_src_ptr); begin_src_ptr += _channel_num; } *dest_ptr++ = sub_sample; } // Compute higher level mipmaps for (unsigned int level = 1; level < ScaleStepCount; level++) { Envelope &e = _envelope_levels[i][level]; const Envelope &el = _envelope_levels[i][level-1]; // Expand the data buffer to fit the new samples prev_length = e.length; e.length = el.length / EnvelopeScaleFactor; // Break off if there are no more samples to computed // if (e.length == prev_length) // break; if (e.length == prev_length) prev_length = 0; reallocate_envelope(e); // Subsample the level lower level const EnvelopeSample *src_ptr = el.samples + prev_length * EnvelopeScaleFactor; const EnvelopeSample *const end_dest_ptr = e.samples + e.length; for (dest_ptr = e.samples + prev_length; dest_ptr < end_dest_ptr; dest_ptr++) { const EnvelopeSample *const end_src_ptr = src_ptr + EnvelopeScaleFactor; EnvelopeSample sub_sample = *src_ptr++; while (src_ptr < end_src_ptr) { sub_sample.min = min(sub_sample.min, src_ptr->min); sub_sample.max = max(sub_sample.max, src_ptr->max); src_ptr++; } *dest_ptr = sub_sample; } } } } } // namespace data } // namespace pv