]> sigrok.org Git - pulseview.git/blobdiff - pv/data/logicsnapshot.cpp
decode: Fix mixup of bytes vs samples
[pulseview.git] / pv / data / logicsnapshot.cpp
index af6ac0e8c367a097372aeea376cef6c101785e8b..797a00bc54789f2cd4de2f7067448cf98aec0b96 100644 (file)
 
 #include <boost/foreach.hpp>
 
+#include "config.h"
 #include "logicsnapshot.h"
 
-using namespace boost;
-using namespace std;
+using boost::lock_guard;
+using boost::recursive_mutex;
+using std::max;
+using std::min;
+using std::pair;
 
 namespace pv {
 namespace data {
@@ -40,10 +44,13 @@ 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) :
+LogicSnapshot::LogicSnapshot(const sr_datafeed_logic &logic,
+                             const uint64_t expected_num_samples) :
        Snapshot(logic.unitsize),
        _last_append_sample(0)
 {
+       set_capacity(expected_num_samples);
+
        lock_guard<recursive_mutex> lock(_mutex);
        memset(_mip_map, 0, sizeof(_mip_map));
        append_payload(logic);
@@ -56,6 +63,80 @@ LogicSnapshot::~LogicSnapshot()
                free(l.data);
 }
 
+uint64_t LogicSnapshot::unpack_sample(const uint8_t *ptr) const
+{
+#ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS
+       return *(uint64_t*)ptr;
+#else
+       uint64_t value = 0;
+       switch(_unit_size) {
+       default:
+               value |= ((uint64_t)ptr[7]) << 56;
+               /* FALLTHRU */
+       case 7:
+               value |= ((uint64_t)ptr[6]) << 48;
+               /* FALLTHRU */
+       case 6:
+               value |= ((uint64_t)ptr[5]) << 40;
+               /* FALLTHRU */
+       case 5:
+               value |= ((uint64_t)ptr[4]) << 32;
+               /* FALLTHRU */
+       case 4:
+               value |= ((uint32_t)ptr[3]) << 24;
+               /* FALLTHRU */
+       case 3:
+               value |= ((uint32_t)ptr[2]) << 16;
+               /* FALLTHRU */
+       case 2:
+               value |= ptr[1] << 8;
+               /* FALLTHRU */
+       case 1:
+               value |= ptr[0];
+               /* FALLTHRU */
+       case 0:
+               break;
+       }
+       return value;
+#endif
+}
+
+void LogicSnapshot::pack_sample(uint8_t *ptr, uint64_t value)
+{
+#ifdef HAVE_UNALIGNED_LITTLE_ENDIAN_ACCESS
+       *(uint64_t*)ptr = value;
+#else
+       switch(_unit_size) {
+       default:
+               ptr[7] = value >> 56;
+               /* FALLTHRU */
+       case 7:
+               ptr[6] = value >> 48;
+               /* FALLTHRU */
+       case 6:
+               ptr[5] = value >> 40;
+               /* FALLTHRU */
+       case 5:
+               ptr[4] = value >> 32;
+               /* FALLTHRU */
+       case 4:
+               ptr[3] = value >> 24;
+               /* FALLTHRU */
+       case 3:
+               ptr[2] = value >> 16;
+               /* FALLTHRU */
+       case 2:
+               ptr[1] = value >> 8;
+               /* FALLTHRU */
+       case 1:
+               ptr[0] = value;
+               /* FALLTHRU */
+       case 0:
+               break;
+       }
+#endif
+}
+
 void LogicSnapshot::append_payload(
        const sr_datafeed_logic &logic)
 {
@@ -70,7 +151,23 @@ void LogicSnapshot::append_payload(
        append_payload_to_mipmap();
 }
 
-void LogicSnapshot::reallocate_mip_map(MipMapLevel &m)
+void LogicSnapshot::get_samples(uint8_t *const data,
+       int64_t start_sample, int64_t end_sample) const
+{
+       assert(data);
+       assert(start_sample >= 0);
+       assert(start_sample <= (int64_t)_sample_count);
+       assert(end_sample >= 0);
+       assert(end_sample <= (int64_t)_sample_count);
+       assert(start_sample <= end_sample);
+
+       lock_guard<recursive_mutex> lock(_mutex);
+
+       const size_t size = (end_sample - start_sample) * _unit_size;
+       memcpy(data, (const uint8_t*)_data + start_sample * _unit_size, size);
+}
+
+void LogicSnapshot::reallocate_mipmap_level(MipMapLevel &m)
 {
        const uint64_t new_data_length = ((m.length + MipMapDataUnit - 1) /
                MipMapDataUnit) * MipMapDataUnit;
@@ -101,14 +198,12 @@ void LogicSnapshot::append_payload_to_mipmap()
        if (m0.length == prev_length)
                return;
 
-       reallocate_mip_map(m0);
+       reallocate_mipmap_level(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 +
+       const uint8_t *const end_src_ptr = (uint8_t*)_data +
                m0.length * _unit_size * MipMapScaleFactor;
        for (src_ptr = (uint8_t*)_data +
                prev_length * _unit_size * MipMapScaleFactor;
@@ -119,13 +214,13 @@ void LogicSnapshot::append_payload_to_mipmap()
                diff_counter = MipMapScaleFactor;
                while (diff_counter-- > 0)
                {
-                       const uint64_t sample = *(uint64_t*)src_ptr;
+                       const uint64_t sample = unpack_sample(src_ptr);
                        accumulator |= _last_append_sample ^ sample;
                        _last_append_sample = sample;
                        src_ptr += _unit_size;
                }
 
-               *(uint64_t*)dest_ptr = accumulator;
+               pack_sample(dest_ptr, accumulator);
                dest_ptr += _unit_size;
        }
 
@@ -143,12 +238,12 @@ void LogicSnapshot::append_payload_to_mipmap()
                if (m.length == prev_length)
                        break;
 
-               reallocate_mip_map(m);
+               reallocate_mipmap_level(m);
 
                // Subsample the level lower level
                src_ptr = (uint8_t*)ml.data +
                        _unit_size * prev_length * MipMapScaleFactor;
-               const uint8_t *end_dest_ptr =
+               const uint8_t *const end_dest_ptr =
                        (uint8_t*)m.data + _unit_size * m.length;
                for (dest_ptr = (uint8_t*)m.data +
                        _unit_size * prev_length;
@@ -159,11 +254,11 @@ void LogicSnapshot::append_payload_to_mipmap()
                        diff_counter = MipMapScaleFactor;
                        while (diff_counter-- > 0)
                        {
-                               accumulator |= *(uint64_t*)src_ptr;
+                               accumulator |= unpack_sample(src_ptr);
                                src_ptr += _unit_size;
                        }
 
-                       *(uint64_t*)dest_ptr = accumulator;
+                       pack_sample(dest_ptr, accumulator);
                }
        }
 }
@@ -173,7 +268,7 @@ uint64_t LogicSnapshot::get_sample(uint64_t index) const
        assert(_data);
        assert(index < _sample_count);
 
-       return *(uint64_t*)((uint8_t*)_data + index * _unit_size);
+       return unpack_sample((uint8_t*)_data + index * _unit_size);
 }
 
 void LogicSnapshot::get_subsampled_edges(
@@ -190,7 +285,7 @@ void LogicSnapshot::get_subsampled_edges(
        assert(start <= end);
        assert(min_length > 0);
        assert(sig_index >= 0);
-       assert(sig_index < SR_MAX_NUM_PROBES);
+       assert(sig_index < 64);
 
        lock_guard<recursive_mutex> lock(_mutex);
 
@@ -349,15 +444,17 @@ void LogicSnapshot::get_subsampled_edges(
        }
 
        // Add the final state
-       edges.push_back(pair<int64_t, bool>(end,
-               get_sample(end) & sig_mask));
+       const bool end_sample = get_sample(end) & sig_mask;
+       if (last_sample != end_sample)
+               edges.push_back(pair<int64_t, bool>(end, end_sample));
+       edges.push_back(pair<int64_t, bool>(end + 1, end_sample));
 }
 
 uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const
 {
        assert(level >= 0);
        assert(_mip_map[level].data);
-       return *(uint64_t*)((uint8_t*)_mip_map[level].data +
+       return unpack_sample((uint8_t*)_mip_map[level].data +
                _unit_size * offset);
 }