diff --git a/.gitignore b/.gitignore
index e9af7c684685f3497b2dfe4ae83937e024d81fc8..c1f91428d2f56d7317ad791a0835b06eb3be71e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,16 +31,18 @@ Makefile.in
 configure
 aclocal.m4
 
-DSLogic-gui/ui_*.h
-DSLogic-gui/DSLogic
-DSLogic-gui/install_manifest.txt
+DSView/ui_*.h
+DSView/DSView
+DSView/install_manifest.txt
 
 moc_*.cxx
 moc_*.cxx_parameters
 
-libsigrok4DSLogic/version.h
+libsigrok4DSL/version.h
 
 libusbx-1.0.18/doc/doxygen.cfg
 libusbx-1.0.18/m4/
 
-
+DSView-prj
+libsigrokdecode
+build*
diff --git a/DSView/pv/data/logicsnapshot.cpp b/DSView/pv/data/logicsnapshot.cpp
index 4b18551ec7a27f681372797c407b3e2434fee62d..316144715faa909924dc862b8cf973e136b60488 100644
--- a/DSView/pv/data/logicsnapshot.cpp
+++ b/DSView/pv/data/logicsnapshot.cpp
@@ -208,8 +208,6 @@ void LogicSnapshot::get_subsampled_edges(
 	boost::lock_guard<boost::recursive_mutex> lock(_mutex);
 
 	const uint64_t block_length = (uint64_t)max(min_length, 1.0f);
-	const unsigned int min_level = max((int)floorf(logf(min_length) /
-		LogMipMapScaleFactor) - 1, 0);
 	const uint64_t sig_mask = 1ULL << sig_index;
 
     if (!edges.empty())
@@ -220,132 +218,8 @@ void LogicSnapshot::get_subsampled_edges(
 
     while (index + block_length <= end)
 	{
-		//----- Continue to search -----//
-		level = min_level;
-
-		// We cannot fast-forward if there is no mip-map data at
-		// at the minimum level.
-		fast_forward = (_mip_map[level].data != NULL);
-
-		if (min_length < MipMapScaleFactor)
-		{
-			// Search individual samples up to the beginning of
-			// the next first level mip map block
-			const uint64_t final_index = min(end,
-				pow2_ceil(index, MipMapScalePower));
-
-			for (; index < final_index &&
-				(index & ~(~0 << MipMapScalePower)) != 0;
-				index++)
-			{
-				const bool sample =
-					(get_sample(index) & sig_mask) != 0;
-
-				// If there was a change we cannot fast forward
-				if (sample != last_sample) {
-					fast_forward = false;
-					break;
-				}
-			}
-		}
-		else
-		{
-			// If resolution is less than a mip map block,
-			// round up to the beginning of the mip-map block
-			// for this level of detail
-			const int min_level_scale_power =
-				(level + 1) * MipMapScalePower;
-			index = pow2_ceil(index, min_level_scale_power);
-            if (index >= end)
-				break;
-
-			// We can fast forward only if there was no change
-			const bool sample =
-				(get_sample(index) & sig_mask) != 0;
-			if (last_sample != sample)
-				fast_forward = false;
-		}
-
-		if (fast_forward) {
-
-			// Fast forward: This involves zooming out to higher
-			// levels of the mip map searching for changes, then
-			// zooming in on them to find the point where the edge
-			// begins.
-
-			// Slide right and zoom out at the beginnings of mip-map
-			// blocks until we encounter a change
-			while (1) {
-				const int level_scale_power =
-					(level + 1) * MipMapScalePower;
-				const uint64_t offset =
-					index >> level_scale_power;
-
-				// Check if we reached the last block at this
-				// level, or if there was a change in this block
-				if (offset >= _mip_map[level].length ||
-					(get_subsample(level, offset) &
-						sig_mask))
-					break;
-
-				if ((offset & ~(~0 << MipMapScalePower)) == 0) {
-					// If we are now at the beginning of a
-					// higher level mip-map block ascend one
-					// level
-					if (level + 1 >= ScaleStepCount ||
-						!_mip_map[level + 1].data)
-						break;
-
-					level++;
-				} else {
-					// Slide right to the beginning of the
-					// next mip map block
-					index = pow2_ceil(index + 1,
-						level_scale_power);
-				}
-			}
-
-			// Zoom in, and slide right until we encounter a change,
-			// and repeat until we reach min_level
-			while (1) {
-				assert(_mip_map[level].data);
-
-				const int level_scale_power =
-					(level + 1) * MipMapScalePower;
-				const uint64_t offset =
-					index >> level_scale_power;
-
-				// Check if we reached the last block at this
-				// level, or if there was a change in this block
-				if (offset >= _mip_map[level].length ||
-					(get_subsample(level, offset) &
-						sig_mask)) {
-					// Zoom in unless we reached the minimum
-					// zoom
-					if (level == min_level)
-						break;
-
-					level--;
-				} else {
-					// Slide right to the beginning of the
-					// next mip map block
-					index = pow2_ceil(index + 1,
-						level_scale_power);
-				}
-			}
-
-			// If individual samples within the limit of resolution,
-			// do a linear search for the next transition within the
-			// block
-			if (min_length < MipMapScaleFactor) {
-				for (; index < end; index++) {
-					const bool sample = (get_sample(index) &
-						sig_mask) != 0;
-					if (sample != last_sample)
-						break;
-				}
-			}
-		}
+        // search next edge
+        get_nxt_edge(index, last_sample, end, min_length, sig_index);
 
 		//----- Store the edge -----//
 
@@ -373,44 +247,34 @@ void LogicSnapshot::get_subsampled_edges(
         edges.push_back(pair<int64_t, bool>(end + 1, ~last_sample));
 }
 
-int LogicSnapshot::get_first_edge(
-    uint64_t &edge_index, bool &edge,
-    uint64_t start, uint64_t end,
-    int sig_index, int edge_type,
-    int flag_index, int flag)
+bool LogicSnapshot::get_nxt_edge(
+    uint64_t &index, bool last_sample, uint64_t end,
+    float min_length, int sig_index)
 {
-    uint64_t index = start;
     unsigned int level;
-    bool last_sample;
     bool fast_forward;
 
-    assert(end <= get_sample_count());
-    assert(start <= end);
-    assert(sig_index >= 0);
-    assert(sig_index < 64);
-
-    boost::lock_guard<boost::recursive_mutex> lock(_mutex);
+    assert(index > 0);
 
-    const uint64_t block_length = 1;
-    const unsigned int min_level = 0;
+    const unsigned int min_level = max((int)floorf(logf(min_length) /
+        LogMipMapScaleFactor) - 1, 0);
     const uint64_t sig_mask = 1ULL << sig_index;
-    const uint64_t flag_mask = 1ULL << flag_index;
 
-    // Store the initial state
-    last_sample = (get_sample(start) & sig_mask) != 0;
+    if (index >= end)
+        return false;
 
-    while (index + block_length <= end)
-    {
-        //----- Continue to search -----//
-        level = min_level;
+    //----- Continue to search -----//
+    level = min_level;
 
-        // We cannot fast-forward if there is no mip-map data at
-        // at the minimum level.
-        fast_forward = (_mip_map[level].data != NULL);
+    // We cannot fast-forward if there is no mip-map data at
+    // at the minimum level.
+    fast_forward = (_mip_map[level].data != NULL);
 
+    if (min_length < MipMapScaleFactor)
+    {
         // Search individual samples up to the beginning of
         // the next first level mip map block
-        uint64_t final_index = min(end,
+        const uint64_t final_index = min(end,
             pow2_ceil(index, MipMapScalePower));
 
         for (; index < final_index &&
@@ -426,78 +290,97 @@ int LogicSnapshot::get_first_edge(
                 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)
+            return false;
+
+        // We can fast forward only if there was no change
+        const bool sample =
+            (get_sample(index) & sig_mask) != 0;
+        if (last_sample != sample)
+            fast_forward = false;
+    }
+
+    if (fast_forward) {
+
+        // Fast forward: This involves zooming out to higher
+        // levels of the mip map searching for changes, then
+        // zooming in on them to find the point where the edge
+        // begins.
+
+        // Slide right and zoom out at the beginnings of mip-map
+        // blocks until we encounter a change
+        while (1) {
+            const int level_scale_power =
+                (level + 1) * MipMapScalePower;
+            const uint64_t offset =
+                index >> level_scale_power;
+
+            // Check if we reached the last block at this
+            // level, or if there was a change in this block
+            if (offset >= _mip_map[level].length ||
+                (get_subsample(level, offset) &
+                    sig_mask))
+                break;
 
-        if (fast_forward) {
-
-            // Fast forward: This involves zooming out to higher
-            // levels of the mip map searching for changes, then
-            // zooming in on them to find the point where the edge
-            // begins.
-
-            // Slide right and zoom out at the beginnings of mip-map
-            // blocks until we encounter a change
-            while (1) {
-                const int level_scale_power =
-                    (level + 1) * MipMapScalePower;
-                const uint64_t offset =
-                    index >> level_scale_power;
-
-                // Check if we reached the last block at this
-                // level, or if there was a change in this block
-                if (offset >= _mip_map[level].length ||
-                    (get_subsample(level, offset) &
-                        sig_mask))
+            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;
 
-                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);
-                }
+                level++;
+            } else {
+                // Slide right to the beginning of the
+                // next mip map block
+                index = pow2_ceil(index + 1,
+                    level_scale_power);
             }
+        }
 
-            // Zoom in, and slide right until we encounter a change,
-            // and repeat until we reach min_level
-            while (1) {
-                assert(_mip_map[level].data);
-
-                const int level_scale_power =
-                    (level + 1) * MipMapScalePower;
-                const uint64_t offset =
-                    index >> level_scale_power;
-
-                // Check if we reached the last block at this
-                // level, or if there was a change in this block
-                if (offset >= _mip_map[level].length ||
-                    (get_subsample(level, offset) &
-                        sig_mask)) {
-                    // Zoom in unless we reached the minimum
-                    // zoom
-                    if (level == min_level)
-                        break;
-
-                    level--;
-                } else {
-                    // Slide right to the beginning of the
-                    // next mip map block
-                    index = pow2_ceil(index + 1,
-                        level_scale_power);
-                }
+        // Zoom in, and slide right until we encounter a change,
+        // and repeat until we reach min_level
+        while (1) {
+            assert(_mip_map[level].data);
+
+            const int level_scale_power =
+                (level + 1) * MipMapScalePower;
+            const uint64_t offset =
+                index >> level_scale_power;
+
+            // Check if we reached the last block at this
+            // level, or if there was a change in this block
+            if (offset >= _mip_map[level].length ||
+                (get_subsample(level, offset) &
+                    sig_mask)) {
+                // Zoom in unless we reached the minimum
+                // zoom
+                if (level == min_level)
+                    break;
+
+                level--;
+            } else {
+                // Slide right to the beginning of the
+                // next mip map block
+                index = pow2_ceil(index + 1,
+                    level_scale_power);
             }
+        }
 
-            // If individual samples within the limit of resolution,
-            // do a linear search for the next transition within the
-            // block
+        // If 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;
@@ -505,90 +388,45 @@ int LogicSnapshot::get_first_edge(
                     break;
             }
         }
-
-        //----- Store the edge -----//
-
-        // Take the last sample of the quanization block
-        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;
-        if (final_index > 1) {
-            const bool final_flag_sample = ((get_sample(final_index - 1) & flag_mask) != 0);
-            const bool final_pre_flag_sample = ((get_sample(final_index - 2) & flag_mask) != 0);
-            if (final_sample != last_sample &&
-                ((edge_type == -1) || final_sample == (edge_type != 0)) &&
-                ((flag == -1) || (final_flag_sample == (flag != 0) && final_flag_sample == final_pre_flag_sample))) {
-                edge_index = index;
-                edge = final_sample;
-                return SR_OK;
-            }
-        }
-
-        index = final_index;
-        last_sample = final_sample;
     }
 
-    // Add the final state
-    const bool end_sample = ((get_sample(end) & sig_mask) != 0);
-    const bool end_flag_sample = ((get_sample(end) & flag_mask) != 0);
-    const bool end_pre_flag_sample = ((get_sample(end - 1) & flag_mask) != 0);
-    if (end_sample != last_sample &&
-        ((edge_type == -1) || end_sample == (edge_type != 0)) &&
-        ((flag == -1) || (end_flag_sample == (flag != 0) && end_flag_sample == end_pre_flag_sample))) {
-        edge_index = end;
-        edge = end_sample;
-        return SR_OK;
-    } else {
-        return SR_ERR;
-    }
+    if (index >= end)
+        return false;
+    else
+        return true;
 }
 
-void LogicSnapshot::get_edges(
-    std::vector<EdgePair> &edges,
-    uint64_t start, uint64_t end, int sig_index, int edge_type)
+bool LogicSnapshot::get_pre_edge(
+    uint64_t &index, bool last_sample,
+    float min_length, int sig_index)
 {
-    uint64_t index = start;
     unsigned int level;
-    bool last_sample;
     bool fast_forward;
 
-    assert(end <= get_sample_count());
-    assert(start <= end);
-    assert(sig_index >= 0);
-    assert(sig_index < 64);
-
-    boost::lock_guard<boost::recursive_mutex> lock(_mutex);
+    assert(index < get_sample_count());
 
-    const uint64_t block_length = 1;
-    const unsigned int min_level = 0;
+    const unsigned int min_level = max((int)floorf(logf(min_length) /
+        LogMipMapScaleFactor) - 1, 0);
     const uint64_t sig_mask = 1ULL << sig_index;
 
-    if (!edges.empty())
-        edges.clear();
-    // Store the initial state
-    last_sample = (get_sample(start) & sig_mask) != 0;
-
-    while (index + block_length <= end)
-    {
-        //----- Continue to search -----//
-        level = min_level;
+    //----- Continue to search -----//
+    level = min_level;
 
-        // We cannot fast-forward if there is no mip-map data at
-        // at the minimum level.
-        fast_forward = (_mip_map[level].data != NULL);
+    // We cannot fast-forward if there is no mip-map data at
+    // at the minimum level.
+    fast_forward = (_mip_map[level].data != NULL);
 
-        // Search individual samples up to the beginning of
-        // the next first level mip map block
-        uint64_t final_index = min(end,
-            pow2_ceil(index, MipMapScalePower));
-
-        for (; index < final_index &&
-            (index & ~(~0 << MipMapScalePower)) != 0;
-            index++)
+    if (min_length < MipMapScaleFactor)
+    {
+        // Search individual samples down to the ending of
+        // the previous first level mip map block
+        uint64_t final_index;
+        if (index < (1 << MipMapScalePower))
+            final_index = 0;
+        else
+            final_index = pow2_ceil(index + 1, MipMapScalePower) - (1 << MipMapScalePower) - 1;
+
+        for (; index >= final_index; index--)
         {
             const bool sample =
                 (get_sample(index) & sig_mask) != 0;
@@ -596,267 +434,125 @@ void LogicSnapshot::get_edges(
             // If there was a change we cannot fast forward
             if (sample != last_sample) {
                 fast_forward = false;
-                break;
-            }
-        }
-
-        if (fast_forward) {
-
-            // Fast forward: This involves zooming out to higher
-            // levels of the mip map searching for changes, then
-            // zooming in on them to find the point where the edge
-            // begins.
-
-            // Slide right and zoom out at the beginnings of mip-map
-            // blocks until we encounter a change
-            while (1) {
-                const int level_scale_power =
-                    (level + 1) * MipMapScalePower;
-                const uint64_t offset =
-                    index >> level_scale_power;
-
-                // Check if we reached the last block at this
-                // level, or if there was a change in this block
-                if (offset >= _mip_map[level].length ||
-                    (get_subsample(level, offset) &
-                        sig_mask))
-                    break;
-
-                if ((offset & ~(~0 << MipMapScalePower)) == 0) {
-                    // If we are now at the beginning of a
-                    // higher level mip-map block ascend one
-                    // level
-                    if (level + 1 >= ScaleStepCount ||
-                        !_mip_map[level + 1].data)
-                        break;
-
-                    level++;
-                } else {
-                    // Slide right to the beginning of the
-                    // next mip map block
-                    index = pow2_ceil(index + 1,
-                        level_scale_power);
-                }
-            }
-
-            // Zoom in, and slide right until we encounter a change,
-            // and repeat until we reach min_level
-            while (1) {
-                assert(_mip_map[level].data);
-
-                const int level_scale_power =
-                    (level + 1) * MipMapScalePower;
-                const uint64_t offset =
-                    index >> level_scale_power;
-
-                // Check if we reached the last block at this
-                // level, or if there was a change in this block
-                if (offset >= _mip_map[level].length ||
-                    (get_subsample(level, offset) &
-                        sig_mask)) {
-                    // Zoom in unless we reached the minimum
-                    // zoom
-                    if (level == min_level)
-                        break;
-
-                    level--;
-                } else {
-                    // Slide right to the beginning of the
-                    // next mip map block
-                    index = pow2_ceil(index + 1,
-                        level_scale_power);
-                }
+                index++;
+                return true;
             }
 
-            // If individual samples within the limit of resolution,
-            // do a linear search for the next transition within the
-            // block
-            for (; index < end; index++) {
-                const bool sample = (get_sample(index) &
-                    sig_mask) != 0;
-                if (sample != last_sample)
-                    break;
-            }
+            if (index == 0)
+                return false;
         }
-
-        //----- Store the edge -----//
-
-        // Take the last sample of the quanization block
-        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;
-        if ((edge_type == -1) || (final_sample == (edge_type != 0)))
-            edges.push_back(pair<int64_t, bool>(final_index - 1, final_sample));
-
-        index = final_index;
-        last_sample = final_sample;
     }
-
-    // Add the final state
-    const bool end_sample = ((get_sample(end) & sig_mask) != 0);
-    if ((end_sample != last_sample) &&
-        ((edge_type == -1) || (end_sample == (edge_type != 0))))
-        edges.push_back(pair<int64_t, bool>(end, end_sample));
-}
-
-uint64_t LogicSnapshot::get_min_pulse(uint64_t start, uint64_t end, int sig_index)
-{
-    uint64_t index = start;
-    unsigned int level;
-    bool last_sample;
-    bool fast_forward;
-    uint64_t last_index;
-    uint64_t min_pulse = end - start;
-
-    assert(end <= get_sample_count());
-    assert(start <= end);
-    assert(sig_index >= 0);
-    assert(sig_index < 64);
-
-    boost::lock_guard<boost::recursive_mutex> lock(_mutex);
-
-    const uint64_t block_length = 1;
-    const unsigned int min_level = 0;
-    const uint64_t sig_mask = 1ULL << sig_index;
-
-    // Store the initial state
-    last_index = start;
-    last_sample = (get_sample(start) & sig_mask) != 0;
-
-    while (index + block_length <= end)
+    else
     {
-        //----- Continue to search -----//
-        level = min_level;
+        // 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;
+        if (index < (1 << min_level_scale_power))
+            index = 0;
+        else
+            index = pow2_ceil(index, min_level_scale_power) - (1 << min_level_scale_power) - 1;
+
+        // We can fast forward only if there was no change
+        const bool sample =
+            (get_sample(index) & sig_mask) != 0;
+        if (last_sample != sample) {
+            fast_forward = false;
+            index++;
+            return true;
+        }
 
-        // We cannot fast-forward if there is no mip-map data at
-        // at the minimum level.
-        fast_forward = (_mip_map[level].data != NULL);
+        if (index == 0)
+            return false;
+    }
 
-        // Search individual samples up to the beginning of
-        // the next first level mip map block
-        uint64_t final_index = min(end,
-            pow2_ceil(index, MipMapScalePower));
+    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 left and zoom out at the endings of mip-map
+        // blocks until we encounter a change
+        while (1) {
+            const int level_scale_power =
+                (level + 1) * MipMapScalePower;
+            const uint64_t offset =
+                index >> level_scale_power;
+
+            // Check if we reached the first block at this
+            // level, or if there was a change in this block
+            if (offset == 0 ||
+                (get_subsample(level, offset) &
+                    sig_mask))
+                break;
 
-        for (; index < final_index &&
-            (index & ~(~0 << MipMapScalePower)) != 0;
-            index++)
-        {
-            const bool sample =
-                (get_sample(index) & sig_mask) != 0;
+            if (((offset+1) & ~(~0 << MipMapScalePower)) == 0) {
+                // If we are now at the ending of a
+                // higher level mip-map block ascend one
+                // level
+                if (level + 1 >= ScaleStepCount ||
+                    !_mip_map[level + 1].data)
+                    break;
 
-            // If there was a change we cannot fast forward
-            if (sample != last_sample) {
-                fast_forward = false;
-                break;
+                level++;
+            } else {
+                // Slide left to the beginning of the
+                // previous mip map block
+                index = pow2_ceil(index + 1,
+                    level_scale_power) - (1 << level_scale_power) - 1;
             }
         }
 
-        if (fast_forward) {
-
-            // Fast forward: This involves zooming out to higher
-            // levels of the mip map searching for changes, then
-            // zooming in on them to find the point where the edge
-            // begins.
-
-            // Slide right and zoom out at the beginnings of mip-map
-            // blocks until we encounter a change
-            while (1) {
-                const int level_scale_power =
-                    (level + 1) * MipMapScalePower;
-                const uint64_t offset =
-                    index >> level_scale_power;
-
-                // Check if we reached the last block at this
-                // level, or if there was a change in this block
-                if (offset >= _mip_map[level].length ||
-                    (get_subsample(level, offset) &
-                        sig_mask))
+        // Zoom in, and slide left until we encounter a change,
+        // and repeat until we reach min_level
+        while (1) {
+            assert(_mip_map[level].data);
+
+            const int level_scale_power =
+                (level + 1) * MipMapScalePower;
+            const uint64_t offset =
+                index >> level_scale_power;
+
+            // Check if we reached the first block at this
+            // level, or if there was a change in this block
+            if (offset == 0 ||
+                (get_subsample(level, offset) &
+                    sig_mask)) {
+                // Zoom in unless we reached the minimum
+                // zoom
+                if (level == min_level)
                     break;
 
-                if ((offset & ~(~0 << MipMapScalePower)) == 0) {
-                    // If we are now at the beginning of a
-                    // higher level mip-map block ascend one
-                    // level
-                    if (level + 1 >= ScaleStepCount ||
-                        !_mip_map[level + 1].data)
-                        break;
-
-                    level++;
-                } else {
-                    // Slide right to the beginning of the
-                    // next mip map block
-                    index = pow2_ceil(index + 1,
-                        level_scale_power);
-                }
-            }
-
-            // Zoom in, and slide right until we encounter a change,
-            // and repeat until we reach min_level
-            while (1) {
-                assert(_mip_map[level].data);
-
-                const int level_scale_power =
-                    (level + 1) * MipMapScalePower;
-                const uint64_t offset =
-                    index >> level_scale_power;
-
-                // Check if we reached the last block at this
-                // level, or if there was a change in this block
-                if (offset >= _mip_map[level].length ||
-                    (get_subsample(level, offset) &
-                        sig_mask)) {
-                    // Zoom in unless we reached the minimum
-                    // zoom
-                    if (level == min_level)
-                        break;
-
-                    level--;
-                } else {
-                    // Slide right to the beginning of the
-                    // next mip map block
-                    index = pow2_ceil(index + 1,
-                        level_scale_power);
-                }
+                level--;
+            } else {
+                // Slide left to the ending of the
+                // previous mip map block
+                index = pow2_ceil(index + 1,
+                    level_scale_power) - (1 << level_scale_power) - 1;
             }
+        }
 
-            // If individual samples within the limit of resolution,
-            // do a linear search for the next transition within the
-            // block
-            for (; index < end; index++) {
+        // 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 >= 0; index--) {
                 const bool sample = (get_sample(index) &
                     sig_mask) != 0;
-                if (sample != last_sample)
-                    break;
+                if (sample != last_sample) {
+                    index++;
+                    return true;
+                }
+
+                if (index == 0)
+                    return false;
             }
         }
-
-        //----- Store the edge -----//
-
-        // Take the last sample of the quanization block
-        final_index = index + block_length;
-        if (index + block_length > end)
-            break;
-
-        // get pulse width
-        const bool final_sample =
-            (get_sample(final_index - 1) & sig_mask) != 0;
-        min_pulse = min(index - last_index, min_pulse);
-        last_index = index;
-        if (min_pulse == 1)
-            break;
-
-        index = final_index;
-        last_sample = final_sample;
     }
-
-    // Add the final state
-    min_pulse = min(end - last_index, min_pulse);
-
-    return min_pulse;
+    return false;
 }
 
 uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const
diff --git a/DSView/pv/data/logicsnapshot.h b/DSView/pv/data/logicsnapshot.h
index 3914a2ed8e134fcf1aaa755264fd5194d4333894..6e9aae12ad86ea5f5f85377eb8ab91fe710e4b3a 100644
--- a/DSView/pv/data/logicsnapshot.h
+++ b/DSView/pv/data/logicsnapshot.h
@@ -90,15 +90,11 @@ public:
 		uint64_t start, uint64_t end,
 		float min_length, int sig_index);
 
-    int get_first_edge(uint64_t &edge_index, bool &edge,
-                       uint64_t start, uint64_t end,
-                       int sig_index, int edge_type,
-                       int flag_index, int flag);
+    bool get_nxt_edge(uint64_t &index, bool last_sample, uint64_t end,
+                      float min_length, int sig_index);
 
-    void get_edges(std::vector<EdgePair> &edges,
-        uint64_t start, uint64_t end, int sig_index, int edge_type);
-
-    uint64_t get_min_pulse(uint64_t start, uint64_t end, int sig_index);
+    bool get_pre_edge(uint64_t &index, bool last_sample,
+                      float min_length, int sig_index);
 
 private:
 	uint64_t get_subsample(int level, uint64_t offset) const;
diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp
index f782ee3ab6e1f899905fb4e6c0abe83a6d923376..211acdffbe88645c2cb08a944b5f8201f03566ec 100644
--- a/DSView/pv/dock/measuredock.cpp
+++ b/DSView/pv/dock/measuredock.cpp
@@ -26,6 +26,7 @@
 #include "../sigsession.h"
 #include "../view/cursor.h"
 #include "../view/view.h"
+#include "../view/viewport.h"
 #include "../view/timemarker.h"
 #include "../view/ruler.h"
 #include "../view/logicsignal.h"
@@ -54,9 +55,10 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) :
     _mouse_groupBox = new QGroupBox("Mouse measurement", this);
     _fen_checkBox = new QCheckBox("Enable floating measurement", this);
     _fen_checkBox->setChecked(true);
-    _width_label = new QLabel(view.get_mm_width(), this);
-    _period_label = new QLabel(view.get_mm_period(), this);
-    _freq_label = new QLabel(view.get_mm_freq(), this);
+    _width_label = new QLabel("#####", this);
+    _period_label = new QLabel("#####", this);
+    _freq_label = new QLabel("#####", this);
+    _duty_label = new QLabel("#####", this);
 
     _mouse_layout = new QGridLayout();
     _mouse_layout->addWidget(_fen_checkBox, 0, 0, 1, 2);
@@ -66,10 +68,13 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) :
     _mouse_layout->addWidget(_period_label, 2, 1);
     _mouse_layout->addWidget(new QLabel("Frequency: ", this), 3, 0);
     _mouse_layout->addWidget(_freq_label, 3, 1);
+    _mouse_layout->addWidget(new QLabel("Duty Cycle: ", this), 4, 0);
+    _mouse_layout->addWidget(_duty_label, 4, 1);
     _mouse_layout->addWidget(new QLabel(this), 0, 2);
     _mouse_layout->addWidget(new QLabel(this), 1, 2);
     _mouse_layout->addWidget(new QLabel(this), 2, 2);
     _mouse_layout->addWidget(new QLabel(this), 3, 2);
+    _mouse_layout->addWidget(new QLabel(this), 4, 2);
     _mouse_layout->setColumnStretch(2, 1);
     _mouse_groupBox->setLayout(_mouse_layout);
 
@@ -134,6 +139,7 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) :
     connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update()));
 
     connect(_fen_checkBox, SIGNAL(stateChanged(int)), &_view, SLOT(set_measure_en(int)));
+    connect(_view.get_viewport(), SIGNAL(mouse_measure()), this, SLOT(mouse_measure()));
 }
 
 MeasureDock::~MeasureDock()
@@ -216,11 +222,12 @@ void MeasureDock::cursor_update()
     update();
 }
 
-void MeasureDock::mouse_moved()
+void MeasureDock::mouse_measure()
 {
-    _width_label->setText(_view.get_mm_width());
-    _period_label->setText(_view.get_mm_period());
-    _freq_label->setText(_view.get_mm_freq());
+    _width_label->setText(_view.get_viewport()->get_measure("width"));
+    _period_label->setText(_view.get_viewport()->get_measure("period"));
+    _freq_label->setText(_view.get_viewport()->get_measure("frequency"));
+    _duty_label->setText(_view.get_viewport()->get_measure("duty"));
 }
 
 void MeasureDock::cursor_moved()
diff --git a/DSView/pv/dock/measuredock.h b/DSView/pv/dock/measuredock.h
index 500ec66e52a65f1d877bd7e899844928e40a48c5..fa29db6472a140d4c902a65ddab84142225e5864 100644
--- a/DSView/pv/dock/measuredock.h
+++ b/DSView/pv/dock/measuredock.h
@@ -74,7 +74,7 @@ private slots:
 public slots:
     void cursor_update();
     void cursor_moved();
-    void mouse_moved();
+    void mouse_measure();
 
 private:
     SigSession &_session;
@@ -86,6 +86,7 @@ private:
     QLabel *_width_label;
     QLabel *_period_label;
     QLabel *_freq_label;
+    QLabel *_duty_label;
 
     QGridLayout *_cursor_layout;
     QGroupBox *_cursor_groupBox;
diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp
index 7a0c9407bafccf607eafa5c5d15889616ab8e977..10410ba6d2c533010fa11ae6f2f2a95760c1834e 100644
--- a/DSView/pv/mainwindow.cpp
+++ b/DSView/pv/mainwindow.cpp
@@ -244,8 +244,6 @@ void MainWindow::setup_ui()
             SLOT(cursor_update()));
     connect(_view, SIGNAL(cursor_moved()), _measure_widget,
             SLOT(cursor_moved()));
-    connect(_view, SIGNAL(mouse_moved()), _measure_widget,
-            SLOT(mouse_moved()));
     connect(_view, SIGNAL(mode_changed()), this,
             SLOT(update_device_list()));
 
diff --git a/DSView/pv/view/cursor.cpp b/DSView/pv/view/cursor.cpp
index 0945a6e893b8d709840e486792c487cdcc4f568f..819f97d4ca1ba65ff4b21052abe6a53b1c123e06 100644
--- a/DSView/pv/view/cursor.cpp
+++ b/DSView/pv/view/cursor.cpp
@@ -51,8 +51,14 @@ const int Cursor::ArrowSize = 10;
 
 const int Cursor::CloseSize = 10;
 
-Cursor::Cursor(View &view, QColor color, double time) :
-    TimeMarker(view, color, time),
+Cursor::Cursor(View &view, QColor color, uint64_t index) :
+    TimeMarker(view, color, index),
+    _other(*this)
+{
+}
+
+Cursor::Cursor(View &view, QColor color) :
+    TimeMarker(view, color),
     _other(*this)
 {
 }
diff --git a/DSView/pv/view/cursor.h b/DSView/pv/view/cursor.h
index d06c4186b158dbae8ffc0559614cbd07ef2dae3e..afecc62f6ed4a49d2b2f2f7503d7106f43e0b624 100644
--- a/DSView/pv/view/cursor.h
+++ b/DSView/pv/view/cursor.h
@@ -55,7 +55,9 @@ public:
 	 * @param time The time to set the flag to.
 	 * @param other A reference to the other cursor.
 	 */
-    Cursor(View &view, QColor color, double time);
+    Cursor(View &view, QColor color);
+    Cursor(View &view, QColor color, uint64_t index);
+
 
 public:
 	/**
diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp
index df0bbb4e00eb7b6651816c56b0bb8b4fba3f2c12..9e9ae59320a02eb9e60cf58ffcaae11846276358 100644
--- a/DSView/pv/view/logicsignal.cpp
+++ b/DSView/pv/view/logicsignal.cpp
@@ -273,5 +273,48 @@ void LogicSignal::paint_type_options(QPainter &p, int right, bool hover, int act
                edgeTrig_rect.right() - 5, edgeTrig_rect.bottom() - 5);
 }
 
+bool LogicSignal::measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2) const
+{
+    const float gap = abs(p.y() - get_y());
+    if (gap < get_signalHeight() * 0.5) {
+        const deque< boost::shared_ptr<pv::data::LogicSnapshot> > &snapshots =
+            _data->get_snapshots();
+        if (snapshots.empty())
+            return false;
+
+        const boost::shared_ptr<pv::data::LogicSnapshot> &snapshot =
+            snapshots.front();
+        if (snapshot->buf_null())
+            return false;
+
+        uint64_t index = _data->samplerate() * (_view->offset() - _data->get_start_time() + p.x() * _view->scale());
+        if (index == 0)
+            return false;
+
+        const uint64_t sig_mask = 1ULL << get_index();
+        bool sample = snapshot->get_sample(index) & sig_mask;
+        index--;
+        if (!snapshot->get_pre_edge(index, sample, 1, get_index()))
+            return false;
+
+        index0 = index;
+        sample = snapshot->get_sample(index) & sig_mask;
+        index++;
+        if (!snapshot->get_nxt_edge(index, sample, snapshot->get_sample_count(), 1, get_index()))
+            return false;
+
+        index1 = index;
+        sample = snapshot->get_sample(index) & sig_mask;
+        index++;
+        if (!snapshot->get_nxt_edge(index, sample, snapshot->get_sample_count(), 1, get_index()))
+            index2 = 0;
+        else
+            index2 = index;
+
+        return true;
+    }
+    return false;
+}
+
 } // namespace view
 } // namespace pv
diff --git a/DSView/pv/view/logicsignal.h b/DSView/pv/view/logicsignal.h
index 47b464316fec6f63ef7d4bc5e976aee2baf7cfd4..75ea8e4df47336ba1651835d543545d05e6028de 100644
--- a/DSView/pv/view/logicsignal.h
+++ b/DSView/pv/view/logicsignal.h
@@ -76,6 +76,8 @@ public:
 
     const std::vector< std::pair<uint64_t, bool> > cur_edges() const;
 
+    bool measure(const QPointF &p, uint64_t &index0, uint64_t &index1, uint64_t &index2) const;
+
 protected:
     void paint_type_options(QPainter &p, int right, bool hover, int action);
 
diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp
index a96a856142950067160fa2783ea45545501e47c4..b4b2ba9bb6dc556a6239ac9bd2244319a84ed4f5 100644
--- a/DSView/pv/view/ruler.cpp
+++ b/DSView/pv/view/ruler.cpp
@@ -134,6 +134,29 @@ QString Ruler::format_time(double t)
     return format_time(t, _cur_prefix);
 }
 
+QString Ruler::format_real_time(uint64_t delta_index, uint64_t sample_rate)
+{
+    uint64_t delta_time = delta_index * std::pow(10, 12) / sample_rate;
+
+    if (delta_time == 0)
+        return "0";
+
+    int zero = 0;
+    int prefix = (int)floor(log10(delta_time));
+    while(delta_time == (delta_time/10*10)) {
+        delta_time /= 10;
+        zero++;
+    }
+
+    return format_time(delta_time * 1.0f / std::pow(10, 12-zero), prefix/3+1, prefix/3*3 > zero ? prefix/3*3 - zero : 0);
+}
+
+QString Ruler::format_real_freq(uint64_t delta_index, uint64_t sample_rate)
+{
+    const double delta_period = delta_index * 1.0f / sample_rate;
+    return format_freq(delta_period);
+}
+
 TimeMarker* Ruler::get_grabbed_cursor()
 {
     return _grabbed_marker;
@@ -182,8 +205,8 @@ void Ruler::mouseMoveEvent(QMouseEvent *e)
     (void)e;
 
     if (_grabbed_marker) {
-        _grabbed_marker->set_time(_view.offset() +
-            _view.hover_point().x() * _view.scale());
+        _grabbed_marker->set_index((_view.offset() +
+            _view.hover_point().x() * _view.scale()) * _view.session().get_device()->get_sample_rate());
     }
 
     update();
@@ -242,19 +265,17 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event)
                     _cursor_sel_visible = true;
                 } else {
                     int overCursor;
-                    double time = _view.offset() + (_cursor_sel_x + 0.5) * _view.scale();
+                    uint64_t index = (_view.offset() + (_cursor_sel_x + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate();
                     overCursor = in_cursor_sel_rect(event->pos());
                     if (overCursor == 0) {
-                        //Cursor *newCursor = new Cursor(_view, CursorColor[_view.get_cursorList().size() % 8], time);
-                        //_view.get_cursorList().push_back(newCursor);
-                        _view.add_cursor(CursorColor[_view.get_cursorList().size() % 8], time);
+                        _view.add_cursor(CursorColor[_view.get_cursorList().size() % 8], index);
                         _view.show_cursors(true);
                         addCursor = true;
                     } else if (overCursor > 0) {
                         list<Cursor*>::iterator i = _view.get_cursorList().begin();
                         while (--overCursor != 0)
                                 i++;
-                        (*i)->set_time(time);
+                        (*i)->set_index(index);
                     }
                     _cursor_sel_visible = false;
                 }
@@ -262,10 +283,6 @@ void Ruler::mouseReleaseEvent(QMouseEvent *event)
                 int overCursor;
                 overCursor = in_cursor_sel_rect(event->pos());
                 if (overCursor > 0) {
-//                    list<Cursor*>::iterator i = _view.get_cursorList().begin();
-//                    while (--overCursor != 0)
-//                            i++;
-//                    _view.set_scale_offset(_view.scale(), (*i)->time() - _view.scale() * _view.viewport()->width() / 2);
                     _view.set_cursor_middle(overCursor - 1);
                 }
 
diff --git a/DSView/pv/view/ruler.h b/DSView/pv/view/ruler.h
index 114ff9ff8182d45d9d4b71776385842db4e9c006..1f322470880e0cd813102d6a2504b679fb7ff79d 100644
--- a/DSView/pv/view/ruler.h
+++ b/DSView/pv/view/ruler.h
@@ -25,6 +25,7 @@
 #define DSVIEW_PV_VIEW_RULER_H
 
 #include <QWidget>
+#include <stdint.h>
 
 namespace pv {
 namespace view {
@@ -66,6 +67,8 @@ public:
         unsigned precision = pricision);
     static QString format_freq(double period, unsigned precision = pricision);
     QString format_time(double t);
+    static QString format_real_time(uint64_t delta_index, uint64_t sample_rate);
+    static QString format_real_freq(uint64_t delta_index, uint64_t sample_rate);
 
     TimeMarker* get_grabbed_cursor();
     void set_grabbed_cursor(TimeMarker* grabbed_marker);
diff --git a/DSView/pv/view/timemarker.cpp b/DSView/pv/view/timemarker.cpp
index 13856d9c308e84c7dd7c96a8dc3241b30c8ac09d..7fdcbbd909ea25767f66df83416809b17ddc6a45 100644
--- a/DSView/pv/view/timemarker.cpp
+++ b/DSView/pv/view/timemarker.cpp
@@ -24,6 +24,7 @@
 #include "timemarker.h"
 
 #include "view.h"
+#include "../device/device.h"
 
 #include <QPainter>
 
@@ -31,18 +32,29 @@ namespace pv {
 namespace view {
 
 TimeMarker::TimeMarker(View &view, QColor &colour,
-	double time) :
+    uint64_t index) :
 	_view(view),
-	_time(time),
-        _grabbed(false),
+    _time(index * 1.0f / view.session().get_device()->get_sample_rate()),
+    _index(index),
+    _grabbed(false),
 	_colour(colour)
 {
 }
 
+TimeMarker::TimeMarker(View &view, QColor &colour) :
+    _view(view),
+    _time(0),
+    _index(0),
+    _grabbed(false),
+    _colour(colour)
+{
+}
+
 TimeMarker::TimeMarker(const TimeMarker &s) :
 	QObject(),
 	_view(s._view),
 	_time(s._time),
+    _index(s._index),
 	_colour(s._colour)
 {
 }
@@ -61,10 +73,16 @@ double TimeMarker::time() const
 	return _time;
 }
 
-void TimeMarker::set_time(double time)
+uint64_t TimeMarker::index() const
+{
+    return _index;
+}
+
+void TimeMarker::set_index(uint64_t index)
 {
-	_time = time;
-	time_changed();
+    _index = index;
+    _time = index * 1.0f / _view.session().get_device()->get_sample_rate();
+    time_changed();
 }
 
 void TimeMarker::paint(QPainter &p, const QRect &rect, const bool highlight)
diff --git a/DSView/pv/view/timemarker.h b/DSView/pv/view/timemarker.h
index ad0ca7e69d78c817796f9c7d3908850860478d4e..e82b4c62e7019d50a3e0ebfdf3d6856c7cc81d2d 100644
--- a/DSView/pv/view/timemarker.h
+++ b/DSView/pv/view/timemarker.h
@@ -28,6 +28,8 @@
 #include <QObject>
 #include <QRectF>
 
+#include <stdint.h>
+
 class QPainter;
 class QRect;
 
@@ -47,7 +49,8 @@ protected:
 	 * @param colour A reference to the colour of this cursor.
 	 * @param time The time to set the flag to.
 	 */
-    TimeMarker(View &view, QColor &colour, double time);
+    TimeMarker(View &view, QColor &colour, uint64_t index);
+    TimeMarker(View &view, QColor &colour);
 
 	/**
 	 * Copy constructor
@@ -59,11 +62,12 @@ public:
 	 * Gets the time of the marker.
 	 */
 	double time() const;
+    uint64_t index() const;
 
 	/**
 	 * Sets the time of the marker.
 	 */
-	void set_time(double time);
+    void set_index(uint64_t index);
 
     /*
      *
@@ -104,6 +108,7 @@ protected:
     View &_view;
 
 	double _time;
+    uint64_t _index;
 
 	QSizeF _text_size;
 
diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp
index 1a912d40832bb514d0e115ca6f39f1bb65ecb1f4..af440a76a9ae87a41bd7c9d2c498aaec644c5ffe 100644
--- a/DSView/pv/view/view.cpp
+++ b/DSView/pv/view/view.cpp
@@ -125,10 +125,10 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget
     _header->setObjectName(tr("ViewArea_header"));
 
     _show_trig_cursor = false;
-    _trig_cursor = new Cursor(*this, Trace::dsLightRed, 0);
+    _trig_cursor = new Cursor(*this, Trace::dsLightRed);
     _show_search_cursor = false;
     _search_pos = 0;
-    _search_cursor = new Cursor(*this, Trace::dsLightBlue, _search_pos);
+    _search_cursor = new Cursor(*this, Trace::dsLightBlue);
 }
 
 SigSession& View::session()
@@ -343,7 +343,7 @@ void View::set_trig_pos(quint64 trig_pos)
 {
     const double time = trig_pos * 1.0f / _session.get_device()->get_sample_rate();
     _trig_pos = trig_pos;
-    _trig_cursor->set_time(time);
+    _trig_cursor->set_index(trig_pos);
     _show_trig_cursor = true;
     set_scale_offset(_scale,  time - _scale * get_view_width() / 2);
     _ruler->update();
@@ -356,7 +356,7 @@ void View::set_search_pos(uint64_t search_pos)
 
     const double time = search_pos * 1.0f / _session.get_device()->get_sample_rate();
     _search_pos = search_pos;
-    _search_cursor->set_time(time);
+    _search_cursor->set_index(search_pos);
     set_scale_offset(_scale,  time - _scale * get_view_width() / 2);
     _ruler->update();
     _viewport->update();
@@ -464,8 +464,7 @@ void View::update_scale()
     _preScale = _scale;
     _preOffset = _offset;
 
-    const double time = _trig_pos * 1.0f / sample_rate;
-    _trig_cursor->set_time(time);
+    _trig_cursor->set_index(_trig_pos);
 
     _ruler->update();
     _viewport->update();
@@ -697,9 +696,9 @@ Ruler* View::get_ruler()
     return _ruler;
 }
 
-void View::add_cursor(QColor color, double time)
+void View::add_cursor(QColor color, uint64_t index)
 {
-    Cursor *newCursor = new Cursor(*this, color, time);
+    Cursor *newCursor = new Cursor(*this, color, index);
     _cursorList.push_back(newCursor);
     cursor_update();
 }
@@ -728,24 +727,14 @@ void View::receive_data(quint64 length)
     _viewport->set_receive_len(length);
 }
 
-QString View::get_mm_width()
+Viewport * View::get_viewport()
 {
-    return _viewport->get_mm_width();
-}
-
-QString View::get_mm_period()
-{
-    return _viewport->get_mm_period();
-}
-
-QString View::get_mm_freq()
-{
-    return _viewport->get_mm_freq();
+    return _viewport;
 }
 
 QString View::get_cm_time(int index)
 {
-    return _ruler->format_time(get_cursor_time(index));
+    return _ruler->format_real_time(get_cursor_samples(index), _session.get_device()->get_sample_rate());
 }
 
 QString View::get_cm_delta(int index1, int index2)
@@ -753,8 +742,10 @@ QString View::get_cm_delta(int index1, int index2)
     if (index1 == index2)
         return "0";
 
-    return _ruler->format_time(abs(get_cursor_time(index1) -
-                                   get_cursor_time(index2)));
+    uint64_t samples1 = get_cursor_samples(index1);
+    uint64_t samples2 = get_cursor_samples(index2);
+    uint64_t delta_sample = (samples1 > samples2) ? samples1 - samples2 : samples2 - samples1;
+    return _ruler->format_real_time(delta_sample, _session.get_device()->get_sample_rate());
 }
 
 double View::get_cursor_time(int index)
@@ -773,17 +764,18 @@ double View::get_cursor_time(int index)
 
 uint64_t View::get_cursor_samples(int index)
 {
-    const double time = get_cursor_time(index);
-    const uint64_t sample_rate = _session.get_device()->get_sample_limit();
-    assert(sample_rate !=0);
+    assert(index < (int)_cursorList.size());
 
-    return time*sample_rate;
+    int curIndex = 0;
+    for (list<Cursor*>::iterator i = _cursorList.begin();
+         i != _cursorList.end(); i++) {
+        if (index == curIndex) {
+            return (*i)->index();
+        }
+        curIndex++;
+    }
 }
 
-void View::on_mouse_moved()
-{
-    mouse_moved();
-}
 void View::on_cursor_moved()
 {
     cursor_moved();
diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h
index 2f82a01ed755a86f489bce2f2e0a6f0c449500fb..228318acc8c4da370caa4f7fd2e199473d07188e 100644
--- a/DSView/pv/view/view.h
+++ b/DSView/pv/view/view.h
@@ -140,7 +140,7 @@ public:
      * cursorList
      */
     std::list<Cursor*>& get_cursorList();
-    void add_cursor(QColor color, double time);
+    void add_cursor(QColor color, uint64_t index);
     void del_cursor(Cursor* cursor);
     void set_cursor_middle(int index);
 
@@ -163,13 +163,10 @@ public:
     bool need_update() const;
 
     uint64_t get_cursor_samples(int index);
-    QString get_mm_width();
-    QString get_mm_period();
-    QString get_mm_freq();
+    Viewport * get_viewport();
     QString get_cm_time(int index);
     QString get_cm_delta(int index1, int index2);
 
-    void on_mouse_moved();
     void on_cursor_moved();
 
     void on_state_changed(bool stop);
@@ -189,7 +186,6 @@ signals:
 
     void cursor_update();
 
-    void mouse_moved();
     void cursor_moved();
 
     void mode_changed();
diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp
index c8aa429974da2fc644f1c5e60eb207e7bf9c3b3a..8bc05428482da340afd9e5854e37fc7c23303a3a 100644
--- a/DSView/pv/view/viewport.cpp
+++ b/DSView/pv/view/viewport.cpp
@@ -27,6 +27,7 @@
 
 #include "signal.h"
 #include "dsosignal.h"
+#include "logicsignal.h"
 #include "../device/devinst.h"
 #include "../data/logic.h"
 #include "../data/logicsnapshot.h"
@@ -63,6 +64,7 @@ Viewport::Viewport(View &parent) :
     _mm_width = "#####";
     _mm_period = "#####";
     _mm_freq = "#####";
+    _mm_duty = "#####";
     _measure_en = true;
     triggered = false;
     timer_cnt = 0;
@@ -110,7 +112,7 @@ void Viewport::paintEvent(QPaintEvent *event)
         t->paint_back(p, 0, _view.get_view_width());
     }
 
-    p.setRenderHint(QPainter::Antialiasing);
+    p.setRenderHint(QPainter::Antialiasing, false);
     if (_view.session().get_device()->dev_inst()->mode == LOGIC ||
         _view.session().get_instant()) {
         switch(_view.session().get_capture_state()) {
@@ -137,7 +139,7 @@ void Viewport::paintEvent(QPaintEvent *event)
             t->paint_fore(p, 0, _view.get_view_width());
     }
 
-    p.setRenderHint(QPainter::Antialiasing, false);
+    //p.setRenderHint(QPainter::Antialiasing, false);
     if (_view.get_signalHeight() != _curSignalHeight)
             _curSignalHeight = _view.get_signalHeight();
 
@@ -159,7 +161,7 @@ void Viewport::paintSignals(QPainter &p)
         pixmap.fill(Qt::transparent);
         QPainter dbp(&pixmap);
         dbp.initFrom(this);
-        p.setRenderHint(QPainter::Antialiasing, false);
+        //p.setRenderHint(QPainter::Antialiasing, false);
         BOOST_FOREACH(const shared_ptr<Trace> t, traces)
         {
             assert(t);
@@ -404,12 +406,10 @@ void Viewport::mouseMoveEvent(QMouseEvent *event)
             const double cur_time = _view.offset() + _view.hover_point().x() * _view.scale();
             const double pos = cur_time * sample_rate;
             const double pos_delta = pos - (int)pos;
-            if ( pos_delta < HitCursorTimeMargin)
-                grabbed_marker->set_time(1.0 / sample_rate * floor(pos));
-            else if (pos_delta > (1.0 - HitCursorTimeMargin))
-                grabbed_marker->set_time(1.0 / sample_rate * ceil(pos));
+            if ( pos_delta < 0.5)
+                grabbed_marker->set_index(floor(pos));
             else
-                grabbed_marker->set_time(cur_time);
+                grabbed_marker->set_index(ceil(pos));
         }
         measure();
     }
@@ -499,99 +499,42 @@ void Viewport::set_receive_len(quint64 length)
 
 void Viewport::measure()
 {
-    uint64_t sample_rate = _view.session().get_device()->get_sample_rate();
-
-    const vector< boost::shared_ptr<Signal> > sigs(_view.session().get_signals());
-    BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
-        assert(s);
-        const int curY = _view.hover_point().y();
-        const double curX = _view.hover_point().x();
-        if (curY <= View::SignalMargin || s->get_type() != Trace::DS_LOGIC) {
-            _measure_shown = false;
-            break;
-        } else if ( curY < s->get_y() + _view.get_signalHeight() * 0.5 &&
-                    curY > (s->get_y() - _view.get_signalHeight() * 0.5)) {
-            if (s->cur_edges().size() > 2) {
-                const double pixels_offset = _view.offset() / _view.scale();
-                const double samples_per_pixel = sample_rate * _view.scale();
-
-                uint64_t findIndex = curX / _view.get_view_width() * s->cur_edges().size();
-                uint64_t left_findIndex = 0;
-                uint64_t right_findIndex = s->cur_edges().size() - 1;
-                int times = 0;
-                while(!s->cur_edges().empty() && times < 20) {
-                    findIndex = min(findIndex, (uint64_t)(s->cur_edges().size() - 2));
-                    const double pre_edge_x =
-                            s->cur_edges().at(findIndex).first / samples_per_pixel - pixels_offset;
-                    const double aft_edge_x =
-                            s->cur_edges().at(findIndex + 1).first / samples_per_pixel - pixels_offset;
-                    if ( curX >= pre_edge_x && curX <= aft_edge_x) {
-                        if (aft_edge_x - pre_edge_x < 2 ||
-                                findIndex == 0 ||
-                                findIndex == s->cur_edges().size() - 2) {
-                            _measure_shown = false;
-                            break;
-                        } else {
-                            _measure_shown = true;
-                            _cur_sample = s->cur_edges().at(findIndex).first;
-                            _nxt_sample = s->cur_edges().at(findIndex + 1).first;
-                            _cur_preX = pre_edge_x;
-                            _cur_aftX = aft_edge_x;
-                            //if (findIndex >= 0 && findIndex <= s->cur_edges().size() - 4) {
-                            if(findIndex <= s->cur_edges().size() - 4) {
-                                _thd_sample = s->cur_edges().at(findIndex + 2).first;
-                                _cur_thdX =
-                                        s->cur_edges().at(findIndex + 2).first / samples_per_pixel - pixels_offset;
-                            } else {
-                                _thd_sample = 0;
-                                _cur_thdX = 0;
-
-                            }
-                            _cur_midY = s->get_y();
-                            break;
-                        }
-                    } else if (curX < pre_edge_x) {
-                        right_findIndex = findIndex;
-                        findIndex = (left_findIndex + findIndex) / 2;
-                    } else if (curX > aft_edge_x) {
-                        left_findIndex = findIndex;
-                        findIndex = (right_findIndex + findIndex) / 2;
-                    }
-                    times++;
-                }
-            }
-            break;
-        } else if (curY >= s->get_y() + _view.get_signalHeight() &&
-                   curY <= (s->get_y()  + _view.get_signalHeight() + 2 * View::SignalMargin)){
-            _measure_shown = false;
-            break;
-        }else {
-            _measure_shown = false;
-        }
-    }
-
-    if (_measure_shown == true) {
-        const uint64_t delta_sample = _nxt_sample - _cur_sample;
-        const uint64_t delta1_sample = _thd_sample - _cur_sample;
-        //assert(delta_sample >= 0);
-        const double delta_time = delta_sample * 1.0f / sample_rate;
-        const double delta1_time = delta1_sample * 1.0f / sample_rate;
-        const int order = (int)floorf(log10f(delta_time));
-        unsigned int prefix = (15 + order) / 3;
-        assert(prefix < 9);
-
-        _mm_width = _view.get_ruler()->format_time(delta_time, prefix);
-        _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_time(delta1_time, prefix) :
-                                        "#####";
-        _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_freq(delta1_time) :
-                                      "#####";
-    } else {
-        _mm_width = "#####";
-        _mm_period = "#####";
-        _mm_freq = "#####";
+   const uint64_t sample_rate = _view.session().get_device()->get_sample_rate();
+   const vector< boost::shared_ptr<Signal> > sigs(_view.session().get_signals());
+   BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
+       assert(s);
+       shared_ptr<view::LogicSignal> logicSig;
+       if (logicSig = dynamic_pointer_cast<view::LogicSignal>(s)) {
+           if (logicSig->measure(_view.hover_point(), _cur_sample, _nxt_sample, _thd_sample)) {
+               _measure_shown = true;
+
+               _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate);
+               _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####";
+               _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####";
+
+               const double pixels_offset =  _view.offset() / _view.scale();
+               const double samples_per_pixel = sample_rate * _view.scale();
+               _cur_preX = _cur_sample / samples_per_pixel - pixels_offset;
+               _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset;
+               _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset;
+               _cur_midY = logicSig->get_y();
+
+               _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0f / (_thd_sample - _cur_sample), 'f', 2)+"%" :
+                                             "#####";
+               mouse_measure();
+               return;
+           } else {
+               _mm_width = "#####";
+               _mm_period = "#####";
+               _mm_freq = "#####";
+               _mm_duty = "#####";
+           }
+           mouse_measure();
+       }
     }
 
-    _view.on_mouse_moved();
+    _measure_shown = false;
+    return;
 }
 
 void Viewport::paintMeasure(QPainter &p)
@@ -614,13 +557,15 @@ void Viewport::paintMeasure(QPainter &p)
         double typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX,
             Qt::AlignLeft | Qt::AlignTop, _mm_width).width() + 150;
         QRectF measure_rect = QRectF(_view.hover_point().x(), _view.hover_point().y(),
-                                     (double)typical_width, 60.0);
+                                     (double)typical_width, 80.0);
         QRectF measure1_rect = QRectF(_view.hover_point().x(), _view.hover_point().y(),
                                      (double)typical_width, 20.0);
         QRectF measure2_rect = QRectF(_view.hover_point().x(), _view.hover_point().y() + 20,
                                      (double)typical_width, 20.0);
         QRectF measure3_rect = QRectF(_view.hover_point().x(), _view.hover_point().y() + 40,
                                      (double)typical_width, 20.0);
+        QRectF measure4_rect = QRectF(_view.hover_point().x(), _view.hover_point().y() + 60,
+                                     (double)typical_width, 20.0);
 
         p.setPen(Qt::NoPen);
         p.setBrush(QColor(17, 133, 209,  150));
@@ -633,22 +578,23 @@ void Viewport::paintMeasure(QPainter &p)
                    "Period: " + _mm_period);
         p.drawText(measure3_rect, Qt::AlignRight | Qt::AlignVCenter,
                    "Frequency: " + _mm_freq);
+        p.drawText(measure4_rect, Qt::AlignRight | Qt::AlignVCenter,
+                   "Duty Cycle: " + _mm_duty);
     }
 }
 
-QString Viewport::get_mm_width()
-{
-    return _mm_width;
-}
-
-QString Viewport::get_mm_period()
+QString Viewport::get_measure(QString option)
 {
-    return _mm_period;
-}
-
-QString Viewport::get_mm_freq()
-{
-    return _mm_freq;
+    if(option.compare("width") == 0)
+        return _mm_width;
+    else if (option.compare("period") == 0)
+        return _mm_period;
+    else if (option.compare("frequency") == 0)
+        return _mm_freq;
+    else if (option.compare("duty") == 0)
+        return _mm_duty;
+    else
+        return "#####";
 }
 
 void Viewport::set_measure_en(int enable)
diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h
index 1f8157a98a7f2ed23d8e6652cd77189fcb0a4403..68cc93c695032147c503402f953677dc35a7749a 100644
--- a/DSView/pv/view/viewport.h
+++ b/DSView/pv/view/viewport.h
@@ -47,7 +47,6 @@ class Viewport : public QWidget
 
 public:
     static const int HitCursorMargin = 10;
-    static const double HitCursorTimeMargin = 0.3;
 
 public:
 	explicit Viewport(View &parent);
@@ -58,9 +57,7 @@ public:
 
     void set_receive_len(quint64 length);
 
-    QString get_mm_width();
-    QString get_mm_period();
-    QString get_mm_freq();
+    QString get_measure(QString option);
 
     void set_measure_en(int enable);
 
@@ -88,6 +85,9 @@ private slots:
     void on_traces_moved();
     void on_trigger_timer();
 
+signals:
+    void mouse_measure();
+
 private:
 	View &_view;
 
@@ -109,13 +109,14 @@ private:
     uint64_t _cur_sample;
     uint64_t _nxt_sample;
     uint64_t _thd_sample;
-    int64_t _cur_preX;
-    int64_t _cur_aftX;
-    int64_t _cur_thdX;
-    int64_t _cur_midY;
+    double _cur_preX;
+    double _cur_aftX;
+    double _cur_thdX;
+    double _cur_midY;
     QString _mm_width;
     QString _mm_period;
     QString _mm_freq;
+    QString _mm_duty;
 
     QTimer trigger_timer;
     bool triggered;