Merge branch 'release-0.93'

This commit is contained in:
DreamSourceLab 2015-05-08 16:11:21 +08:00
commit 56dc212337
81 changed files with 3069 additions and 2744 deletions

13
.gitignore vendored
View File

@ -31,16 +31,19 @@ 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
qrc_*.cxx
libsigrok4DSLogic/version.h
libsigrok4DSL/version.h
libusbx-1.0.18/doc/doxygen.cfg
libusbx-1.0.18/m4/
DSView-prj
libsigrokdecode
build*

View File

@ -103,7 +103,7 @@ set(DS_DESCRIPTION "A GUI for instruments of DreamSourceLab")
set(DS_VERSION_MAJOR 0)
set(DS_VERSION_MINOR 9)
set(DS_VERSION_MICRO 2)
set(DS_VERSION_MICRO 3)
set(DS_VERSION_STRING
${DS_VERSION_MAJOR}.${DS_VERSION_MINOR}.${DS_VERSION_MICRO}
)
@ -270,7 +270,7 @@ endif()
#-------------------------------------------------------------------------------
add_definitions(${QT_DEFINITIONS})
add_definitions(-Wall -Wextra -Wno-return-type -Wno-ignored-qualifiers)
add_definitions(-std=c++11 -Wall -Wextra -Wno-return-type -Wno-ignored-qualifiers)
if(ENABLE_DECODE)
add_definitions(-DENABLE_DECODE)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -30,7 +30,7 @@
#include <getopt.h>
#include <QtGui/QApplication>
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDir>
@ -40,8 +40,6 @@
#include "config.h"
char decoders_path[256];
void usage()
{
fprintf(stdout,
@ -122,11 +120,6 @@ int main(int argc, char *argv[])
do {
#ifdef ENABLE_DECODE
QDir dir(QCoreApplication::applicationDirPath());
assert(dir.cd("decoders"));
std::string str = dir.absolutePath().toStdString() + "/";
strcpy(decoders_path, str.c_str());
// Initialise libsigrokdecode
if (srd_init(NULL) != SRD_OK) {
qDebug() << "ERROR: libsigrokdecode init failed.";

View File

@ -433,6 +433,11 @@ void DecoderStack::decode_proc()
_decode_state = Stopped;
}
uint64_t DecoderStack::sample_count() const
{
return _sample_count;
}
void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder)
{
assert(pdata);

View File

@ -120,6 +120,8 @@ public:
void options_changed(bool changed);
uint64_t sample_count() const;
private:
boost::optional<uint64_t> wait_for_data() const;

View File

@ -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);
assert(index > 0);
boost::lock_guard<boost::recursive_mutex> lock(_mutex);
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;
// 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)
{
//----- 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);
// 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;
if (fast_forward) {
// 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;
}
// 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.
if (fast_forward) {
// 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;
// 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.
// 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))
// 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;
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);
// 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;
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;
// 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 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);
assert(index < get_sample_count());
boost::lock_guard<boost::recursive_mutex> lock(_mutex);
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;
//----- Continue to search -----//
level = min_level;
while (index + block_length <= end)
// 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)
{
//----- Continue to search -----//
level = min_level;
// 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;
// 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++)
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;
index++;
return true;
}
if (index == 0)
return 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
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
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 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++)
{
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;
}
// 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;
}
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
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
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;
if (index == 0)
return false;
}
// Add the final state
min_pulse = min(end - last_index, min_pulse);
if (fast_forward) {
return min_pulse;
// 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;
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;
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;
}
}
// 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;
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
if (min_length < MipMapScaleFactor) {
for (; index >= 0; index--) {
const bool sample = (get_sample(index) &
sig_mask) != 0;
if (sample != last_sample) {
index++;
return true;
}
if (index == 0)
return false;
}
}
}
return false;
}
uint64_t LogicSnapshot::get_subsample(int level, uint64_t offset) const

View File

@ -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;

View File

@ -170,7 +170,7 @@ double DevInst::get_sample_time()
if (sample_rate == 0)
sample_time = 0;
else
sample_time = sample_limit * 1.0f / sample_rate;
sample_time = sample_limit * 1.0 / sample_rate;
return sample_time;
}

View File

@ -31,7 +31,7 @@
#include <stdexcept>
#include <string>
#include <QtGui/QApplication>
#include <QApplication>
#include <QObject>
#include <QDebug>
#include <QDir>

View File

@ -37,7 +37,7 @@ using namespace std;
namespace pv {
namespace dialogs {
DeviceOptions::DeviceOptions(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst) :
DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst) :
QDialog(parent),
_dev_inst(dev_inst),
_layout(this),

View File

@ -37,7 +37,7 @@ using namespace std;
namespace pv {
namespace dialogs {
StreamOptions::StreamOptions(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst,
StreamOptions::StreamOptions(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst,
uint64_t sample_count, bool stream) :
QDialog(parent),
_dev_inst(dev_inst),

View File

@ -39,7 +39,7 @@ namespace dialogs {
const QString WaitingDialog::TIPS_INFO = "Waiting";
WaitingDialog::WaitingDialog(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst) :
WaitingDialog::WaitingDialog(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst) :
QDialog(parent),
_dev_inst(dev_inst),
_button_box(QDialogButtonBox::Save | QDialogButtonBox::Abort,
@ -48,8 +48,7 @@ WaitingDialog::WaitingDialog(QWidget *parent, shared_ptr<pv::device::DevInst> de
this->setFixedSize((GIF_SIZE+TIP_WIDTH)*2, (GIF_SIZE+TIP_HEIGHT)*2);
int midx = this->width() / 2;
int midy = this->height() / 2;
this->setWindowOpacity(0.6);
this->setStyleSheet("background-color: rgb(255, 255, 255);");
this->setWindowOpacity(0.7);
this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
label = new QLabel(this);
@ -60,7 +59,6 @@ WaitingDialog::WaitingDialog(QWidget *parent, shared_ptr<pv::device::DevInst> de
tips = new QLabel(this);
tips->setText(TIPS_INFO);
tips->setStyleSheet("color: rgb(17, 133, 209); background-color: transparent;");
QFont font;
font.setPointSize(10);
font.setBold(true);
@ -71,8 +69,6 @@ WaitingDialog::WaitingDialog(QWidget *parent, shared_ptr<pv::device::DevInst> de
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(changeText()));
QString styleSheet = "* {color: rgb(255, 255, 255); background-color: rgb(17, 133, 209);} *:hover {background-color: rgb(238, 178, 17);}";
_button_box.setStyleSheet(styleSheet);
_button_box.setGeometry(width()-_button_box.width()-30, height()-_button_box.height()-15,
_button_box.width(), _button_box.height());
connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept()));

View File

@ -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()

View File

@ -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;

View File

@ -369,11 +369,12 @@ void TriggerDock::device_change()
if (stream ||
strcmp(_session.get_device()->dev_inst()->driver->name, "DSLogic") != 0) {
position_spinBox->setDisabled(true);
position_slider->setDisabled(true);
const int maxRange = SR_MB(11)*100/_session.get_device()->get_sample_limit();
position_spinBox->setRange(0, maxRange);
position_slider->setRange(0, maxRange);
} else {
position_spinBox->setDisabled(false);
position_slider->setDisabled(false);
position_spinBox->setRange(0, 99);
position_slider->setRange(0, 99);
}
}

View File

@ -180,7 +180,7 @@ void MainWindow::setup_ui()
connect(_sampling_bar, SIGNAL(device_selected()), this,
SLOT(update_device_list()));
connect(_sampling_bar, SIGNAL(device_updated()), &_session,
connect(_sampling_bar, SIGNAL(device_updated()), this,
SLOT(reload()));
connect(_sampling_bar, SIGNAL(run_stop()), this,
SLOT(run_stop()));
@ -225,8 +225,7 @@ void MainWindow::setup_ui()
// Set the title
QString title = QApplication::applicationName()+" v"+QApplication::applicationVersion();
std::string std_title = title.toStdString();
setWindowTitle(QApplication::translate("MainWindow", std_title.c_str(), 0,
QApplication::UnicodeUTF8));
setWindowTitle(QApplication::translate("MainWindow", std_title.c_str(), 0));
// Setup _session events
connect(&_session, SIGNAL(capture_state_changed(int)), this,
@ -244,8 +243,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()));
@ -320,6 +317,12 @@ void MainWindow::update_device_list()
_logo_bar->dsl_connected(false);
}
void MainWindow::reload()
{
_trigger_widget->device_change();
_session.reload();
}
void MainWindow::load_file(QString file_name)
{
try {
@ -522,7 +525,7 @@ void MainWindow::on_screenShot()
tr("%1 Files (*.%2);;All Files (*)")
.arg(format.toUpper()).arg(format));
if (!fileName.isEmpty())
pixmap.save(fileName, format.toAscii());
pixmap.save(fileName, format.toLatin1());
}
void MainWindow::on_save()

View File

@ -90,6 +90,8 @@ private slots:
*/
void update_device_list();
void reload();
void show_session_error(
const QString text, const QString info_text);

View File

@ -90,6 +90,7 @@ DeviceOptions::DeviceOptions(struct sr_dev_inst *sdi) :
case SR_CONF_STREAM:
case SR_CONF_TEST:
case SR_CONF_STATUS:
case SR_CONF_FACTOR:
bind_enum(name, key, gvar_list);
break;

View File

@ -54,21 +54,27 @@
#include <QDebug>
#include <QMessageBox>
#include <QProgressDialog>
#include <QFile>
#include <QtConcurrent/QtConcurrent>
#include <boost/foreach.hpp>
using boost::dynamic_pointer_cast;
using boost::function;
using boost::lock_guard;
using boost::mutex;
using boost::shared_ptr;
using std::list;
using std::map;
using std::set;
using std::string;
using std::vector;
using std::deque;
using std::min;
//using boost::dynamic_pointer_cast;
//using boost::function;
//using boost::lock_guard;
//using boost::mutex;
//using boost::shared_ptr;
//using std::list;
//using std::map;
//using std::set;
//using std::string;
//using std::vector;
//using std::deque;
//using std::min;
using namespace boost;
using namespace std;
namespace pv {
@ -97,10 +103,6 @@ SigSession::SigSession(DeviceManager &device_manager) :
SigSession::~SigSession()
{
stop_capture();
if (_hotplug_handle) {
stop_hotplug_proc();
deregister_hotplug_callback();
}
ds_trigger_destroy();
@ -108,6 +110,11 @@ SigSession::~SigSession()
// TODO: This should not be necessary
_session = NULL;
if (_hotplug_handle) {
stop_hotplug_proc();
deregister_hotplug_callback();
}
}
boost::shared_ptr<device::DevInst> SigSession::get_device() const
@ -115,7 +122,7 @@ boost::shared_ptr<device::DevInst> SigSession::get_device() const
return _dev_inst;
}
void SigSession::set_device(shared_ptr<device::DevInst> dev_inst) throw(QString)
void SigSession::set_device(boost::shared_ptr<device::DevInst> dev_inst) throw(QString)
{
using pv::device::Device;
@ -151,13 +158,13 @@ void SigSession::set_file(const string &name) throw(QString)
// Deslect the old device, because file type detection in File::create
// destorys the old session inside libsigrok.
try {
set_device(shared_ptr<device::DevInst>());
set_device(boost::shared_ptr<device::DevInst>());
} catch(const QString e) {
throw(e);
return;
}
try {
set_device(shared_ptr<device::DevInst>(device::File::create(name)));
set_device(boost::shared_ptr<device::DevInst>(device::File::create(name)));
} catch(const QString e) {
throw(e);
return;
@ -179,10 +186,168 @@ void SigSession::save_file(const std::string &name){
snapshot->get_sample_count());
}
QList<QString> SigSession::getSuportedExportFormats(){
const struct sr_output_module** supportedModules = sr_output_list();
QList<QString> list;
while(*supportedModules){
if(*supportedModules == NULL)
break;
if (_dev_inst->dev_inst()->mode == DSO && strcmp((*supportedModules)->id, "csv"))
break;
QString format((*supportedModules)->desc);
format.append(" (*.");
format.append((*supportedModules)->id);
format.append(")");
list.append(format);
*supportedModules++;
}
return list;
}
void SigSession::cancelSaveFile(){
saveFileThreadRunning = false;
}
void SigSession::export_file(const std::string &name, QWidget* parent, const std::string &ext){
boost::shared_ptr<pv::data::Snapshot> snapshot;
int channel_type;
if (_dev_inst->dev_inst()->mode == LOGIC) {
const deque< boost::shared_ptr<pv::data::LogicSnapshot> > &snapshots =
_logic_data->get_snapshots();
if(snapshots.empty())
return;
snapshot = snapshots.front();
channel_type = SR_CHANNEL_LOGIC;
} else if (_dev_inst->dev_inst()->mode == DSO) {
const deque< boost::shared_ptr<pv::data::DsoSnapshot> > &snapshots =
_dso_data->get_snapshots();
if(snapshots.empty())
return;
snapshot = snapshots.front();
channel_type = SR_CHANNEL_DSO;
} else {
return;
}
const struct sr_output_module** supportedModules = sr_output_list();
const struct sr_output_module* outModule = NULL;
while(*supportedModules){
if(*supportedModules == NULL)
break;
if(!strcmp((*supportedModules)->id, ext.c_str())){
outModule = *supportedModules;
break;
}
*supportedModules++;
}
if(outModule == NULL)
return;
GHashTable *params = g_hash_table_new(g_str_hash, g_str_equal);
GVariant* filenameGVariant = g_variant_new_string(name.c_str());
g_hash_table_insert(params, (char*)"filename", filenameGVariant);
GVariant* typeGVariant = g_variant_new_int16(channel_type);
g_hash_table_insert(params, (char*)"type", typeGVariant);
BOOST_FOREACH(const boost::shared_ptr<view::Signal> s, _signals) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)) {
GVariant* timebaseGVariant = g_variant_new_uint64(dsoSig->get_hDialValue());
g_hash_table_insert(params, (char*)"timebase", timebaseGVariant);
break;
}
}
struct sr_output output;
output.module = (sr_output_module*) outModule;
output.sdi = _dev_inst->dev_inst();
output.param = NULL;
if(outModule->init)
outModule->init(&output, params);
QFile file(name.c_str());
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
QFuture<void> future;
if (_dev_inst->dev_inst()->mode == LOGIC) {
future = QtConcurrent::run([&]{
saveFileThreadRunning = true;
unsigned char* datat = (unsigned char*)snapshot->get_data();
unsigned int numsamples = snapshot->get_sample_count()*snapshot->unit_size();
GString *data_out;
int usize = 8192;
int size = usize;
struct sr_datafeed_logic lp;
struct sr_datafeed_packet p;
for(uint64_t i = 0; i < numsamples; i+=usize){
if(numsamples - i < usize)
size = numsamples - i;
lp.data = &datat[i];
lp.length = size;
lp.unitsize = snapshot->unit_size();
p.type = SR_DF_LOGIC;
p.payload = &lp;
outModule->receive(&output, &p, &data_out);
if(data_out){
out << (char*) data_out->str;
g_string_free(data_out,TRUE);
}
emit progressSaveFileValueChanged(i*100/numsamples);
if(!saveFileThreadRunning)
break;
}
});
} else if (_dev_inst->dev_inst()->mode == DSO) {
future = QtConcurrent::run([&]{
saveFileThreadRunning = true;
unsigned char* datat = (unsigned char*)snapshot->get_data();
unsigned int numsamples = snapshot->get_sample_count();
GString *data_out;
int usize = 8192;
int size = usize;
struct sr_datafeed_dso dp;
struct sr_datafeed_packet p;
for(uint64_t i = 0; i < numsamples; i+=usize){
if(numsamples - i < usize)
size = numsamples - i;
dp.data = &datat[i*snapshot->get_channel_num()];
dp.num_samples = size;
p.type = SR_DF_DSO;
p.payload = &dp;
outModule->receive(&output, &p, &data_out);
if(data_out){
out << (char*) data_out->str;
g_string_free(data_out,TRUE);
}
emit progressSaveFileValueChanged(i*100/numsamples);
if(!saveFileThreadRunning)
break;
}
});
}
QFutureWatcher<void> watcher;
Qt::WindowFlags flags = Qt::CustomizeWindowHint;
QProgressDialog dlg(QString::fromUtf8("Exporting data... It can take a while."),
QString::fromUtf8("Cancel"),0,100,parent,flags);
dlg.setWindowModality(Qt::WindowModal);
watcher.setFuture(future);
connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel()));
connect(this,SIGNAL(progressSaveFileValueChanged(int)),&dlg,SLOT(setValue(int)));
connect(&dlg,SIGNAL(canceled()),this,SLOT(cancelSaveFile()));
dlg.exec();
future.waitForFinished();
// optional, as QFile destructor will already do it:
file.close();
outModule->cleanup(&output);
g_hash_table_destroy(params);
g_variant_unref(filenameGVariant);
}
void SigSession::set_default_device(boost::function<void (const QString)> error_handler)
{
shared_ptr<pv::device::DevInst> default_device;
const list< shared_ptr<device::DevInst> > &devices =
boost::shared_ptr<pv::device::DevInst> default_device;
const list<boost::shared_ptr<device::DevInst> > &devices =
_device_manager.devices();
if (!devices.empty()) {
@ -190,7 +355,7 @@ void SigSession::set_default_device(boost::function<void (const QString)> error_
default_device = devices.front();
// Try and find the DreamSourceLab device and select that by default
BOOST_FOREACH (shared_ptr<pv::device::DevInst> dev, devices)
BOOST_FOREACH (boost::shared_ptr<pv::device::DevInst> dev, devices)
if (dev->dev_inst() &&
strcmp(dev->dev_inst()->driver->name,
"demo") != 0) {
@ -212,7 +377,7 @@ void SigSession::release_device(device::DevInst *dev_inst)
assert(_dev_inst.get() == dev_inst);
assert(_capture_state != Running);
_dev_inst = shared_ptr<device::DevInst>();
_dev_inst = boost::shared_ptr<device::DevInst>();
//_dev_inst.reset();
}
@ -286,11 +451,11 @@ vector< boost::shared_ptr<view::GroupSignal> > SigSession::get_group_signals()
return _group_traces;
}
set< shared_ptr<data::SignalData> > SigSession::get_data() const
set< boost::shared_ptr<data::SignalData> > SigSession::get_data() const
{
lock_guard<mutex> lock(_signals_mutex);
set< shared_ptr<data::SignalData> > data;
BOOST_FOREACH(const shared_ptr<view::Signal> sig, _signals) {
set< boost::shared_ptr<data::SignalData> > data;
BOOST_FOREACH(const boost::shared_ptr<view::Signal> sig, _signals) {
assert(sig);
data.insert(sig->data());
}
@ -352,7 +517,7 @@ void SigSession::set_capture_state(capture_state state)
capture_state_changed(state);
}
void SigSession::sample_thread_proc(shared_ptr<device::DevInst> dev_inst,
void SigSession::sample_thread_proc(boost::shared_ptr<device::DevInst> dev_inst,
boost::function<void (const QString)> error_handler)
{
assert(dev_inst);
@ -416,8 +581,8 @@ void SigSession::read_sample_rate(const sr_dev_inst *const sdi)
}
// Set the sample rate of all data
const set< shared_ptr<data::SignalData> > data_set = get_data();
BOOST_FOREACH(shared_ptr<data::SignalData> data, data_set) {
const set< boost::shared_ptr<data::SignalData> > data_set = get_data();
BOOST_FOREACH(boost::shared_ptr<data::SignalData> data, data_set) {
assert(data);
data->set_samplerate(sample_rate);
}
@ -502,6 +667,7 @@ void SigSession::init_signals()
assert(_dev_inst);
stop_capture();
vector< boost::shared_ptr<view::Signal> > sigs;
boost::shared_ptr<view::Signal> signal;
unsigned int logic_probe_count = 0;
unsigned int dso_probe_count = 0;
@ -561,8 +727,6 @@ void SigSession::init_signals()
// Make the logic probe list
{
_signals.clear();
for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) {
const sr_channel *const probe =
(const sr_channel *)l->data;
@ -576,19 +740,24 @@ void SigSession::init_signals()
break;
case SR_CHANNEL_DSO:
signal = shared_ptr<view::Signal>(
signal = boost::shared_ptr<view::Signal>(
new view::DsoSignal(_dev_inst, _dso_data, probe));
break;
case SR_CHANNEL_ANALOG:
if (probe->enabled)
signal = shared_ptr<view::Signal>(
signal = boost::shared_ptr<view::Signal>(
new view::AnalogSignal(_dev_inst, _analog_data, probe));
break;
}
if(signal.get())
_signals.push_back(signal);
sigs.push_back(signal);
}
_signals.clear();
vector< boost::shared_ptr<view::Signal> >().swap(_signals);
_signals = sigs;
signals_changed();
data_updated();
}
@ -601,12 +770,11 @@ void SigSession::reload()
if (_capture_state == Running)
stop_capture();
vector< boost::shared_ptr<view::Signal> > sigs;
boost::shared_ptr<view::Signal> signal;
// Make the logic probe list
{
_signals.clear();
for (const GSList *l = _dev_inst->dev_inst()->channels; l; l = l->next) {
const sr_channel *const probe =
(const sr_channel *)l->data;
@ -614,25 +782,32 @@ void SigSession::reload()
signal.reset();
switch(probe->type) {
case SR_CHANNEL_LOGIC:
if (probe->enabled)
if (probe->enabled && probe->index < _signals.size())
signal = boost::shared_ptr<view::Signal>(
new view::LogicSignal(*_signals[probe->index].get(), _logic_data, probe));
else if (probe->enabled)
signal = boost::shared_ptr<view::Signal>(
new view::LogicSignal(_dev_inst, _logic_data, probe));
break;
case SR_CHANNEL_DSO:
signal = shared_ptr<view::Signal>(
signal = boost::shared_ptr<view::Signal>(
new view::DsoSignal(_dev_inst,_dso_data, probe));
break;
case SR_CHANNEL_ANALOG:
if (probe->enabled)
signal = shared_ptr<view::Signal>(
signal = boost::shared_ptr<view::Signal>(
new view::AnalogSignal(_dev_inst, _analog_data, probe));
break;
}
if (signal.get())
_signals.push_back(signal);
sigs.push_back(signal);
}
_signals.clear();
vector< boost::shared_ptr<view::Signal> >().swap(_signals);
_signals = sigs;
}
signals_changed();
@ -718,7 +893,7 @@ void SigSession::feed_in_logic(const sr_datafeed_logic &logic)
return;
}
receive_data(logic.length/logic.unitsize);
emit receive_data(logic.length/logic.unitsize);
data_received();
//data_updated();
}
@ -844,7 +1019,7 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi,
_cur_analog_snapshot.reset();
}
#ifdef ENABLE_DECODE
for (vector< shared_ptr<view::DecodeTrace> >::iterator i =
for (vector< boost::shared_ptr<view::DecodeTrace> >::iterator i =
_decode_traces.begin();
i != _decode_traces.end();
i++)
@ -977,7 +1152,7 @@ uint16_t SigSession::get_ch_num(int type)
uint16_t dso_ch_num = 0;
uint16_t analog_ch_num = 0;
if (_dev_inst->dev_inst()) {
BOOST_FOREACH(const shared_ptr<view::Signal> s, _signals)
BOOST_FOREACH(const boost::shared_ptr<view::Signal> s, _signals)
{
assert(s);
if (dynamic_pointer_cast<view::LogicSignal>(s) && s->enabled()) {
@ -1013,15 +1188,15 @@ uint16_t SigSession::get_ch_num(int type)
bool SigSession::add_decoder(srd_decoder *const dec)
{
bool ret = false;
map<const srd_channel*, shared_ptr<view::LogicSignal> > probes;
shared_ptr<data::DecoderStack> decoder_stack;
map<const srd_channel*, boost::shared_ptr<view::LogicSignal> > probes;
boost::shared_ptr<data::DecoderStack> decoder_stack;
try
{
//lock_guard<mutex> lock(_signals_mutex);
// Create the decoder
decoder_stack = shared_ptr<data::DecoderStack>(
decoder_stack = boost::shared_ptr<data::DecoderStack>(
new data::DecoderStack(*this, dec));
// Make a list of all the probes
@ -1037,7 +1212,7 @@ bool SigSession::add_decoder(srd_decoder *const dec)
decoder_stack->stack().front()->set_probes(probes);
// Create the decode signal
shared_ptr<view::DecodeTrace> d(
boost::shared_ptr<view::DecodeTrace> d(
new view::DecodeTrace(*this, decoder_stack,
_decode_traces.size()));
if (d->create_popup()) {
@ -1060,7 +1235,7 @@ bool SigSession::add_decoder(srd_decoder *const dec)
return ret;
}
vector< shared_ptr<view::DecodeTrace> > SigSession::get_decode_signals() const
vector< boost::shared_ptr<view::DecodeTrace> > SigSession::get_decode_signals() const
{
lock_guard<mutex> lock(_signals_mutex);
return _decode_traces;
@ -1068,7 +1243,7 @@ vector< shared_ptr<view::DecodeTrace> > SigSession::get_decode_signals() const
void SigSession::remove_decode_signal(view::DecodeTrace *signal)
{
for (vector< shared_ptr<view::DecodeTrace> >::iterator i =
for (vector< boost::shared_ptr<view::DecodeTrace> >::iterator i =
_decode_traces.begin();
i != _decode_traces.end();
i++)
@ -1083,7 +1258,7 @@ void SigSession::remove_decode_signal(view::DecodeTrace *signal)
void SigSession::remove_decode_signal(int index)
{
int cur_index = 0;
for (vector< shared_ptr<view::DecodeTrace> >::iterator i =
for (vector< boost::shared_ptr<view::DecodeTrace> >::iterator i =
_decode_traces.begin();
i != _decode_traces.end();
i++)
@ -1101,7 +1276,7 @@ void SigSession::remove_decode_signal(int index)
void SigSession::rst_decoder(int index)
{
int cur_index = 0;
for (vector< shared_ptr<view::DecodeTrace> >::iterator i =
for (vector< boost::shared_ptr<view::DecodeTrace> >::iterator i =
_decode_traces.begin();
i != _decode_traces.end();
i++)
@ -1122,7 +1297,7 @@ void SigSession::rst_decoder(int index)
void SigSession::rst_decoder(view::DecodeTrace *signal)
{
for (vector< shared_ptr<view::DecodeTrace> >::iterator i =
for (vector< boost::shared_ptr<view::DecodeTrace> >::iterator i =
_decode_traces.begin();
i != _decode_traces.end();
i++)

View File

@ -35,6 +35,7 @@
#include <set>
#include <string>
#include <vector>
#include <stdint.h>
#include <QObject>
#include <QString>
@ -43,6 +44,7 @@
#include <QMap>
#include <QVariant>
#include <QTimer>
#include <QtConcurrent/QtConcurrent>
#include <libsigrok4DSL/libsigrok.h>
#include <libusb.h>
@ -86,8 +88,9 @@ class SigSession : public QObject
Q_OBJECT
private:
static const float Oversampling = 2.0f;
static constexpr float Oversampling = 2.0f;
static const int ViewTime = 800;
bool saveFileThreadRunning = false;
public:
enum capture_state {
@ -115,6 +118,9 @@ public:
void save_file(const std::string &name);
void set_default_device(boost::function<void (const QString)> error_handler);
void export_file(const std::string &name, QWidget* parent, const std::string &ext);
void set_default_device();
void release_device(device::DevInst *dev_inst);
@ -132,6 +138,7 @@ public:
std::vector< boost::shared_ptr<view::GroupSignal> >
get_group_signals();
QList<QString> getSuportedExportFormats();
#ifdef ENABLE_DECODE
bool add_decoder(srd_decoder *const dec);
@ -282,11 +289,15 @@ signals:
void malloc_error();
void zero_adj();
void progressSaveFileValueChanged(int percent);
public slots:
void reload();
void refresh();
private slots:
void cancelSaveFile();
private:
// TODO: This should not be necessary. Multiple concurrent
// sessions should should be supported and it should be

View File

@ -48,7 +48,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) :
_action_open = new QAction(this);
_action_open->setText(QApplication::translate(
"File", "&Open...", 0, QApplication::UnicodeUTF8));
"File", "&Open...", 0));
_action_open->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/open.png")));
_action_open->setObjectName(QString::fromUtf8("actionOpen"));
@ -57,16 +57,24 @@ FileBar::FileBar(SigSession &session, QWidget *parent) :
_action_save = new QAction(this);
_action_save->setText(QApplication::translate(
"File", "&Save...", 0, QApplication::UnicodeUTF8));
"File", "&Save...", 0));
_action_save->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/save.png")));
_action_save->setObjectName(QString::fromUtf8("actionSave"));
_file_button.addAction(_action_save);
connect(_action_save, SIGNAL(triggered()), this, SLOT(on_actionSave_triggered()));
_action_export = new QAction(this);
_action_export->setText(QApplication::translate("File", "&Export...", 0));
_action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/instant.png")));
_action_export->setObjectName(QString::fromUtf8("actionExport"));
_file_button.addAction(_action_export);
connect(_action_export, SIGNAL(triggered()), this, SLOT(on_actionExport_triggered()));
_action_capture = new QAction(this);
_action_capture->setText(QApplication::translate(
"File", "&Capture...", 0, QApplication::UnicodeUTF8));
"File", "&Capture...", 0));
_action_capture->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/capture.png")));
_action_capture->setObjectName(QString::fromUtf8("actionCapture"));
@ -84,7 +92,7 @@ void FileBar::on_actionOpen_triggered()
// Show the dialog
const QString file_name = QFileDialog::getOpenFileName(
this, tr("Open File"), "", tr(
"DSView Sessions (*.dsl)"));
"DSView Sessions (*.dsl);;All Files (*.*)"));
if (!file_name.isEmpty())
load_file(file_name);
}
@ -108,6 +116,38 @@ void FileBar::show_session_error(
msg.exec();
}
void FileBar::on_actionExport_triggered(){
int unit_size;
uint64_t length;
void* buf = _session.get_buf(unit_size, length);
if (!buf) {
QMessageBox msg(this);
msg.setText("Data Export");
msg.setInformativeText("No Data to Save!");
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
} else {
QList<QString> supportedFormats = _session.getSuportedExportFormats();
QString filter;
for(int i = 0; i < supportedFormats.count();i++){
filter.append(supportedFormats[i]);
if(i < supportedFormats.count() - 1)
filter.append(";;");
}
QString file_name = QFileDialog::getSaveFileName(
this, tr("Export Data"), "",filter,&filter);
if (!file_name.isEmpty()) {
QFileInfo f(file_name);
QStringList list = filter.split('.').last().split(')');
QString ext = list.first();
if(f.suffix().compare(ext))
file_name+=tr(".")+ext;
_session.export_file(file_name.toStdString(), this, ext.toStdString());
}
}
}
void FileBar::on_actionSave_triggered()
{
//save();
@ -129,10 +169,13 @@ void FileBar::on_actionSave_triggered()
msg.setIcon(QMessageBox::Warning);
msg.exec();
}else {
const QString file_name = QFileDialog::getSaveFileName(
QString file_name = QFileDialog::getSaveFileName(
this, tr("Save File"), "",
tr("DSView Session (*.dsl)"));
if (!file_name.isEmpty()) {
QFileInfo f(file_name);
if(f.suffix().compare("dsl"))
file_name.append(tr(".dsl"));
_session.save_file(file_name.toStdString());
}
}

View File

@ -58,6 +58,7 @@ private slots:
void on_actionOpen_triggered();
void on_actionSave_triggered();
void on_actionCapture_triggered();
void on_actionExport_triggered();
private:
bool _enable;
@ -67,6 +68,7 @@ private:
QAction *_action_open;
QAction *_action_save;
QAction *_action_export;
QAction *_action_capture;
};

View File

@ -47,7 +47,7 @@ LogoBar::LogoBar(SigSession &session, QWidget *parent) :
_about = new QAction(this);
_about->setText(QApplication::translate(
"File", "&About...", 0, QApplication::UnicodeUTF8));
"File", "&About...", 0));
_about->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/about.png")));
_about->setObjectName(QString::fromUtf8("actionAbout"));
@ -56,7 +56,7 @@ LogoBar::LogoBar(SigSession &session, QWidget *parent) :
_wiki = new QAction(this);
_wiki->setText(QApplication::translate(
"File", "&Wiki", 0, QApplication::UnicodeUTF8));
"File", "&Wiki", 0));
_wiki->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/wiki.png")));
_wiki->setObjectName(QString::fromUtf8("actionWiki"));

View File

@ -667,19 +667,21 @@ void SamplingBar::on_run_stop()
const shared_ptr<device::DevInst> dev_inst = get_selected_device();
if (!dev_inst)
return;
GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO);
if (gvar != NULL) {
bool zero = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (zero) {
QMessageBox msg(this);
msg.setText("Zero Adjustment");
msg.setInformativeText("Please adjust zero skew and save the result!");
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
zero_adj();
return;
if (dev_inst->dev_inst()->mode == DSO) {
GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO);
if (gvar != NULL) {
bool zero = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (zero) {
QMessageBox msg(this);
msg.setText("Zero Adjustment");
msg.setInformativeText("Please adjust zero skew and save the result!");
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
zero_adj();
return;
}
}
}
run_stop();
@ -695,22 +697,24 @@ void SamplingBar::on_instant_stop()
const shared_ptr<device::DevInst> dev_inst = get_selected_device();
if (!dev_inst)
return;
GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO);
if (gvar != NULL) {
bool zero = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (zero) {
QMessageBox msg(this);
msg.setText("Zero Adjustment");
if(strcmp(dev_inst->dev_inst()->driver->name, "DSLogic") == 0)
msg.setInformativeText("Please adjust zero skew and save the result!\nPlease left both of channels unconnect for zero adjustment!");
else
msg.setInformativeText("Please adjust zero skew and save the result!");
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
zero_adj();
return;
if (dev_inst->dev_inst()->mode == DSO) {
GVariant* gvar = dev_inst->get_config(NULL, NULL, SR_CONF_ZERO);
if (gvar != NULL) {
bool zero = g_variant_get_boolean(gvar);
g_variant_unref(gvar);
if (zero) {
QMessageBox msg(this);
msg.setText("Zero Adjustment");
if(strcmp(dev_inst->dev_inst()->driver->name, "DSLogic") == 0)
msg.setInformativeText("Please adjust zero skew and save the result!\nPlease left both of channels unconnect for zero adjustment!");
else
msg.setInformativeText("Please adjust zero skew and save the result!");
msg.setStandardButtons(QMessageBox::Ok);
msg.setIcon(QMessageBox::Warning);
msg.exec();
zero_adj();
return;
}
}
}
instant_stop();

View File

@ -65,7 +65,7 @@ AnalogSignal::~AnalogSignal()
{
}
shared_ptr<pv::data::SignalData> AnalogSignal::data() const
boost::shared_ptr<pv::data::SignalData> AnalogSignal::data() const
{
return _data;
}
@ -86,7 +86,7 @@ void AnalogSignal::paint_mid(QPainter &p, int left, int right)
assert(scale > 0);
const double offset = _view->offset();
const deque< shared_ptr<pv::data::AnalogSnapshot> > &snapshots =
const deque< boost::shared_ptr<pv::data::AnalogSnapshot> > &snapshots =
_data->get_snapshots();
if (snapshots.empty())
return;

View File

@ -25,6 +25,7 @@
#include "ruler.h"
#include "view.h"
#include "../device/device.h"
#include <QBrush>
#include <QPainter>
@ -51,15 +52,16 @@ 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)
{
}
QRectF Cursor::get_label_rect(const QRect &rect) const
{
const float x = (_time - _view.offset()) / _view.scale();
const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale();
const double x = _index/samples_per_pixel - (_view.offset() / _view.scale());
const QSizeF label_size(
_text_size.width() + View::LabelPadding.width() * 2,
@ -114,7 +116,7 @@ void Cursor::paint_label(QPainter &p, const QRect &rect,
p.drawLine(close.left() + 2, close.bottom() - 2, close.right() - 2, close.top() + 2);
p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter,
Ruler::format_time(_time, prefix, 2));
Ruler::format_real_time(_index, _view.session().get_device()->get_sample_rate()));
const QRectF arrowRect = QRectF(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize);
p.drawText(arrowRect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(index));
@ -141,7 +143,7 @@ void Cursor::paint_fix_label(QPainter &p, const QRect &rect,
p.setPen(Qt::white);
p.drawText(r, Qt::AlignCenter | Qt::AlignVCenter,
Ruler::format_time(_time, prefix, 2));
Ruler::format_real_time(_index, _view.session().get_device()->get_sample_rate()));
const QRectF arrowRect = QRectF(r.bottomLeft().x(), r.bottomLeft().y(), r.width(), ArrowSize);
p.drawText(arrowRect, Qt::AlignCenter | Qt::AlignVCenter, label);
@ -150,7 +152,7 @@ void Cursor::paint_fix_label(QPainter &p, const QRect &rect,
void Cursor::compute_text_size(QPainter &p, unsigned int prefix)
{
_text_size = p.boundingRect(QRectF(), 0,
Ruler::format_time(_time, prefix, 2)).size();
Ruler::format_real_time(_index, _view.session().get_device()->get_sample_rate())).size();
}
} // namespace view

View File

@ -55,7 +55,8 @@ 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, uint64_t index);
public:
/**

View File

@ -117,10 +117,12 @@ const QColor DecodeTrace::OutlineColours[16] = {
DecodeTrace::DecodeTrace(pv::SigSession &session,
boost::shared_ptr<pv::data::DecoderStack> decoder_stack, int index) :
Trace(QString::fromUtf8(
decoder_stack->stack().front()->decoder()->name), Trace::DS_DECODER),
decoder_stack->stack().front()->decoder()->name), index, Trace::DS_DECODER),
_session(session),
_decoder_stack(decoder_stack),
_show_hide_mapper(this)
_show_hide_mapper(this),
_popup_form(NULL),
_popup()
{
assert(_decoder_stack);
@ -297,21 +299,11 @@ void DecodeTrace::paint_fore(QPainter &p, int left, int right)
bool DecodeTrace::create_popup()
{
// Clear the layout
// Transfer the layout and the child widgets to a temporary widget
// which then goes out of scope destroying the layout and all the child
// widgets.
//if (_popup_form)
// QWidget().setLayout(_popup_form);
int ret = false;
QDialog popup;
QFormLayout popup_form;
popup.setLayout(&popup_form);
populate_popup_form(&popup, &popup_form);
_popup = new QDialog();
create_popup_form();
if (QDialog::Accepted == popup.exec())
if (QDialog::Accepted == _popup->exec())
{
BOOST_FOREACH(shared_ptr<data::decode::Decoder> dec,
_decoder_stack->stack())
@ -321,12 +313,28 @@ bool DecodeTrace::create_popup()
ret = true;
}
}
return ret;
}
else
return false;
_popup = NULL;
_popup_form = NULL;
return ret;
}
void DecodeTrace::create_popup_form()
{
// Clear the layout
// Transfer the layout and the child widgets to a temporary widget
// which then goes out of scope destroying the layout and all the child
// widgets.
if (_popup_form)
QWidget().setLayout(_popup_form);
_popup_form = new QFormLayout(_popup);
_popup->setLayout(_popup_form);
populate_popup_form(_popup, _popup_form);
}
void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form)
{
@ -368,8 +376,8 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form)
new pv::widgets::DecoderMenu(parent);
connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)),
this, SLOT(on_stack_decoder(srd_decoder*)));
connect(decoder_menu, SIGNAL(selected()),
parent, SLOT(accept()));
//connect(decoder_menu, SIGNAL(selected()),
// parent, SLOT(accept()));
QPushButton *const stack_button =
new QPushButton(tr("Stack Decoder"), parent);
@ -547,7 +555,8 @@ bool DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left,
shared_ptr<Logic> data;
shared_ptr<LogicSignal> logic_signal;
const int64_t sample_count = _session.get_device()->get_sample_limit();
//const int64_t sample_count = _session.get_device()->get_sample_limit();
const int64_t sample_count = _decoder_stack->sample_count();
if (sample_count == 0)
return true;
@ -768,7 +777,7 @@ void DecodeTrace::on_stack_decoder(srd_decoder *decoder)
new data::decode::Decoder(decoder)));
//_decoder_stack->begin_decode();
create_popup();
create_popup_form();
}
void DecodeTrace::on_show_hide_decoder(int index)

View File

@ -128,6 +128,8 @@ protected:
void paint_type_options(QPainter &p, int right, bool hover, int action);
private:
void create_popup_form();
void populate_popup_form(QWidget *parent, QFormLayout *form);
void draw_annotation(const pv::data::decode::Annotation &a, QPainter &p,
@ -196,6 +198,8 @@ private:
std::vector<QString> _cur_row_headings;
QSignalMapper _show_hide_mapper;
QFormLayout *_popup_form;
QDialog *_popup;
};
} // namespace view

View File

@ -68,7 +68,7 @@ void DevMode::set_device()
l; l = l->next) {
sr_dev_mode *mode = (sr_dev_mode *)l->data;
shared_ptr<QPushButton> mode_button = shared_ptr<QPushButton>(new QPushButton(NULL));
boost::shared_ptr<QPushButton> mode_button = boost::shared_ptr<QPushButton>(new QPushButton(NULL));
mode_button->setFlat(true);
mode_button->setText(mode->name);
@ -97,7 +97,7 @@ void DevMode::paintEvent(QPaintEvent*)
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
for(std::map<shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
for(std::map<boost::shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
i != _mode_button_list.end(); i++) {
const boost::shared_ptr<device::DevInst> dev_inst = _view.session().get_device();
assert(dev_inst);
@ -118,7 +118,7 @@ void DevMode::on_mode_change()
assert(dev_inst);
QPushButton *button = qobject_cast<QPushButton *>(sender());
for(std::map<shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
for(std::map<boost::shared_ptr<QPushButton>, sr_dev_mode *>::const_iterator i = _mode_button_list.begin();
i != _mode_button_list.end(); i++) {
if ((*i).first.get() == button) {
if (dev_inst->dev_inst()->mode != (*i).second->mode) {

View File

@ -5,12 +5,12 @@
namespace pv {
namespace view {
dslDial::dslDial(const quint64 div, const quint64 step,
const QVector<quint64> value, const QVector<QString> unit)
dslDial::dslDial(const uint64_t div, const uint64_t step,
const QVector<uint64_t> value, const QVector<QString> unit)
{
assert(div > 0);
assert(step > 0);
assert((quint64)value.count() == div);
assert((uint64_t)value.count() == div);
assert(unit.count() > 0);
_div = div;
@ -18,6 +18,7 @@ dslDial::dslDial(const quint64 div, const quint64 step,
_value = value;
_unit = unit;
_sel = 0;
_factor = 1;
}
dslDial::~dslDial()
@ -39,11 +40,11 @@ void dslDial::paint(QPainter &p, QRectF dialRect, QColor dialColor)
p.save();
p.translate(dialRect.center());
p.rotate(45);
for (quint64 i = 0; i < _div; i++) {
for (uint64_t i = 0; i < _div; i++) {
// draw major ticks
p.drawLine(0, dialRect.width()/2+3, 0, dialRect.width()/2+8);
// draw minor ticks
for (quint64 j = 0; (j < 5) && (i < _div - 1); j++) {
for (uint64_t j = 0; (j < 5) && (i < _div - 1); j++) {
p.drawLine(0, dialRect.width()/2+3, 0, dialRect.width()/2+5);
p.rotate(54.0/(_div-1));
}
@ -55,8 +56,8 @@ void dslDial::paint(QPainter &p, QRectF dialRect, QColor dialColor)
p.drawLine(-3, 0, 0, dialRect.width()/2-3);
p.restore();
// draw value
quint64 displayValue = _value[_sel];
quint64 displayIndex = 0;
uint64_t displayValue = _value[_sel]*_factor;
uint64_t displayIndex = 0;
while(displayValue / _step >= 1) {
displayValue = displayValue / _step;
displayIndex++;
@ -67,14 +68,14 @@ void dslDial::paint(QPainter &p, QRectF dialRect, QColor dialColor)
}
void dslDial::set_sel(quint64 sel)
void dslDial::set_sel(uint64_t sel)
{
assert(sel < _div);
_sel = sel;
}
quint64 dslDial::get_sel()
uint64_t dslDial::get_sel()
{
return _sel;
}
@ -95,16 +96,28 @@ bool dslDial::isMax()
return false;
}
quint64 dslDial::get_value()
uint64_t dslDial::get_value()
{
return _value[_sel];
}
bool dslDial::set_value(quint64 value)
bool dslDial::set_value(uint64_t value)
{
assert(_value.contains(value));
_sel = _value.indexOf(value, 0);
}
void dslDial::set_factor(uint64_t factor)
{
if (_factor != factor) {
_factor = factor;
}
}
uint64_t dslDial::get_factor()
{
return _factor;
}
} // namespace view
} // namespace pv

View File

@ -10,8 +10,8 @@ namespace view {
class dslDial
{
public:
dslDial(const quint64 div, const quint64 step,
const QVector<quint64> value, const QVector<QString> unit);
dslDial(const uint64_t div, const uint64_t step,
const QVector<uint64_t> value, const QVector<QString> unit);
virtual ~dslDial();
public:
@ -23,23 +23,28 @@ public:
void paint(QPainter &p, QRectF dialRect, QColor dialColor);
// set/get current select
void set_sel(quint64 sel);
quint64 get_sel();
void set_sel(uint64_t sel);
uint64_t get_sel();
// boundary detection
bool isMin();
bool isMax();
// get current value
quint64 get_value();
bool set_value(quint64 value);
uint64_t get_value();
bool set_value(uint64_t value);
// set/get factor
void set_factor(uint64_t factor);
uint64_t get_factor();
private:
quint64 _div;
quint64 _step;
QVector<quint64> _value;
uint64_t _div;
uint64_t _step;
QVector<uint64_t> _value;
QVector<QString> _unit;
quint64 _sel;
uint64_t _sel;
uint64_t _factor;
};
} // namespace view

View File

@ -103,13 +103,14 @@ const QColor DsoSignal::SignalColours[4] = {
};
const float DsoSignal::EnvelopeThreshold = 256.0f;
const double DsoSignal::TrigMargin = 0.02;
const int DsoSignal::UpMargin = 30;
const int DsoSignal::DownMargin = 30;
const int DsoSignal::RightMargin = 30;
DsoSignal::DsoSignal(boost::shared_ptr<pv::device::DevInst> dev_inst,
shared_ptr<data::Dso> data,
boost::shared_ptr<data::Dso> data,
const sr_channel * const probe):
Signal(dev_inst, probe, DS_DSO),
_data(data),
@ -120,21 +121,26 @@ DsoSignal::DsoSignal(boost::shared_ptr<pv::device::DevInst> dev_inst,
//_zeroPos(probe->index * 0.5 + 0.25)
_trig_vpos(0.5),
_zeroPos(0.5),
_zero_off(255/2.0),
_autoV(false),
_autoH(false)
_autoH(false),
_hover_en(false),
_hover_index(0),
_hover_point(QPointF(0, 0)),
_hover_value(0)
{
QVector<quint64> vValue;
QVector<uint64_t> vValue;
QVector<QString> vUnit;
QVector<quint64> hValue;
QVector<uint64_t> hValue;
QVector<QString> hUnit;
for(quint64 i = 0; i < vDialValueCount; i++)
for(uint64_t i = 0; i < vDialValueCount; i++)
vValue.append(vDialValue[i]);
for(quint64 i = 0; i < vDialUnitCount; i++)
for(uint64_t i = 0; i < vDialUnitCount; i++)
vUnit.append(vDialUnit[i]);
for(quint64 i = 0; i < hDialValueCount; i++)
for(uint64_t i = 0; i < hDialValueCount; i++)
hValue.append(hDialValue[i]);
for(quint64 i = 0; i < hDialUnitCount; i++)
for(uint64_t i = 0; i < hDialUnitCount; i++)
hUnit.append(hDialUnit[i]);
_vDial = new dslDial(vDialValueCount, vDialValueStep, vValue, vUnit);
@ -173,7 +179,7 @@ DsoSignal::~DsoSignal()
{
}
shared_ptr<pv::data::SignalData> DsoSignal::data() const
boost::shared_ptr<pv::data::SignalData> DsoSignal::data() const
{
return _data;
}
@ -244,10 +250,15 @@ void DsoSignal::set_vDialActive(bool active)
bool DsoSignal::go_vDialPre()
{
if (enabled() && !_vDial->isMin()) {
const double pre_vdiv = _vDial->get_value();
_vDial->set_sel(_vDial->get_sel() - 1);
_dev_inst->set_config(_probe, NULL, SR_CONF_VDIV,
g_variant_new_uint64(_vDial->get_value()));
if (_view->session().get_capture_state() == SigSession::Stopped)
_scale *= pre_vdiv/_vDial->get_value();
update_zeroPos();
_view->set_need_update(true);
_view->update();
return true;
} else {
_autoV = false;
@ -258,10 +269,15 @@ bool DsoSignal::go_vDialPre()
bool DsoSignal::go_vDialNext()
{
if (enabled() && !_vDial->isMax()) {
const double pre_vdiv = _vDial->get_value();
_vDial->set_sel(_vDial->get_sel() + 1);
_dev_inst->set_config(_probe, NULL, SR_CONF_VDIV,
g_variant_new_uint64(_vDial->get_value()));
if (_view->session().get_capture_state() == SigSession::Stopped)
_scale *= pre_vdiv/_vDial->get_value();
update_zeroPos();
_view->set_need_update(true);
_view->update();
return true;
} else {
_autoV = false;
@ -448,16 +464,16 @@ void DsoSignal::set_trig_vpos(int pos)
assert(_view);
int trig_value;
if (enabled()) {
double delta = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0f / get_view_rect().height();
double delta = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height();
bool isDSCope = (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0);
if (isDSCope) {
_trig_vpos = delta;
_trig_vpos = min(max(delta, 0+TrigMargin), 1-TrigMargin);
trig_value = delta * 255;
} else {
delta = delta - _zeroPos;
delta = min(delta, 0.5);
delta = max(delta, -0.5);
_trig_vpos = _zeroPos + delta;
_trig_vpos = min(max(_zeroPos + delta, 0+TrigMargin), 1-TrigMargin);
trig_value = (delta * 255.0f + 0x80);
}
_dev_inst->set_config(_probe, NULL, SR_CONF_TRIGGER_VALUE,
@ -475,18 +491,41 @@ void DsoSignal::set_zeroPos(int pos)
if (enabled()) {
double delta = _trig_vpos - _zeroPos;
set_trig_vpos(get_trig_vpos() + pos - get_zeroPos());
_zeroPos = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0f / get_view_rect().height();
_trig_vpos = min(max(_zeroPos + delta, 0.0), 1.0);
_zeroPos = min((double)max(pos - UpMargin, 0), get_view_rect().height()) * 1.0 / get_view_rect().height();
_trig_vpos = min(max(_zeroPos + delta, 0+TrigMargin), 1-TrigMargin);
update_zeroPos();
}
}
void DsoSignal::set_factor(uint64_t factor)
{
if (enabled()) {
GVariant* gvar;
uint64_t prefactor = 0;
gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_FACTOR);
if (gvar != NULL) {
prefactor = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
} else {
qDebug() << "ERROR: config_get SR_CONF_FACTOR failed.";
return;
}
if (prefactor != factor) {
_dev_inst->set_config(_probe, NULL, SR_CONF_FACTOR,
g_variant_new_uint64(factor));
_vDial->set_factor(factor);
_view->set_need_update(true);
_view->update();
}
}
}
void DsoSignal::update_zeroPos()
{
if (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0) {
//double vpos_off = (0.5 - _zeroPos) * _vDial->get_value() * DS_CONF_DSO_VDIVS;
double vpos_off = (0.5 - (get_zeroPos() - UpMargin) * 1.0f/get_view_rect().height()) * _vDial->get_value() * DS_CONF_DSO_VDIVS;
double vpos_off = (0.5 - (get_zeroPos() - UpMargin) * 1.0/get_view_rect().height()) * _vDial->get_value() * DS_CONF_DSO_VDIVS;
_dev_inst->set_config(_probe, NULL, SR_CONF_VPOS,
g_variant_new_double(vpos_off));
}
@ -505,7 +544,7 @@ void DsoSignal::paint_back(QPainter &p, int left, int right)
assert(_view);
int i, j;
const int height = _view->viewport()->height() - UpMargin - DownMargin;
const int height = get_view_rect().height();
const int width = right - left;
p.setPen(Qt::NoPen);
@ -517,7 +556,7 @@ void DsoSignal::paint_back(QPainter &p, int left, int right)
const uint64_t sample_len = _dev_inst->get_sample_limit();
const double samplerate = _dev_inst->get_sample_rate();
const double samples_per_pixel = samplerate * _view->scale();
const double shown_rate = min(samples_per_pixel * width * 1.0f / sample_len, 1.0);
const double shown_rate = min(samples_per_pixel * width * 1.0 / sample_len, 1.0);
const double start_time = _data->get_start_time();
const double start = samplerate * (_view->offset() - start_time);
const double shown_offset = min(start / sample_len, 1.0) * width;
@ -538,7 +577,7 @@ void DsoSignal::paint_back(QPainter &p, int left, int right)
QPen pen(Signal::dsFore);
pen.setStyle(Qt::DotLine);
p.setPen(pen);
const double spanY =height * 1.0f / DS_CONF_DSO_VDIVS;
const double spanY =height * 1.0 / DS_CONF_DSO_VDIVS;
for (i = 1; i <= DS_CONF_DSO_VDIVS; i++) {
const double posY = spanY * i + UpMargin;
p.drawLine(left, posY, right, posY);
@ -548,7 +587,7 @@ void DsoSignal::paint_back(QPainter &p, int left, int right)
width / 2.0f + 5, posY - miniSpanY * j);
}
}
const double spanX = width * 1.0f / DS_CONF_DSO_HDIVS;
const double spanX = width * 1.0 / DS_CONF_DSO_HDIVS;
for (i = 1; i <= DS_CONF_DSO_HDIVS; i++) {
const double posX = spanX * i;
p.drawLine(posX, UpMargin,
@ -568,7 +607,7 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right)
assert(right >= left);
if (enabled()) {
const int height = _view->viewport()->height() - UpMargin - DownMargin;
const int height = get_view_rect().height();
const int width = right - left;
const int y = get_zeroPos() + height * 0.5;
@ -581,8 +620,9 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right)
if (snapshots.empty())
return;
_scale = height * 1.0f / 256;
const shared_ptr<pv::data::DsoSnapshot> &snapshot =
if (_view->session().get_capture_state() == SigSession::Running)
_scale = height * 1.0f / 256;
const boost::shared_ptr<pv::data::DsoSnapshot> &snapshot =
snapshots.front();
const uint16_t number_channels = snapshot->get_channel_num();
@ -647,9 +687,19 @@ void DsoSignal::paint_fore(QPainter &p, int left, int right)
p.setBrush(hover ? _colour.dark() : _colour);
p.drawPolygon(points, countof(points));
// paint the trig voltage
int trigp = get_trig_vpos();
float t_vol = (_zeroPos - _trig_vpos) * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS;
QString t_vol_s = (_vDial->get_value() >= 500) ? QString::number(t_vol/1000.0f, 'f', 2)+"V" : QString::number(t_vol, 'f', 2)+"mV";
int vol_width = p.boundingRect(0, 0, INT_MAX, INT_MAX,
Qt::AlignLeft | Qt::AlignTop, t_vol_s).width();
const QRectF t_vol_rect = QRectF(right-vol_width, trigp-10, vol_width, 20);
p.setPen(Qt::white);
p.drawText(t_vol_rect, Qt::AlignRight | Qt::AlignVCenter, t_vol_s);
// paint the _trig_vpos line
p.setPen(QPen(_colour, 1, Qt::DotLine));
p.drawLine(left, get_trig_vpos(), right - label_rect.width()*1.5, get_trig_vpos());
p.drawLine(left, trigp, right - p.boundingRect(t_vol_rect, Qt::AlignLeft, t_vol_s).width(), trigp);
// Paint the text
p.setPen(Qt::white);
@ -687,9 +737,10 @@ void DsoSignal::paint_trace(QPainter &p,
float top = get_view_rect().top();
float bottom = get_view_rect().bottom();
float zeroP = 0;
if (strcmp(_dev_inst->dev_inst()->driver->name, "DSLogic") == 0)
zeroP = (_zeroPos - 0.5) * get_view_rect().height();
float zeroP = _zeroPos * get_view_rect().height() + top;;
if (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0 &&
_view->session().get_capture_state() == SigSession::Running)
_zero_off = _zeroPos * 255;
float x = (start / samples_per_pixel - pixels_offset) + left;
double pixels_per_sample = 1.0/samples_per_pixel;
uint8_t offset;
@ -700,7 +751,7 @@ void DsoSignal::paint_trace(QPainter &p,
//offset = samples[(sample - start)*num_channels];
offset = samples[sample];
const float y = min(max(top, top + offset * _scale + zeroP), bottom);
const float y = min(max(top, zeroP + (offset - _zero_off) * _scale), bottom);
*point++ = QPointF(x, y);
x += pixels_per_sample;
//*point++ = QPointF(x, top + offset);
@ -738,9 +789,10 @@ void DsoSignal::paint_envelope(QPainter &p,
QRectF *rect = rects;
float top = get_view_rect().top();
float bottom = get_view_rect().bottom();
float zeroP = 0;
if (strcmp(_dev_inst->dev_inst()->driver->name, "DSLogic") == 0)
zeroP = (_zeroPos - 0.5) * get_view_rect().height();
float zeroP = _zeroPos * get_view_rect().height() + top;
if (strcmp(_dev_inst->dev_inst()->driver->name, "DSCope") == 0 &&
_view->session().get_capture_state() == SigSession::Running)
_zero_off = _zeroPos * 255;
for(uint64_t sample = 0; sample < e.length-1; sample++) {
const float x = ((e.scale * sample + e.start) /
samples_per_pixel - pixels_offset) + left;
@ -749,8 +801,8 @@ void DsoSignal::paint_envelope(QPainter &p,
// We overlap this sample with the next so that vertical
// gaps do not appear during steep rising or falling edges
const float b = min(max(top, (top + max(s->max, (s+1)->min) * _scale + zeroP)), bottom);
const float t = min(max(top, (top + min(s->min, (s+1)->max) * _scale + zeroP)), bottom);
const float b = min(max(top, ((max(s->max, (s+1)->min) - _zero_off) * _scale + zeroP)), bottom);
const float t = min(max(top, ((min(s->min, (s+1)->max) - _zero_off) * _scale + zeroP)), bottom);
float h = b - t;
if(h >= 0.0f && h <= 1.0f)
@ -776,6 +828,9 @@ void DsoSignal::paint_type_options(QPainter &p, int right, bool hover, int actio
{
int y = get_y();
const QRectF vDial_rect = get_rect("vDial", y, right);
const QRectF x1_rect = get_rect("x1", y, right);
const QRectF x10_rect = get_rect("x10", y, right);
const QRectF x100_rect = get_rect("x100", y, right);
const QRectF hDial_rect = get_rect("hDial", y, right);
const QRectF acdc_rect = get_rect("acdc", y, right);
const QRectF chEn_rect = get_rect("chEn", y, right);
@ -797,6 +852,31 @@ void DsoSignal::paint_type_options(QPainter &p, int right, bool hover, int actio
p.setPen(Qt::white);
p.drawText(acdc_rect, Qt::AlignCenter | Qt::AlignVCenter, (_acCoupling == SR_GND_COUPLING) ? "GND" :
(_acCoupling == SR_DC_COUPLING) ? "DC" : "AC");
// paint the probe factor selector
GVariant* gvar;
uint64_t factor;
gvar = _dev_inst->get_config(_probe, NULL, SR_CONF_FACTOR);
if (gvar != NULL) {
factor = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
} else {
qDebug() << "ERROR: config_get SR_CONF_FACTOR failed.";
return;
}
p.setPen(Qt::white);
p.setBrush((enabled() && (factor == 100)) ? ((hover && action == X100) ? _colour.darker() : _colour) : ((hover && action == X100) ? _colour.darker() : dsDisable));
p.drawRect(x100_rect);
p.drawText(x100_rect, Qt::AlignLeft | Qt::AlignVCenter, "x100");
p.setBrush((enabled() && (factor == 10)) ? ((hover && action == X10) ? _colour.darker() : _colour) : ((hover && action == X10) ? _colour.darker() : dsDisable));
p.drawRect(x10_rect);
p.drawText(x10_rect, Qt::AlignLeft | Qt::AlignVCenter, "x10");
p.setBrush((enabled() && (factor == 1)) ? ((hover && action == X1) ? _colour.darker() : _colour) : ((hover && action == X1) ? _colour.darker() : dsDisable));
p.drawRect(x1_rect);
p.drawText(x1_rect, Qt::AlignLeft | Qt::AlignVCenter, "x1");
}
void DsoSignal::paint_measure(QPainter &p)
@ -808,26 +888,26 @@ void DsoSignal::paint_measure(QPainter &p)
if (sr_status_get(_dev_inst->dev_inst(), &status, st_begin, st_end) == SR_OK) {
_max = (index == 0) ? status.ch0_max : status.ch1_max;
_min = (index == 0) ? status.ch0_min : status.ch1_min;
const uint32_t period = (index == 0) ? status.ch0_period : status.ch1_period;
const uint64_t period = (index == 0) ? status.ch0_period : status.ch1_period;
const uint32_t count = (index == 0) ? status.ch0_pcnt : status.ch1_pcnt;
double value_max = ((0xff - _min - (1-_zeroPos)*0xff) * _vDial->get_value() * DS_CONF_DSO_VDIVS) / 0xff;
double value_min = ((0xff - _max - (1-_zeroPos)*0xff) * _vDial->get_value() * DS_CONF_DSO_VDIVS) / 0xff;
_period = (count == 0) ? period * 10 : period * 10.0f / count;
double value_max = (_zero_off - _min) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height();
double value_min = (_zero_off - _max) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height();
_period = (count == 0) ? period * 10.0 : period * 10.0 / count;
const int channel_count = _view->session().get_ch_num(SR_CHANNEL_DSO);
uint64_t sample_rate = _dev_inst->get_sample_rate();
_period = _period * 200 / (channel_count * sample_rate * 1.0f/ SR_MHZ(1));
QString max_string = abs(value_max) > 1000 ? QString::number(value_max/1000.0) + "V" : QString::number(value_max) + "mV";
QString min_string = abs(value_min) > 1000 ? QString::number(value_min/1000.0) + "V" : QString::number(value_min) + "mV";
QString period_string = abs(_period) > 1000000000 ? QString::number(_period/1000000000) + "S" :
abs(_period) > 1000000 ? QString::number(_period/1000000) + "mS" :
abs(_period) > 1000 ? QString::number(_period/1000) + "uS" : QString::number(_period) + "nS";
QString freq_string = abs(_period) > 1000000 ? QString::number(1000000000/_period) + "Hz" :
abs(_period) > 1000 ? QString::number(1000000/_period) + "kHz" : QString::number(1000/_period) + "MHz";
_period = _period * 200.0 / (channel_count * sample_rate * 1.0 / SR_MHZ(1));
QString max_string = abs(value_max) > 1000 ? QString::number(value_max/1000.0, 'f', 2) + "V" : QString::number(value_max, 'f', 2) + "mV";
QString min_string = abs(value_min) > 1000 ? QString::number(value_min/1000.0, 'f', 2) + "V" : QString::number(value_min, 'f', 2) + "mV";
QString period_string = abs(_period) > 1000000000 ? QString::number(_period/1000000000, 'f', 2) + "S" :
abs(_period) > 1000000 ? QString::number(_period/1000000, 'f', 2) + "mS" :
abs(_period) > 1000 ? QString::number(_period/1000, 'f', 2) + "uS" : QString::number(_period, 'f', 2) + "nS";
QString freq_string = abs(_period) > 1000000 ? QString::number(1000000000/_period, 'f', 2) + "Hz" :
abs(_period) > 1000 ? QString::number(1000000/_period, 'f', 2) + "kHz" : QString::number(1000/_period, 'f', 2) + "MHz";
p.setPen(_colour);
p.drawText(QRectF(0, 100*index + UpMargin, get_view_rect().width(), 20), Qt::AlignRight | Qt::AlignVCenter, "Max: "+max_string+" ");
p.drawText(QRectF(0, 100*index + UpMargin + 20, get_view_rect().width(), 20), Qt::AlignRight | Qt::AlignVCenter, "Min: "+min_string+" ");
p.drawText(QRectF(0, 100*index + UpMargin + 40, get_view_rect().width(), 20), Qt::AlignRight | Qt::AlignVCenter, "Period: "+period_string+" ");
p.drawText(QRectF(0, 100*index + UpMargin + 60, get_view_rect().width(), 20), Qt::AlignRight | Qt::AlignVCenter, "Frequency: "+freq_string+" ");
p.drawText(QRectF(0, 100*index + UpMargin, get_view_rect().width()*0.9, 20), Qt::AlignRight | Qt::AlignVCenter, "Max: "+max_string+" ");
p.drawText(QRectF(0, 100*index + UpMargin + 20, get_view_rect().width()*0.9, 20), Qt::AlignRight | Qt::AlignVCenter, "Min: "+min_string+" ");
p.drawText(QRectF(0, 100*index + UpMargin + 40, get_view_rect().width()*0.9, 20), Qt::AlignRight | Qt::AlignVCenter, "Period: "+period_string+" ");
p.drawText(QRectF(0, 100*index + UpMargin + 60, get_view_rect().width()*0.9, 20), Qt::AlignRight | Qt::AlignVCenter, "Frequency: "+freq_string+" ");
if (_autoV) {
const uint8_t vscale = abs(_max - _min);
@ -846,8 +926,8 @@ void DsoSignal::paint_measure(QPainter &p)
const double upPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.8;
const double dnPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.2;
if (_period > upPeriod) {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->go_hDialNext(setted);
setted = true;
@ -856,8 +936,8 @@ void DsoSignal::paint_measure(QPainter &p)
} else if (_period > dnPeriod) {
_autoH = false;
} else {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->go_hDialPre(setted);
setted = true;
@ -880,5 +960,78 @@ void DsoSignal::auto_set()
}
}
bool DsoSignal::measure(const QPointF &p)
{
_hover_en = false;
if (!enabled())
return false;
const deque< boost::shared_ptr<pv::data::DsoSnapshot> > &snapshots =
_data->get_snapshots();
if (snapshots.empty())
return false;
const boost::shared_ptr<pv::data::DsoSnapshot> &snapshot =
snapshots.front();
if (snapshot->buf_null())
return false;
const double scale = _view->scale();
assert(scale > 0);
const double offset = _view->offset();
const double pixels_offset = offset / scale;
const double samplerate = _dev_inst->get_sample_rate();
const double samples_per_pixel = samplerate * scale;
_hover_index = floor((p.x() + pixels_offset) * samples_per_pixel+0.5);
if (_hover_index >= snapshot->get_sample_count())
return false;
uint64_t pre_index;
uint64_t nxt_index;
if (_hover_index > 0)
pre_index = _hover_index - 1;
else
pre_index = _hover_index;
if (_hover_index < snapshot->get_sample_count() - 1)
nxt_index = _hover_index + 1;
else
nxt_index = _hover_index;
const uint8_t pre_sample = *snapshot->get_samples(pre_index, pre_index, get_index());
const uint8_t cur_sample = *snapshot->get_samples(_hover_index, _hover_index, get_index());
const uint8_t nxt_sample = *snapshot->get_samples(nxt_index, nxt_index, get_index());
_hover_value = (_zero_off - cur_sample) * _scale * _vDial->get_value() * _vDial->get_factor() * DS_CONF_DSO_VDIVS / get_view_rect().height();
float top = get_view_rect().top();
float bottom = get_view_rect().bottom();
float zeroP = _zeroPos * get_view_rect().height() + top;
float pre_x = (pre_index / samples_per_pixel - pixels_offset);
const float pre_y = min(max(top, zeroP + (pre_sample - _zero_off)* _scale), bottom);
float x = (_hover_index / samples_per_pixel - pixels_offset);
const float y = min(max(top, zeroP + (cur_sample - _zero_off)* _scale), bottom);
float nxt_x = (nxt_index / samples_per_pixel - pixels_offset);
const float nxt_y = min(max(top, zeroP + (nxt_sample - _zero_off)* _scale), bottom);
const QRectF slope_rect = QRectF(QPointF(pre_x - 10, pre_y - 10), QPointF(nxt_x + 10, nxt_y + 10));
if (abs(y-p.y()) < 20 || slope_rect.contains(p)) {
_hover_point = QPointF(x, y);
_hover_en = true;
return true;
} else {
return false;
}
}
bool DsoSignal::get_hover(uint64_t &index, QPointF &p, double &value)
{
if (_hover_en) {
index = _hover_index;
p = _hover_point;
value = _hover_value;
return true;
}
return false;
}
} // namespace view
} // namespace pv

View File

@ -43,10 +43,11 @@ class DsoSignal : public Signal
private:
static const QColor SignalColours[4];
static const float EnvelopeThreshold;
static const double TrigMargin;
static const int HitCursorMargin = 3;
static const quint64 vDialValueCount = 8;
static const quint64 vDialValueStep = 1000;
static const uint64_t vDialValueCount = 8;
static const uint64_t vDialValueStep = 1000;
static const uint64_t vDialUnitCount = 2;
static const uint64_t hDialValueCount = 28;
static const uint64_t hDialValueStep = 1000;
@ -94,6 +95,13 @@ public:
void set_acCoupling(uint8_t coupling);
void set_trig_vpos(int pos);
int get_trig_vpos() const;
void set_factor(uint64_t factor);
/**
*
*/
bool measure(const QPointF &p);
bool get_hover(uint64_t &index, QPointF &p, double &value);
/**
* auto set the vertical and Horizontal scale
@ -171,12 +179,18 @@ private:
double _trig_vpos;
double _zeroPos;
float _zero_off;
uint8_t _max;
uint8_t _min;
double _period;
bool _autoV;
bool _autoH;
bool _hover_en;
uint64_t _hover_index;
QPointF _hover_point;
double _hover_value;
};
} // namespace view

View File

@ -63,7 +63,7 @@ bool GroupSignal::enabled() const
return true;
}
shared_ptr<pv::data::SignalData> GroupSignal::data() const
boost::shared_ptr<pv::data::SignalData> GroupSignal::data() const
{
return _data;
}

View File

@ -160,7 +160,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event)
const boost::shared_ptr<Trace> mTrace =
get_mTrace(action, event->pos());
if (action == Trace::LABEL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->auto_set();
}
@ -239,8 +239,8 @@ void Header::mousePressEvent(QMouseEvent *event)
else
mTrace->set_trig(Trace::EDGETRIG);
} else if (action == Trace::VDIAL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_hDialActive(false);
if (t != mTrace) {
@ -251,17 +251,17 @@ void Header::mousePressEvent(QMouseEvent *event)
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace))
dsoSig->set_vDialActive(!dsoSig->get_vDialActive());
} else if (action == Trace::HDIAL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
if (dsoSig->get_hDialActive()) {
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_vDialActive(false);
dsoSig->set_hDialActive(false);
}
}
} else {
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_vDialActive(false);
dsoSig->set_hDialActive(true);
@ -270,24 +270,39 @@ void Header::mousePressEvent(QMouseEvent *event)
}
}
} else if (action == Trace::CHEN && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->set_enable(!dsoSig->enabled());
}
} else if (action == Trace::ACDC && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
if (strcmp(_view.session().get_device()->dev_inst()->driver->name, "DSLogic") == 0)
dsoSig->set_acCoupling((dsoSig->get_acCoupling()+1)%2);
else
dsoSig->set_acCoupling((dsoSig->get_acCoupling()+1)%3);
}
} else if (action == Trace::X1 && mTrace) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->set_factor(1);
}
} else if (action == Trace::X10 && mTrace) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->set_factor(10);
}
} else if (action == Trace::X100 && mTrace) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->set_factor(100);
}
}
if (~QApplication::keyboardModifiers() & Qt::ControlModifier) {
// Unselect all other Traces because the Ctrl is not
// pressed
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
if (t != mTrace)
t->select(false);
}
@ -330,13 +345,13 @@ void Header::wheelEvent(QWheelEvent *event)
assert(event);
if (event->orientation() == Qt::Vertical) {
const vector< shared_ptr<Trace> > traces(
const vector< boost::shared_ptr<Trace> > traces(
_view.get_traces());
// Vertical scrolling
double shift = event->delta() / 20.0;
bool setted = false;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
if (dsoSig->get_vDialActive()) {
if (shift > 1.0)
@ -407,7 +422,7 @@ void Header::mouseMoveEvent(QMouseEvent *event)
// Ensure the Trace is selected
sig->select(true);
} else {
shared_ptr<DsoSignal> dsoSig;
boost::shared_ptr<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(sig)) {
dsoSig->set_zeroPos(y);
dsoSig->select(false);

View File

@ -76,6 +76,15 @@ LogicSignal::LogicSignal(boost::shared_ptr<pv::device::DevInst> dev_inst,
_colour = SignalColours[probe->index % countof(SignalColours)];
}
LogicSignal::LogicSignal(const Signal &s,
boost::shared_ptr<pv::data::Logic> data,
const sr_channel * const probe) :
Signal(s, probe),
_data(data)
{
assert(probe->index >= 0);
}
LogicSignal::~LogicSignal()
{
}
@ -85,12 +94,12 @@ const sr_channel* LogicSignal::probe() const
return _probe;
}
shared_ptr<pv::data::SignalData> LogicSignal::data() const
boost::shared_ptr<pv::data::SignalData> LogicSignal::data() const
{
return _data;
}
shared_ptr<pv::data::Logic> LogicSignal::logic_data() const
boost::shared_ptr<pv::data::Logic> LogicSignal::logic_data() const
{
return _data;
}
@ -273,5 +282,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 || index >= (snapshot->get_sample_count() - 1))
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

View File

@ -58,6 +58,10 @@ public:
boost::shared_ptr<pv::data::Logic> data,
const sr_channel * const probe);
LogicSignal(const Signal &s,
boost::shared_ptr<pv::data::Logic> data,
const sr_channel * const probe);
virtual ~LogicSignal();
const sr_channel* probe() const;
@ -76,6 +80,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);

View File

@ -102,9 +102,8 @@ QString Ruler::format_freq(double period, unsigned precision)
} else {
const int order = ceil(log10f(period));
assert(order >= FirstSIPrefixPower);
const unsigned int prefix = ceil((order - FirstSIPrefixPower) / 3.0f);
const double multiplier = pow(10.0,
static_cast<double>(- prefix * 3 - FirstSIPrefixPower));
const int prefix = ceil((order - FirstSIPrefixPower) / 3.0f);
const double multiplier = pow(10.0, max(-prefix * 3.0 - FirstSIPrefixPower, 0.0));
QString s;
QTextStream ts(&s);
@ -115,11 +114,10 @@ QString Ruler::format_freq(double period, unsigned precision)
}
}
QString Ruler::format_time(double t, unsigned int prefix,
QString Ruler::format_time(double t, int prefix,
unsigned int precision)
{
const double multiplier = pow(10.0,
static_cast<double>(- prefix * 3 - FirstSIPrefixPower + 6));
const double multiplier = pow(10.0, -prefix * 3 - FirstSIPrefixPower + 6.0);
QString s;
QTextStream ts(&s);
@ -134,6 +132,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 = std::pow(10, 12) / sample_rate * delta_index;
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 / std::pow(10.0, 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.0 / sample_rate;
return format_freq(delta_period);
}
TimeMarker* Ruler::get_grabbed_cursor()
{
return _grabbed_marker;
@ -182,8 +203,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 +263,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 +281,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);
}
@ -307,8 +322,8 @@ void Ruler::draw_tick_mark(QPainter &p)
{
using namespace Qt;
const double SpacingIncrement = 32.0f;
const double MinValueSpacing = 16.0f;
const double SpacingIncrement = 32.0;
const double MinValueSpacing = 16.0;
const int ValueMargin = 15;
double min_width = SpacingIncrement, typical_width;
@ -406,11 +421,11 @@ void Ruler::draw_logic_tick_mark(QPainter &p)
{
using namespace Qt;
const double SpacingIncrement = 32.0f;
const double MinValueSpacing = 16.0f;
const double SpacingIncrement = 32.0;
const double MinValueSpacing = 16.0;
const int ValueMargin = 5;
const double abs_min_period = 10.0f / _view.session().get_device()->get_sample_rate();
const double abs_min_period = 10.0 / _view.session().get_device()->get_sample_rate();
double min_width = SpacingIncrement;
double typical_width;
@ -488,13 +503,13 @@ void Ruler::draw_logic_tick_mark(QPainter &p)
else
{
// Draw a minor tick
if (minor_tick_period / _view.scale() > 2 * typical_width ||
tick_period / _view.scale() > _view.get_view_width())
if (minor_tick_period / _view.scale() > 2 * typical_width)
p.drawText(x, 2 * ValueMargin, 0, text_height,
AlignCenter | AlignTop | TextDontClip,
format_time(t, prefix));
//else if ((tick_period / _view.scale() > width() / 4) && (minor_tick_period / _view.scale() > inc_text_width))
else if (minor_tick_period / _view.scale() > 1.1 * inc_text_width)
else if (minor_tick_period / _view.scale() > 1.1 * inc_text_width ||
tick_period / _view.scale() > _view.get_view_width())
p.drawText(x, 2 * ValueMargin, 0, minor_tick_y1 + ValueMargin,
AlignCenter | AlignTop | TextDontClip,
format_time(t - major_t, minor_prefix));

View File

@ -25,6 +25,7 @@
#define DSVIEW_PV_VIEW_RULER_H
#include <QWidget>
#include <stdint.h>
namespace pv {
namespace view {
@ -62,10 +63,12 @@ public:
public:
Ruler(View &parent);
static QString format_time(double t, unsigned int prefix,
static QString format_time(double t, int prefix,
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);

View File

@ -42,6 +42,13 @@ Signal::Signal(boost::shared_ptr<pv::device::DevInst> dev_inst,
{
}
Signal::Signal(const Signal &s, const sr_channel * const probe) :
Trace((const Trace &)s),
_dev_inst(s._dev_inst),
_probe(probe)
{
}
bool Signal::enabled() const
{
return _probe->enabled;

View File

@ -59,6 +59,11 @@ protected:
Signal(boost::shared_ptr<pv::device::DevInst> dev_inst,
const sr_channel * const probe, int type);
/**
* Copy constructor
*/
Signal(const Signal &s, const sr_channel * const probe);
public:
virtual boost::shared_ptr<pv::data::SignalData> data() const = 0;

View File

@ -24,6 +24,7 @@
#include "timemarker.h"
#include "view.h"
#include "../device/device.h"
#include <QPainter>
@ -31,10 +32,10 @@ namespace pv {
namespace view {
TimeMarker::TimeMarker(View &view, QColor &colour,
double time) :
uint64_t index) :
_view(view),
_time(time),
_grabbed(false),
_index(index),
_grabbed(false),
_colour(colour)
{
}
@ -42,7 +43,7 @@ TimeMarker::TimeMarker(View &view, QColor &colour,
TimeMarker::TimeMarker(const TimeMarker &s) :
QObject(),
_view(s._view),
_time(s._time),
_index(s._index),
_colour(s._colour)
{
}
@ -56,20 +57,21 @@ void TimeMarker::set_grabbed(bool grabbed)
_grabbed = grabbed;
}
double TimeMarker::time() const
uint64_t TimeMarker::index() const
{
return _time;
return _index;
}
void TimeMarker::set_time(double time)
void TimeMarker::set_index(uint64_t index)
{
_time = time;
time_changed();
_index = index;
time_changed();
}
void TimeMarker::paint(QPainter &p, const QRect &rect, const bool highlight)
{
const float x = (_time - _view.offset()) / _view.scale();
const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale();
const double x = _index/samples_per_pixel - (_view.offset() / _view.scale());
p.setPen((_grabbed | highlight) ? QPen(_colour.lighter(), 2, Qt::DashLine) : QPen(_colour, 1, Qt::DashLine));
p.drawLine(QPointF(x, rect.top()), QPointF(x, rect.bottom()));
}

View File

@ -28,6 +28,8 @@
#include <QObject>
#include <QRectF>
#include <stdint.h>
class QPainter;
class QRect;
@ -47,7 +49,7 @@ 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);
/**
* Copy constructor
@ -59,11 +61,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);
/*
*
@ -103,7 +106,7 @@ signals:
protected:
View &_view;
double _time;
uint64_t _index;
QSizeF _text_size;

View File

@ -53,19 +53,9 @@ const QPen Trace::SignalAxisPen = QColor(128, 128, 128, 64);
const QPen Trace::AxisPen(QColor(128, 128, 128, 64));
const int Trace::LabelHitPadding = 2;
Trace::Trace(QString name, int type) :
_name(name),
_v_offset(0),
_type(type),
_sec_index(0),
_signalHeight(30),
_trig(0)
{
}
Trace::Trace(QString name, int index, int type) :
_name(name),
_v_offset(0),
_v_offset(INT_MAX),
_type(type),
_sec_index(0),
_signalHeight(30),
@ -76,7 +66,7 @@ Trace::Trace(QString name, int index, int type) :
Trace::Trace(QString name, std::list<int> index_list, int type, int sec_index) :
_name(name),
_v_offset(0),
_v_offset(INT_MAX),
_type(type),
_index_list(index_list),
_sec_index(sec_index),
@ -85,6 +75,21 @@ Trace::Trace(QString name, std::list<int> index_list, int type, int sec_index) :
{
}
Trace::Trace(const Trace &t) :
_view(t._view),
_name(t._name),
_colour(t._colour),
_v_offset(t._v_offset),
_type(t._type),
_index_list(t._index_list),
_sec_index(t._sec_index),
_old_v_offset(t._old_v_offset),
_signalHeight(t._signalHeight),
_trig(t._trig),
_text_size(t._text_size)
{
}
QString Trace::get_name() const
{
return _name;
@ -300,6 +305,9 @@ int Trace::pt_in_rect(int y, int right, const QPoint &point)
const QRectF edgeTrig = get_rect("edgeTrig", y, right);
const QRectF label = get_rect("label", get_zeroPos(), right);
const QRectF vDial = get_rect("vDial", y, right);
const QRectF x1 = get_rect("x1", y, right);
const QRectF x10 = get_rect("x10", y, right);
const QRectF x100 = get_rect("x100", y, right);
const QRectF hDial = get_rect("hDial", y, right);
const QRectF chEn = get_rect("chEn", y, right);
const QRectF acdc = get_rect("acdc", y, right);
@ -323,6 +331,12 @@ int Trace::pt_in_rect(int y, int right, const QPoint &point)
return LABEL;
else if (vDial.contains(point) && _type == DS_DSO && enabled())
return VDIAL;
else if (x1.contains(point) && _type == DS_DSO && enabled())
return X1;
else if (x10.contains(point) && _type == DS_DSO && enabled())
return X10;
else if (x100.contains(point) && _type == DS_DSO && enabled())
return X100;
else if (hDial.contains(point) && _type == DS_DSO && enabled())
return HDIAL;
else if (chEn.contains(point) && _type == DS_DSO)
@ -400,6 +414,21 @@ QRectF Trace::get_rect(const char *s, int y, int right)
get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin,
y - SquareWidth * SquareNum,
SquareWidth * (SquareNum-1), SquareWidth * (SquareNum-1));
else if (!strcmp(s, "x1"))
return QRectF(
get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin - 45,
y - SquareWidth - SquareWidth * (SquareNum-1) * 0.85,
SquareWidth * 1.75, SquareWidth);
else if (!strcmp(s, "x10"))
return QRectF(
get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin - 45,
y - SquareWidth - SquareWidth * (SquareNum-1) * 0.55,
SquareWidth * 1.75, SquareWidth);
else if (!strcmp(s, "x100"))
return QRectF(
get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin - 45,
y - SquareWidth - SquareWidth * (SquareNum-1) * 0.25,
SquareWidth * 1.75, SquareWidth);
else if (!strcmp(s, "hDial"))
return QRectF(
get_leftWidth() + name_size.width() + SquareWidth*0.5 + Margin,

View File

@ -66,6 +66,9 @@ public:
static const int CHEN = 11;
static const int ACDC = 12;
static const int DSOTRIG = 13;
static const int X1 = 14;
static const int X10 = 15;
static const int X100 = 16;
static const QColor dsBlue;
static const QColor dsYellow;
@ -81,12 +84,16 @@ public:
static const QPen SignalAxisPen;
protected:
Trace(QString name, int type);
Trace(QString name, int index, int type);
Trace(QString name, std::list<int> index_list, int type, int sec_index);
/**
* Copy constructor
*/
Trace(const Trace &t);
public:
enum {DS_LOGIC = 0, DS_ANALOG, DS_GROUP, DS_DSO, DS_DECODER};
enum {DS_LOGIC = 0, DS_ANALOG, DS_DSO, DS_GROUP, DS_DECODER};
public:
/**

View File

@ -27,11 +27,12 @@
#include <boost/foreach.hpp>
#include <QtGui/QApplication>
#include <QApplication>
#include <QEvent>
#include <QMouseEvent>
#include <QScrollBar>
#include "groupsignal.h"
#include "decodetrace.h"
#include "header.h"
#include "devmode.h"
@ -96,12 +97,10 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget
setViewportMargins(headerWidth(), RulerHeight, 0, 0);
setViewport(_viewport);
connect(&_session, SIGNAL(signals_changed()),
this, SLOT(signals_changed()));
connect(&_session, SIGNAL(data_updated()),
this, SLOT(data_updated()));
connect(&_session, SIGNAL(receive_data(quint64)),
this, SLOT(receive_data(quint64)));
connect(&_session, SIGNAL(signals_changed()),
this, SLOT(signals_changed()));
connect(&_session, SIGNAL(data_updated()),
this, SLOT(data_updated()));
connect(&_session, SIGNAL(receive_trigger(quint64)),
this, SLOT(set_trig_pos(quint64)));
@ -211,10 +210,10 @@ void View::zoom(double steps, int offset)
_scale *= std::pow(3.0/2.0, -steps);
_scale = max(min(_scale, _maxscale), _minscale);
}else {
const vector< shared_ptr<Signal> > sigs(_session.get_signals());
const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
bool setted = false;
BOOST_FOREACH(const shared_ptr<Signal> s, sigs) {
shared_ptr<DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
boost::shared_ptr<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(s)) {
if(steps > 0.5)
dsoSig->go_hDialPre(setted);
@ -273,34 +272,39 @@ void View::set_preScale_preOffset()
set_scale_offset(_preScale, _preOffset);
}
vector< shared_ptr<Trace> > View::get_traces() const
vector< boost::shared_ptr<Trace> > View::get_traces() const
{
const vector< shared_ptr<Signal> > sigs(_session.get_signals());
const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
const vector< boost::shared_ptr<GroupSignal> > groups(_session.get_group_signals());
#ifdef ENABLE_DECODE
const vector< shared_ptr<DecodeTrace> > decode_sigs(
const vector< boost::shared_ptr<DecodeTrace> > decode_sigs(
_session.get_decode_signals());
vector< shared_ptr<Trace> > traces(
sigs.size() + decode_sigs.size());
vector< boost::shared_ptr<Trace> > traces(
sigs.size() + groups.size() + decode_sigs.size());
#else
vector< shared_ptr<Trace> > traces(sigs.size());
vector< boost::shared_ptr<Trace> > traces(sigs.size() + groups.size());
#endif
vector< shared_ptr<Trace> >::iterator i = traces.begin();
vector< boost::shared_ptr<Trace> >::iterator i = traces.begin();
i = copy(sigs.begin(), sigs.end(), i);
#ifdef ENABLE_DECODE
i = copy(decode_sigs.begin(), decode_sigs.end(), i);
#endif
i = copy(groups.begin(), groups.end(), i);
stable_sort(traces.begin(), traces.end(), compare_trace_v_offsets);
return traces;
}
bool View::compare_trace_v_offsets(const shared_ptr<Trace> &a,
const shared_ptr<Trace> &b)
bool View::compare_trace_v_offsets(const boost::shared_ptr<Trace> &a,
const boost::shared_ptr<Trace> &b)
{
assert(a);
assert(b);
return a->get_v_offset() < b->get_v_offset();
if (a->get_type() != b->get_type())
return a->get_type() > b->get_type();
else
return a->get_v_offset() < b->get_v_offset();
}
bool View::cursors_shown() const
@ -341,9 +345,9 @@ void View::show_search_cursor(bool show)
void View::set_trig_pos(quint64 trig_pos)
{
const double time = trig_pos * 1.0f / _session.get_device()->get_sample_rate();
const double time = trig_pos * 1.0 / _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();
@ -354,9 +358,9 @@ void View::set_search_pos(uint64_t search_pos)
{
//assert(search_pos >= 0);
const double time = search_pos * 1.0f / _session.get_device()->get_sample_rate();
const double time = search_pos * 1.0 / _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();
@ -379,14 +383,14 @@ const QPointF& View::hover_point() const
void View::normalize_layout()
{
const vector< shared_ptr<Trace> > traces(get_traces());
const vector< boost::shared_ptr<Trace> > traces(get_traces());
int v_min = INT_MAX;
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
v_min = min(t->get_v_offset(), v_min);
const int delta = -min(v_min, 0);
BOOST_FOREACH(shared_ptr<Trace> t, traces)
BOOST_FOREACH(boost::shared_ptr<Trace> t, traces)
t->set_v_offset(t->get_v_offset() + delta);
verticalScrollBar()->setSliderPosition(_v_offset + delta);
@ -406,7 +410,7 @@ int View::get_signalHeight()
void View::get_scroll_layout(double &length, double &offset) const
{
const set< shared_ptr<data::SignalData> > data_set = _session.get_data();
const set< boost::shared_ptr<data::SignalData> > data_set = _session.get_data();
if (data_set.empty())
return;
@ -452,20 +456,19 @@ void View::update_scale()
assert(sample_rate > 0);
if (_session.get_device()->dev_inst()->mode != DSO) {
_scale = (1.0f / sample_rate) / WellPixelsPerSample;
_scale = (1.0 / sample_rate) / WellPixelsPerSample;
_maxscale = _session.get_device()->get_sample_time() / (get_view_width() * MaxViewRate);
} else {
_scale = _session.get_device()->get_time_base() * 10.0f / get_view_width() * std::pow(10.0, -9.0);
_scale = _session.get_device()->get_time_base() * 10.0 / get_view_width() * std::pow(10.0, -9.0);
_maxscale = 1e9;
}
_minscale = (1.0f / sample_rate) / MaxPixelsPerSample;
_minscale = (1.0 / sample_rate) / MaxPixelsPerSample;
_offset = 0;
_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();
@ -474,8 +477,8 @@ void View::update_scale()
void View::signals_changed()
{
int total_rows = 0;
const vector< shared_ptr<Trace> > traces(get_traces());
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
const vector< boost::shared_ptr<Trace> > traces(get_traces());
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (dynamic_pointer_cast<DsoSignal>(t) ||
@ -490,7 +493,7 @@ void View::signals_changed()
_signalHeight = (int)((height <= 0) ? 1 : height);
_spanY = _signalHeight + 2 * SignalMargin;
int next_v_offset = SignalMargin;
BOOST_FOREACH(shared_ptr<Trace> t, traces) {
BOOST_FOREACH(boost::shared_ptr<Trace> t, traces) {
t->set_view(this);
const double traceHeight = _signalHeight*t->rows_size();
t->set_signalHeight((int)traceHeight);
@ -551,16 +554,16 @@ bool View::viewportEvent(QEvent *e)
int View::headerWidth()
{
int headerWidth;
int maxNameWidth = 0;
int maxNameWidth = 25;
int maxLeftWidth = 0;
int maxRightWidth = 0;
QFont font = QApplication::font();
QFontMetrics fm(font);
const vector< shared_ptr<Trace> > traces(get_traces());
const vector< boost::shared_ptr<Trace> > traces(get_traces());
if (!traces.empty()){
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
maxNameWidth = max(fm.boundingRect(t->get_name()).width(), maxNameWidth);
maxLeftWidth = max(t->get_leftWidth(), maxLeftWidth);
maxRightWidth = max(t->get_rightWidth(), maxRightWidth);
@ -581,7 +584,11 @@ void View::resizeEvent(QResizeEvent*)
if (_session.get_device()->dev_inst()->mode == DSO)
_scale = _session.get_device()->get_time_base() * std::pow(10.0, -9.0) * DS_CONF_DSO_HDIVS / get_view_width();
_maxscale = _session.get_device()->get_sample_time() / (get_view_width() * MaxViewRate);
if (_session.get_device()->dev_inst()->mode != DSO)
_maxscale = _session.get_device()->get_sample_time() / (get_view_width() * MaxViewRate);
else
_maxscale = 1e9;
_scale = min(_scale, _maxscale);
signals_changed();
@ -697,9 +704,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();
}
@ -720,32 +727,17 @@ void View::set_cursor_middle(int index)
list<Cursor*>::iterator i = _cursorList.begin();
while (index-- != 0)
i++;
set_scale_offset(_scale, (*i)->time() - _scale * get_view_width() / 2);
set_scale_offset(_scale, (*i)->index() * 1.0 / _session.get_device()->get_sample_rate() - _scale * get_view_width() / 2);
}
void View::receive_data(quint64 length)
Viewport * View::get_viewport()
{
_viewport->set_receive_len(length);
}
QString View::get_mm_width()
{
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,11 +745,13 @@ 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)
uint64_t View::get_cursor_samples(int index)
{
assert(index < (int)_cursorList.size());
@ -765,25 +759,12 @@ double View::get_cursor_time(int index)
for (list<Cursor*>::iterator i = _cursorList.begin();
i != _cursorList.end(); i++) {
if (index == curIndex) {
return (*i)->time();
return (*i)->index();
}
curIndex++;
}
}
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);
return time*sample_rate;
}
void View::on_mouse_moved()
{
mouse_moved();
}
void View::on_cursor_moved()
{
cursor_moved();
@ -804,8 +785,8 @@ int View::get_view_width()
{
int view_width = 0;
if (_session.get_device()->dev_inst()->mode == DSO) {
const vector< shared_ptr<Signal> > sigs(_session.get_signals());
BOOST_FOREACH(const shared_ptr<Signal> s, sigs) {
const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
view_width = max((double)view_width, s->get_view_rect().width());
}
} else {

View File

@ -74,9 +74,9 @@ public:
static const QSizeF LabelPadding;
static const int WellPixelsPerSample = 10.0f;
static const double MaxViewRate = 1.0f;
static const int MaxPixelsPerSample = 100.0f;
static const int WellPixelsPerSample = 10;
static constexpr double MaxViewRate = 1.0;
static const int MaxPixelsPerSample = 100;
public:
explicit View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent = 0);
@ -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();
@ -201,8 +197,6 @@ private:
void update_margins();
double get_cursor_time(int index);
static bool compare_trace_v_offsets(
const boost::shared_ptr<pv::view::Trace> &a,
const boost::shared_ptr<pv::view::Trace> &b);
@ -231,8 +225,6 @@ private slots:
void header_updated();
void receive_data(quint64 length);
void set_trig_pos(quint64 trig_pos);
private:

View File

@ -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"
@ -35,6 +36,8 @@
#include <QMouseEvent>
#include <QStyleOption>
#include <math.h>
#include <boost/foreach.hpp>
using namespace boost;
@ -49,11 +52,14 @@ Viewport::Viewport(View &parent) :
_total_receive_len(0),
_zoom_rect_visible(false),
_measure_shown(false),
_measure_type(LOGIC),
_cur_sample(0),
_nxt_sample(1),
_cur_preX(0),
_cur_aftX(1),
_cur_midY(0)
_cur_midY(0),
_hover_index(0),
_hover_hit(false)
{
setMouseTracking(true);
setAutoFillBackground(true);
@ -63,6 +69,7 @@ Viewport::Viewport(View &parent) :
_mm_width = "#####";
_mm_period = "#####";
_mm_freq = "#####";
_mm_duty = "#####";
_measure_en = true;
triggered = false;
timer_cnt = 0;
@ -71,14 +78,17 @@ Viewport::Viewport(View &parent) :
this, SLOT(on_traces_moved()));
connect(&trigger_timer, SIGNAL(timeout()),
this, SLOT(on_trigger_timer()));
connect(&_view.session(), &SigSession::receive_data,
this, &Viewport::set_receive_len);
}
int Viewport::get_total_height() const
{
int h = 0;
const vector< shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
assert(t);
h += (int)(t->get_signalHeight());
}
@ -103,14 +113,14 @@ void Viewport::paintEvent(QPaintEvent *event)
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
const vector< shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces());
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
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()) {
@ -122,22 +132,23 @@ void Viewport::paintEvent(QPaintEvent *event)
break;
case SigSession::Running:
//p.setRenderHint(QPainter::Antialiasing);
p.setRenderHint(QPainter::Antialiasing);
paintProgress(p);
p.setRenderHint(QPainter::Antialiasing, false);
break;
}
} else {
paintSignals(p);
}
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (t->enabled())
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();
@ -146,7 +157,7 @@ void Viewport::paintEvent(QPaintEvent *event)
void Viewport::paintSignals(QPainter &p)
{
const vector< shared_ptr<Trace> > traces(_view.get_traces());
const vector< boost::shared_ptr<Trace> > traces(_view.get_traces());
if (_view.scale() != _curScale ||
_view.offset() != _curOffset ||
_view.get_signalHeight() != _curSignalHeight ||
@ -159,8 +170,8 @@ void Viewport::paintSignals(QPainter &p)
pixmap.fill(Qt::transparent);
QPainter dbp(&pixmap);
dbp.initFrom(this);
p.setRenderHint(QPainter::Antialiasing, false);
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
//p.setRenderHint(QPainter::Antialiasing, false);
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (t->enabled())
@ -175,8 +186,9 @@ void Viewport::paintSignals(QPainter &p)
if (_view.cursors_shown()) {
list<Cursor*>::iterator i = _view.get_cursorList().begin();
double cursorX;
const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale();
while (i != _view.get_cursorList().end()) {
cursorX = ((*i)->time() - _view.offset()) / _view.scale();
cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale());
if (rect().contains(_view.hover_point().x(), _view.hover_point().y()) &&
qAbs(cursorX - _view.hover_point().x()) <= HitCursorMargin)
(*i)->paint(p, rect(), 1);
@ -209,8 +221,8 @@ void Viewport::paintProgress(QPainter &p)
{
using pv::view::Signal;
const quint64 _total_sample_len = _view.session().get_device()->get_sample_limit();
double progress = -(_total_receive_len * 1.0f / _total_sample_len * 360 * 16);
const uint64_t _total_sample_len = _view.session().get_device()->get_sample_limit();
double progress = -(_total_receive_len * 1.0 / _total_sample_len * 360 * 16);
int captured_progress = 0;
p.setPen(Qt::gray);
@ -297,7 +309,10 @@ void Viewport::paintProgress(QPainter &p)
(status.captured_cnt1 << 8) +
(status.captured_cnt2 << 16) +
(status.captured_cnt3 << 24));
captured_progress = captured_cnt * 100.0 / _total_sample_len;
if (triggred)
captured_progress = (_total_sample_len - captured_cnt) * 100.0 / _total_sample_len;
else
captured_progress = captured_cnt * 100.0 / _total_sample_len;
p.setPen(Trace::dsLightBlue);
@ -338,13 +353,15 @@ void Viewport::mousePressEvent(QMouseEvent *event)
_mouse_down_point = event->pos();
_mouse_down_offset = _view.offset();
_measure_shown = false;
if (event->buttons() & Qt::LeftButton) {
if (_view.cursors_shown()) {
list<Cursor*>::iterator i = _view.get_cursorList().begin();
double cursorX;
const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale();
while (i != _view.get_cursorList().end()) {
cursorX = ((*i)->time() - _view.offset()) / _view.scale();
cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale());
if ((*i)->grabbed())
_view.get_ruler()->rel_grabbed_cursor();
else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) {
@ -355,14 +372,11 @@ void Viewport::mousePressEvent(QMouseEvent *event)
}
}
// if (!_view.get_ruler()->get_grabbed_cursor()) {
// _zoom_rect_visible = true;
// }
const vector< shared_ptr<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const shared_ptr<Signal> s, sigs) {
const vector< boost::shared_ptr<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
assert(s);
shared_ptr<DsoSignal> dsoSig;
boost::shared_ptr<DsoSignal> dsoSig;
if ((dsoSig = dynamic_pointer_cast<DsoSignal>(s)) &&
dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) {
_drag_sig = s;
@ -378,6 +392,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event)
{
assert(event);
_mouse_point = event->pos();
_hover_hit = false;
if (event->buttons() & Qt::RightButton) {
_zoom_rect = QRectF(_mouse_down_point, event->pos());
_zoom_rect_visible = true;
@ -385,7 +400,7 @@ void Viewport::mouseMoveEvent(QMouseEvent *event)
if (event->buttons() & Qt::LeftButton) {
if (_drag_sig) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(_drag_sig))
dsoSig->set_trig_vpos(_mouse_point.y());
} else {
@ -403,13 +418,11 @@ void Viewport::mouseMoveEvent(QMouseEvent *event)
if (_view.cursors_shown() && grabbed_marker) {
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));
const double pos_delta = pos - (uint64_t)pos;
if ( pos_delta < 0.5)
grabbed_marker->set_index((uint64_t)floor(pos));
else
grabbed_marker->set_time(cur_time);
grabbed_marker->set_index((uint64_t)ceil(pos));
}
measure();
}
@ -424,7 +437,7 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event)
if (_zoom_rect_visible) {
_zoom_rect_visible = false;
const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale();
const double newScale = max(min(_view.scale() * (event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(),
const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(),
_view.get_maxscale()), _view.get_minscale());
if (newScale != _view.scale())
_view.set_scale_offset(newScale, newOffset);
@ -433,6 +446,13 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event)
if(_drag_sig)
_drag_sig.reset();
if (_hover_hit){
_view.add_cursor(view::Ruler::CursorColor[_view.get_cursorList().size() % 8], _hover_index);
_view.show_cursors(true);
_hover_hit = false;
}
update();
}
@ -457,7 +477,7 @@ void Viewport::wheelEvent(QWheelEvent *event)
if (event->orientation() == Qt::Vertical) {
// Vertical scrolling is interpreted as zooming in/out
const double offset = (_view.session().get_capture_state() == SigSession::Running) ? 0 : event->x();
const double offset = event->x();
_view.zoom(event->delta() / 80, offset);
} else if (event->orientation() == Qt::Horizontal) {
// Horizontal scrolling is interpreted as moving left/right
@ -499,156 +519,178 @@ void Viewport::set_receive_len(quint64 length)
void Viewport::measure()
{
uint64_t sample_rate = _view.session().get_device()->get_sample_rate();
if (_view.session().get_capture_state() == SigSession::Running)
return;
_measure_shown = false;
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);
boost::shared_ptr<view::LogicSignal> logicSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (logicSig = dynamic_pointer_cast<view::LogicSignal>(s)) {
if (logicSig->measure(_view.hover_point(), _cur_sample, _nxt_sample, _thd_sample)) {
_measure_shown = true;
_measure_type = LOGIC;
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();
_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) : "#####";
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;
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();
}
_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;
}
_mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" :
"#####";
mouse_measure();
break;
} else {
_mm_width = "#####";
_mm_period = "#####";
_mm_freq = "#####";
_mm_duty = "#####";
}
mouse_measure();
} else if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)) {
if (_measure_en && dsoSig->measure(_view.hover_point())) {
_measure_shown = true;
_measure_type = DSO;
}
}
}
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 = "#####";
}
_view.on_mouse_moved();
}
void Viewport::paintMeasure(QPainter &p)
{
p.setPen(QColor(17, 133, 209, 255));
p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_aftX, _cur_midY));
p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_preX + 2, _cur_midY - 2));
p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_preX + 2, _cur_midY + 2));
p.drawLine(QLineF(_cur_aftX - 2, _cur_midY - 2, _cur_aftX, _cur_midY));
p.drawLine(QLineF(_cur_aftX - 2, _cur_midY + 2, _cur_aftX, _cur_midY));
if (_thd_sample != 0) {
p.drawLine(QLineF(_cur_aftX, _cur_midY, _cur_thdX, _cur_midY));
p.drawLine(QLineF(_cur_aftX, _cur_midY, _cur_aftX + 2, _cur_midY - 2));
p.drawLine(QLineF(_cur_aftX, _cur_midY, _cur_aftX + 2, _cur_midY + 2));
p.drawLine(QLineF(_cur_thdX - 2, _cur_midY - 2, _cur_thdX, _cur_midY));
p.drawLine(QLineF(_cur_thdX - 2, _cur_midY + 2, _cur_thdX, _cur_midY));
}
_hover_hit = false;
if (_measure_type == LOGIC) {
p.setPen(QColor(17, 133, 209, 255));
p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_aftX, _cur_midY));
p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_preX + 2, _cur_midY - 2));
p.drawLine(QLineF(_cur_preX, _cur_midY, _cur_preX + 2, _cur_midY + 2));
p.drawLine(QLineF(_cur_aftX - 2, _cur_midY - 2, _cur_aftX, _cur_midY));
p.drawLine(QLineF(_cur_aftX - 2, _cur_midY + 2, _cur_aftX, _cur_midY));
if (_thd_sample != 0) {
p.drawLine(QLineF(_cur_aftX, _cur_midY, _cur_thdX, _cur_midY));
p.drawLine(QLineF(_cur_aftX, _cur_midY, _cur_aftX + 2, _cur_midY - 2));
p.drawLine(QLineF(_cur_aftX, _cur_midY, _cur_aftX + 2, _cur_midY + 2));
p.drawLine(QLineF(_cur_thdX - 2, _cur_midY - 2, _cur_thdX, _cur_midY));
p.drawLine(QLineF(_cur_thdX - 2, _cur_midY + 2, _cur_thdX, _cur_midY));
}
if (_measure_en) {
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);
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);
if (_measure_en) {
int typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX,
Qt::AlignLeft | Qt::AlignTop, _mm_width).width();
typical_width = max(typical_width, p.boundingRect(0, 0, INT_MAX, INT_MAX,
Qt::AlignLeft | Qt::AlignTop, _mm_period).width());
typical_width = max(typical_width, p.boundingRect(0, 0, INT_MAX, INT_MAX,
Qt::AlignLeft | Qt::AlignTop, _mm_freq).width());
typical_width = max(typical_width, p.boundingRect(0, 0, INT_MAX, INT_MAX,
Qt::AlignLeft | Qt::AlignTop, _mm_duty).width());
typical_width = typical_width + 100;
p.setPen(Qt::NoPen);
p.setBrush(QColor(17, 133, 209, 150));
p.drawRect(measure_rect);
const double width = _view.get_view_width();
const double height = _view.viewport()->height();
const double left = _view.hover_point().x();
const double top = _view.hover_point().y();
const double right = left + typical_width;
const double bottom = top + 80;
QPointF org_pos = QPointF(right > width ? left - typical_width : left, bottom > height ? top - 80 : top);
QRectF measure_rect = QRectF(org_pos.x(), org_pos.y(), (double)typical_width, 80.0);
QRectF measure1_rect = QRectF(org_pos.x(), org_pos.y(), (double)typical_width, 20.0);
QRectF measure2_rect = QRectF(org_pos.x(), org_pos.y()+20, (double)typical_width, 20.0);
QRectF measure3_rect = QRectF(org_pos.x(), org_pos.y()+40, (double)typical_width, 20.0);
QRectF measure4_rect = QRectF(org_pos.x(), org_pos.y()+60, (double)typical_width, 20.0);
p.setPen(Qt::black);
p.drawText(measure1_rect, Qt::AlignRight | Qt::AlignVCenter,
"Width: " + _mm_width);
p.drawText(measure2_rect, Qt::AlignRight | Qt::AlignVCenter,
"Period: " + _mm_period);
p.drawText(measure3_rect, Qt::AlignRight | Qt::AlignVCenter,
"Frequency: " + _mm_freq);
p.setPen(Qt::NoPen);
p.setBrush(QColor(17, 133, 209, 150));
p.drawRect(measure_rect);
p.setPen(Qt::black);
p.drawText(measure1_rect, Qt::AlignRight | Qt::AlignVCenter,
"Width: " + _mm_width);
p.drawText(measure2_rect, Qt::AlignRight | Qt::AlignVCenter,
"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);
}
} else if (_measure_type == DSO) {
const vector< boost::shared_ptr<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(s)) {
uint64_t index;
double value;
QPointF hpoint;
const int arrow_size = 5;
const int mark_radius = 10;
const int mark_width = 20;
const int mark_cursor_height = 30;
if (dsoSig->get_hover(index, hpoint, value)) {
p.setPen(dsoSig->get_colour());
const QRectF hpoint_rect = QRectF(hpoint.x()-mark_radius/2, hpoint.y()-mark_radius/2, mark_radius, mark_radius);
if (hpoint_rect.contains(_view.hover_point())) {
p.setBrush(dsoSig->get_colour());
const int cursor_up = hpoint.y()-mark_cursor_height;
const int cursor_dn = hpoint.y()+mark_cursor_height;
const int cursor_lf = hpoint.x()-arrow_size;
const int cursor_md = hpoint.x();
const int cursor_rt = hpoint.x()+arrow_size;
const QPointF up_arrow[3] = {
QPointF(cursor_lf, cursor_up+arrow_size),
QPointF(cursor_md, cursor_up),
QPointF(cursor_rt, cursor_up+arrow_size),
};
const QPointF dn_arrow[3] = {
QPointF(cursor_lf, cursor_dn-arrow_size),
QPointF(cursor_md, cursor_dn),
QPointF(cursor_rt, cursor_dn-arrow_size),
};
p.drawPolyline(up_arrow, 3);
p.drawPolyline(dn_arrow, 3);
p.drawLine(cursor_md, cursor_up, cursor_md, cursor_dn);
_hover_hit = true;
_hover_index = index;
} else {
p.setBrush(Qt::NoBrush);
}
p.drawEllipse(hpoint, mark_radius, mark_radius);
QString value_c = abs(value) > 1000 ? QString::number(value/1000.0, 'f', 2) + "V" : QString::number(value, 'f', 2) + "mV";
int value_width = p.boundingRect(0, 0, INT_MAX, INT_MAX,
Qt::AlignLeft | Qt::AlignTop, value_c).width();
const bool right = dsoSig->get_index()%2 ? hpoint.x() < value_width : hpoint.x() < _view.get_view_width() - value_width;
const bool up = hpoint.y() > 50;
const QPointF hpoint_sec = QPointF(hpoint.x() - (right ? -mark_width : mark_width), hpoint.y() - (up ? mark_width : -mark_width));
p.drawLine(hpoint, hpoint_sec);
p.drawLine(hpoint_sec, QPointF(hpoint_sec.x() + (right ? value_width : -value_width), hpoint_sec.y()));
p.drawText(QRectF(right ? hpoint_sec.x() : hpoint_sec.x() - value_width, hpoint_sec.y() - mark_width, value_width, mark_width),
Qt::AlignLeft | Qt::AlignBottom,
value_c);
}
}
}
}
}
QString Viewport::get_mm_width()
QString Viewport::get_measure(QString option)
{
return _mm_width;
}
QString Viewport::get_mm_period()
{
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)

View File

@ -47,7 +47,7 @@ class Viewport : public QWidget
public:
static const int HitCursorMargin = 10;
static const double HitCursorTimeMargin = 0.3;
static const double HitCursorTimeMargin;
public:
explicit Viewport(View &parent);
@ -56,11 +56,7 @@ public:
QPoint get_mouse_point() const;
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);
@ -87,11 +83,15 @@ private:
private slots:
void on_traces_moved();
void on_trigger_timer();
void set_receive_len(quint64 length);
signals:
void mouse_measure();
private:
View &_view;
quint64 _total_receive_len;
uint64_t _total_receive_len;
QPoint _mouse_point;
QPoint _mouse_down_point;
double _mouse_down_offset;
@ -106,22 +106,27 @@ private:
bool _measure_en;
bool _measure_shown;
int _measure_type;
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;
int timer_cnt;
boost::shared_ptr<Signal> _drag_sig;
uint64_t _hover_index;
bool _hover_hit;
};
} // namespace view

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -261,7 +261,7 @@ static int sanity_check_all_input_modules(void)
static int sanity_check_all_output_modules(void)
{
int i, errors, ret = SR_OK;
struct sr_output_format **outputs;
struct sr_output_module **outputs;
const char *d;
sr_spew("Sanity-checking all output modules.");
@ -276,18 +276,18 @@ static int sanity_check_all_output_modules(void)
sr_err("No ID in module %d ('%s').", i, d);
errors++;
}
if (!outputs[i]->description) {
if (!outputs[i]->desc) {
sr_err("No description in module %d ('%s').", i, d);
errors++;
}
if (outputs[i]->df_type < 10000 || outputs[i]->df_type > 10007) {
/*if (outputs[i]->df_type < 10000 || outputs[i]->df_type > 10007) {
sr_err("Invalid df_type %d in module %d ('%s').",
outputs[i]->df_type, i, d);
errors++;
}
}*/
/* All modules must provide a data or recv API callback. */
if (!outputs[i]->data && !outputs[i]->receive) {
if (!outputs[i]->receive) {
sr_err("No data/receive in module %d ('%s').", i, d);
errors++;
}

View File

@ -227,7 +227,6 @@ AC_CONFIG_FILES([Makefile version.h hardware/Makefile
hardware/DSL/Makefile
input/Makefile
output/Makefile
output/text/Makefile
libsigrok4DSL.pc
tests/Makefile
])

View File

@ -249,9 +249,9 @@ static int fpga_setting(const struct sr_dev_inst *sdi)
((sdi->mode == ANALOG) << 7) +
((devc->filter == SR_FILTER_1T) << 8) +
(devc->instant << 9) + (devc->zero << 10);
setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate);
setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt);
setting.count = (uint32_t)(devc->limit_samples / (channel_cnt / channel_en_cnt));
setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0f * devc->limit_samples);
setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples);
setting.trig_glb = trigger->trigger_stages;
setting.trig_adp = setting.count - setting.trig_pos - 1;
setting.trig_sda = 0x0;
@ -601,6 +601,7 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes)
return SR_ERR;
if (sdi->mode == DSO) {
probe->vdiv = 1000;
probe->vfactor = 1;
probe->vpos = 0;
probe->coupling = SR_DC_COUPLING;
probe->trig_value = 0x80;
@ -846,7 +847,7 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int
channel_cnt += probe->enabled;
}
cmd += 0x18;
uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate);
uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_cnt);
cmd += divider << 8;
break;
case SR_CONF_HORIZ_TRIGGERPOS:
@ -1173,6 +1174,11 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
return SR_ERR;
*data = g_variant_new_uint64(ch->vdiv);
break;
case SR_CONF_FACTOR:
if (!ch)
return SR_ERR;
*data = g_variant_new_uint64(ch->vfactor);
break;
case SR_CONF_VPOS:
if (!ch)
return SR_ERR;
@ -1421,6 +1427,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
else
sr_dbg("%s: setting VDIV of channel %d to %d mv failed",
__func__, ch->index, ch->vdiv);
} else if (id == SR_CONF_FACTOR) {
ch->vfactor = g_variant_get_uint64(data);
} else if (id == SR_CONF_VPOS) {
ch->vpos = g_variant_get_double(data);
if (sdi->mode == DSO) {
@ -1485,7 +1493,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
struct sr_channel *probe = (struct sr_channel *)l->data;
channel_cnt += probe->enabled;
}
devc->trigger_hpos = g_variant_get_uint16(data) * channel_cnt * devc->limit_samples / 200.0f;
devc->trigger_hpos = g_variant_get_uint16(data) * channel_cnt * devc->limit_samples / 200.0;
if (sdi->mode == DSO) {
ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS));
}
@ -1853,11 +1861,12 @@ static void receive_transfer(struct libusb_transfer *transfer)
mstatus.ch0_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 1*2);
mstatus.ch0_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 3);
mstatus.ch0_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 2/2);
mstatus.ch0_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 4/2);
mstatus.ch1_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 7*2);
mstatus.ch1_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 15);
mstatus.ch1_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 8/2);
mstatus.ch1_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 10/2);
mstatus.ch0_period += ((uint64_t)*((const uint32_t*)cur_buf + mstatus_offset/2 + 4/2)) << 32;
mstatus.ch0_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 6/2);
mstatus.ch1_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 9*2);
mstatus.ch1_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 19);
mstatus.ch1_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 10/2);
mstatus.ch1_period += ((uint64_t)*((const uint32_t*)cur_buf + mstatus_offset/2 + 12/2)) << 32;
mstatus.vlen = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x7fffffff;
mstatus.stream_mode = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x80000000;
mstatus.sample_divider = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2);
@ -1879,7 +1888,7 @@ static void receive_transfer(struct libusb_transfer *transfer)
mstatus.vlen = instant_buffer_size;
}
const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate);
const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSCOPE_MAX_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt);
if ((mstatus.sample_divider == divider &&
mstatus.vlen != 0 &&
mstatus.vlen <= (transfer->actual_length - 512) / sample_width) ||
@ -2001,7 +2010,7 @@ static unsigned int get_number_of_transfers(struct DSL_context *devc)
total_buffer_time * to_bytes_per_ms(devc));
/* Total buffer size should be able to hold about 500ms of data. */
//n = 500 * to_bytes_per_ms(devc) / get_buffer_size(devc);
n = ceil(total_size * 1.0f / get_buffer_size(devc));
n = ceil(total_size * 1.0 / get_buffer_size(devc));
if (n > NUM_SIMUL_TRANSFERS)
return NUM_SIMUL_TRANSFERS;

View File

@ -287,9 +287,12 @@ static int fpga_setting(const struct sr_dev_inst *sdi)
((sdi->mode == ANALOG) << 7) +
((devc->filter == SR_FILTER_1T) << 8) +
(devc->instant << 9) + (devc->zero << 10);
setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate);
if (sdi->mode == DSO)
setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt);
else
setting.divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_LOGIC_SAMPLERATE * 1.0 / devc->cur_samplerate);
setting.count = (sdi->mode == DSO) ? (uint32_t)(devc->limit_samples / (channel_cnt / channel_en_cnt)) : (uint32_t)(devc->limit_samples);
setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0f * devc->limit_samples);
setting.trig_pos = (uint32_t)(trigger->trigger_pos / 100.0 * devc->limit_samples);
setting.trig_glb = trigger->trigger_stages;
setting.trig_adp = setting.count - setting.trig_pos - 1;
setting.trig_sda = 0x0;
@ -642,6 +645,7 @@ static int set_probes(struct sr_dev_inst *sdi, int num_probes)
return SR_ERR;
if (sdi->mode == DSO) {
probe->vdiv = 1000;
probe->vfactor = 1;
probe->coupling = SR_DC_COUPLING;
probe->trig_value = 0x80;
}
@ -881,7 +885,7 @@ static uint64_t dso_cmd_gen(struct sr_dev_inst *sdi, struct sr_channel* ch, int
channel_cnt += probe->enabled;
}
cmd += 0x18;
uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate);
uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_cnt);
cmd += divider << 8;
break;
case SR_CONF_HORIZ_TRIGGERPOS:
@ -1156,6 +1160,11 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
return SR_ERR;
*data = g_variant_new_uint64(ch->vdiv);
break;
case SR_CONF_FACTOR:
if (!ch)
return SR_ERR;
*data = g_variant_new_uint64(ch->vfactor);
break;
case SR_CONF_TIMEBASE:
if (!sdi)
return SR_ERR;
@ -1518,6 +1527,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
else
sr_dbg("%s: setting VDIV of channel %d to %d mv failed",
__func__, ch->index, ch->vdiv);
} else if (id == SR_CONF_FACTOR) {
ch->vfactor = g_variant_get_uint64(data);
} else if (id == SR_CONF_TIMEBASE) {
devc->timebase = g_variant_get_uint64(data);
} else if (id == SR_CONF_COUPLING) {
@ -1574,9 +1585,9 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
struct sr_channel *probe = (struct sr_channel *)l->data;
channel_cnt += probe->enabled;
}
devc->trigger_hpos = g_variant_get_uint16(data) * channel_cnt * devc->limit_samples / 200.0f;
devc->trigger_hpos = g_variant_get_uint16(data) * channel_cnt * devc->limit_samples / 200.0;
} else {
devc->trigger_hpos = g_variant_get_uint16(data) * devc->limit_samples / 100.0f;
devc->trigger_hpos = g_variant_get_uint16(data) * devc->limit_samples / 100.0;
}
if (sdi->mode == DSO) {
ret = command_dso_ctrl(usb->devhdl, dso_cmd_gen(sdi, 1, SR_CONF_HORIZ_TRIGGERPOS));
@ -1935,11 +1946,13 @@ static void receive_transfer(struct libusb_transfer *transfer)
mstatus.ch0_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 1*2);
mstatus.ch0_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 3);
mstatus.ch0_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 2/2);
mstatus.ch0_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 4/2);
mstatus.ch1_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 7*2);
mstatus.ch1_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 15);
mstatus.ch1_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 8/2);
mstatus.ch1_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 10/2);
mstatus.ch0_period += *((const uint32_t*)cur_buf + mstatus_offset/2 + 4/2) << 32;
mstatus.ch0_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 6/2);
mstatus.ch1_max = *((const uint8_t*)cur_buf + mstatus_offset*2 + 9*2);
mstatus.ch1_min = *((const uint8_t*)cur_buf + mstatus_offset*2 + 19);
mstatus.ch1_period = *((const uint32_t*)cur_buf + mstatus_offset/2 + 10/2);
mstatus.ch1_period += *((const uint32_t*)cur_buf + mstatus_offset/2 + 12/2) << 32;
mstatus.ch1_pcnt = *((const uint32_t*)cur_buf + mstatus_offset/2 + 14/2);
mstatus.vlen = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x7fffffff;
mstatus.stream_mode = *((const uint32_t*)cur_buf + mstatus_offset/2 + 16/2) & 0x80000000;
mstatus.sample_divider = *((const uint32_t*)cur_buf + mstatus_offset/2 + 18/2);
@ -1954,7 +1967,7 @@ static void receive_transfer(struct libusb_transfer *transfer)
} else {
mstatus.vlen = instant_buffer_size;
}
const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(SR_MHZ(100) * 1.0 / devc->cur_samplerate);
const uint32_t divider = devc->zero ? 0x1 : (uint32_t)ceil(DSLOGIC_MAX_DSO_SAMPLERATE * 1.0 / devc->cur_samplerate / channel_en_cnt);
if ((mstatus.sample_divider == divider &&
mstatus.vlen != 0 &&
mstatus.vlen <= (transfer->actual_length - 512) / sample_width) ||

View File

@ -344,6 +344,9 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
case SR_CONF_VDIV:
*data = g_variant_new_uint64(ch->vdiv);
break;
case SR_CONF_FACTOR:
*data = g_variant_new_uint64(ch->vfactor);
break;
case SR_CONF_TIMEBASE:
*data = g_variant_new_uint64(devc->timebase);
break;
@ -424,6 +427,7 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
ret = SR_ERR;
else {
probe->vdiv = 1000;
probe->vfactor = 1;
probe->coupling = SR_DC_COUPLING;
probe->trig_value = 0x80;
sdi->channels = g_slist_append(sdi->channels, probe);
@ -472,6 +476,11 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi,
sr_dbg("%s: setting VDIV of channel %d to %" PRIu64, __func__,
ch->index, ch->vdiv);
ret = SR_OK;
} else if (id == SR_CONF_FACTOR) {
ch->vfactor = g_variant_get_uint64(data);
sr_dbg("%s: setting FACTOR of channel %d to %" PRIu64, __func__,
ch->index, ch->vfactor);
ret = SR_OK;
} else if (id == SR_CONF_TIMEBASE) {
devc->timebase = g_variant_get_uint64(data);
sr_dbg("%s: setting TIMEBASE to %" PRIu64, __func__,
@ -601,8 +610,8 @@ static void samples_generator(uint16_t *buf, uint64_t size,
case PATTERN_TRIANGLE:
for (i = 0; i < size; i++) {
if (i%CONST_LEN == 0) {
demo_data = p > 0x7fff ? 0x40 * (1 + (0x8000 - p * 1.0f) / 0x8000) :
0x40 * (p * 1.0f / 0x8000);
demo_data = p > 0x7fff ? 0x40 * (1 + (0x8000 - p * 1.0) / 0x8000) :
0x40 * (p * 1.0 / 0x8000);
p += CONST_LEN * 10;
}
*(buf + i) = demo_data + (demo_data << 8);
@ -654,7 +663,7 @@ static void samples_generator(uint16_t *buf, uint64_t size,
case PATTERN_RANDOM: /* Random */
for (i = 0; i < size; i++) {
if (i%CONST_LEN == 0)
demo_data = (uint16_t)(rand() * (0x40 * 1.0f / RAND_MAX));
demo_data = (uint16_t)(rand() * (0x40 * 1.0 / RAND_MAX));
*(buf + i) = demo_data + (demo_data << 8);
GSList *l;
struct sr_channel *probe;

View File

@ -83,6 +83,8 @@ static struct sr_config_info sr_config_info_data[] = {
"Filter Targets", NULL},
{SR_CONF_VDIV, SR_T_RATIONAL_VOLT, "vdiv",
"Volts/div", NULL},
{SR_CONF_VDIV, SR_T_RATIONAL_VOLT, "factor",
"Probe Factor", NULL},
{SR_CONF_COUPLING, SR_T_CHAR, "coupling",
"Coupling", NULL},
{SR_CONF_DATALOG, SR_T_BOOL, "datalog",

View File

@ -32,7 +32,7 @@
#define WINVER 0x0501
#define _WIN32_WINNT WINVER
#include <Winsock2.h>
#include <ddk/usbiodef.h>
#include <usbiodef.h>
#endif
#ifdef __cplusplus
@ -323,7 +323,7 @@ struct sr_datafeed_dso {
uint64_t mqflags;
/** The analog value(s). The data is interleaved according to
* the probes list. */
float *data;
void *data;
};
struct sr_datafeed_analog {
@ -389,7 +389,7 @@ struct sr_input_format {
/**
* Load a file, parsing the input according to the file's format.
*
*
* This function will send datafeed packets to the session bus, so
* the calling frontend must have registered its session callbacks
* beforehand.
@ -404,7 +404,7 @@ struct sr_input_format {
* the responsibility of the caller to free it later.
* @param filename The name (and path) of the file to use.
*
* @return SR_OK upon success, a negative error code upon failure.
* @return SR_OK upon succcess, a negative error code upon failure.
*/
int (*loadfile) (struct sr_input *in, const char *filename);
};
@ -415,7 +415,7 @@ struct sr_output {
* A pointer to this output format's 'struct sr_output_format'.
* The frontend can use this to call the module's callbacks.
*/
struct sr_output_format *format;
struct sr_output_module *module;
/**
* The device for which this output module is creating output. This
@ -437,29 +437,57 @@ struct sr_output {
* For example, the module might store a pointer to a chunk of output
* there, and only flush it when it reaches a certain size.
*/
void *internal;
void *priv;
};
struct sr_output_format {
/** Generic option struct used by various subsystems. */
struct sr_option {
/* Short name suitable for commandline usage, [a-z0-9-]. */
char *id;
/* Short name suitable for GUI usage, can contain UTF-8. */
char *name;
/* Description of the option, in a sentence. */
char *desc;
/* Default value for this option. */
GVariant *def;
/* List of possible values, if this is an option with few values. */
GSList *values;
};
/** Output module driver. */
struct sr_output_module {
/**
* A unique ID for this output format. Must not be NULL.
*
* It can be used by frontends to select this output format for use.
*
* For example, calling sigrok-cli with <code>-O hex</code> will
* select the hexadecimal text output format.
* A unique ID for this output module, suitable for use in command-line
* clients, [a-z0-9-]. Must not be NULL.
*/
char *id;
/**
* A short description of the output format. Must not be NULL.
* A unique name for this output module, suitable for use in GUI
* clients, can contain UTF-8. Must not be NULL.
*/
const char *name;
/**
* A short description of the output module. Must not be NULL.
*
* This can be displayed by frontends, e.g. when selecting the output
* format for saving a file.
* module for saving a file.
*/
char *description;
char *desc;
int df_type;
/**
* A NULL terminated array of strings containing a list of file name
* extensions typical for the input file format, or NULL if there is
* no typical extension for this file format.
*/
const char *const *exts;
/**
* Returns a NULL-terminated list of options this module can take.
* Can be NULL, if the module has no options.
*/
const struct sr_option *(*options) (void);
/**
* This function is called once, at the beginning of an output stream.
@ -473,73 +501,10 @@ struct sr_output_format {
*
* @param o Pointer to the respective 'struct sr_output'.
*
* @return SR_OK upon success, a negative error code otherwise.
* @retval SR_OK Success
* @retval other Negative error code.
*/
int (*init) (struct sr_output *o);
/**
* Whenever a chunk of data comes in, it will be passed to the
* output module via this function. The <code>data_in</code> and
* <code>length_in</code> values refers to this data; the module
* must not alter or g_free() this buffer.
*
* The function must allocate a buffer for storing its output, and
* pass along a pointer to this buffer in the <code>data_out</code>
* parameter, as well as storing the length of the buffer in
* <code>length_out</code>. The calling frontend will g_free()
* this buffer when it's done with it.
*
* IMPORTANT: The memory allocation much happen using a glib memory
* allocation call (not a "normal" malloc) since g_free() will be
* used to free the memory!
*
* If there is no output, this function MUST store NULL in the
* <code>data_out</code> parameter, so the caller knows not to try
* and g_free() it.
*
* Note: This API call is obsolete, use receive() instead.
*
* @param o Pointer to the respective 'struct sr_output'.
* @param data_in Pointer to the input data buffer.
* @param length_in Length of the input.
* @param data_out Pointer to the allocated output buffer.
* @param length_out Length (in bytes) of the output.
*
* @return SR_OK upon success, a negative error code otherwise.
*/
int (*data) (struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out);
/**
* This function is called when an event occurs in the datafeed
* which the output module may need to be aware of. No data is
* passed in, only the fact that the event occurs. The following
* events can currently be passed in:
*
* - SR_DF_TRIGGER: At this point in the datafeed, the trigger
* matched. The output module may mark this in some way, e.g. by
* plotting a red line on a graph.
*
* - SR_DF_END: This marks the end of the datafeed. No more calls
* into the output module will be done, so this is a good time to
* free up any memory used to keep state, for example.
*
* Any output generated by this function must have a reference to
* it stored in the <code>data_out</code> and <code>length_out</code>
* parameters, or NULL if no output was generated.
*
* Note: This API call is obsolete, use receive() instead.
*
* @param o Pointer to the respective 'struct sr_output'.
* @param event_type Type of event that occured.
* @param data_out Pointer to the allocated output buffer.
* @param length_out Length (in bytes) of the output.
*
* @return SR_OK upon success, a negative error code otherwise.
*/
int (*event) (struct sr_output *o, int event_type, uint8_t **data_out,
uint64_t *length_out);
int (*init) (struct sr_output *o, GHashTable *options);
/**
* This function is passed a copy of every packed in the data feed.
@ -556,9 +521,10 @@ struct sr_output_format {
* @param out A pointer where a GString * should be stored if
* the module generates output, or NULL if not.
*
* @return SR_OK upon success, a negative error code otherwise.
* @retval SR_OK Success
* @retval other Negative error code.
*/
int (*receive) (struct sr_output *o, const struct sr_dev_inst *sdi,
int (*receive) (const struct sr_output *o,
const struct sr_datafeed_packet *packet, GString **out);
/**
@ -566,11 +532,13 @@ struct sr_output_format {
* the output module, and can be used to free any internal
* resources the module may keep.
*
* @return SR_OK upon success, a negative error code otherwise.
* @retval SR_OK Success
* @retval other Negative error code.
*/
int (*cleanup) (struct sr_output *o);
};
enum {
SR_CHANNEL_LOGIC = 10000,
SR_CHANNEL_DSO,
@ -591,6 +559,7 @@ struct sr_channel {
char *name;
char *trigger;
uint64_t vdiv;
uint16_t vfactor;
double vpos;
uint8_t coupling;
uint8_t trig_value;
@ -641,11 +610,11 @@ struct sr_status {
uint8_t ch0_max;
uint8_t ch0_min;
uint32_t ch0_period;
uint64_t ch0_period;
uint32_t ch0_pcnt;
uint8_t ch1_max;
uint8_t ch1_min;
uint32_t ch1_period;
uint64_t ch1_period;
uint32_t ch1_pcnt;
uint32_t vlen;
@ -798,6 +767,9 @@ enum {
/** Channel enable for dso channel. */
SR_CONF_EN_CH,
/** probe factor for dso channel. */
SR_CONF_FACTOR,
/** Trigger types. */
SR_CONF_TRIGGER_TYPE,

View File

@ -17,21 +17,19 @@
## along with this program. If not, see <http://www.gnu.org/licenses/>.
##
SUBDIRS = text
# Local lib, this is NOT meant to be installed!
noinst_LTLIBRARIES = libsigrok4DSLoutput.la
libsigrok4DSLoutput_la_SOURCES = \
out_binary.c \
out_vcd.c \
out_csv.c \
out_analog.c \
output.c
output.c \
csv.c \
vcd.c \
gnuplot.c \
srzip.c
libsigrok4DSLoutput_la_CFLAGS = \
-I$(top_srcdir)
libsigrok4DSLoutput_la_LIBADD = \
text/libsigrok4DSLoutputtext.la
#libsigrok4DSLogicoutput_la_LIBADD = \
# text/libsigrok4DSLogicoutputtext.la

283
libsigrok4DSL/output/csv.c Normal file
View File

@ -0,0 +1,283 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
*
* 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 <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE_STRING and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
#define LOG_PREFIX "output/csv"
struct context {
unsigned int num_enabled_channels;
uint64_t samplerate;
char separator;
gboolean header_done;
int *channel_index;
float *channel_vdiv;
double *channel_vpos;
uint64_t timebase;
uint64_t mask;
uint64_t pre_data;
uint64_t index;
int type;
};
/*
* TODO:
* - Option to specify delimiter character and/or string.
* - Option to (not) print metadata as comments.
* - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
* - Option to (not) print samplenumber / time as extra column.
* - Option to "compress" output (only print changed samples, VCD-like).
* - Option to print comma-separated bits, or whole bytes/words (for 8/16
* channel LAs) as ASCII/hex etc. etc.
* - Trigger support.
*/
static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
int i;
if (!o || !o->sdi)
return SR_ERR_ARG;
ctx = g_malloc0(sizeof(struct context));
o->priv = ctx;
ctx->separator = ',';
ctx->mask = 0;
ctx->index = 0;
ctx->type = g_variant_get_int16(g_hash_table_lookup(options, "type"));
ctx->timebase = g_variant_get_uint64(g_hash_table_lookup(options, "timebase"));
/* Get the number of channels, and the unitsize. */
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != ctx->type)
continue;
if (!ch->enabled)
continue;
ctx->num_enabled_channels++;
}
ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
ctx->channel_vdiv = g_malloc(sizeof(float) * ctx->num_enabled_channels);
ctx->channel_vpos = g_malloc(sizeof(double) * ctx->num_enabled_channels);
/* Once more to map the enabled channels. */
for (i = 0, l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != ctx->type)
continue;
if (!ch->enabled)
continue;
ctx->channel_index[i] = ch->index;
ctx->mask |= (1 << ch->index);
ctx->channel_vdiv[i] = ch->vdiv * ch->vfactor >= 500 ? ch->vdiv * ch->vfactor / 100.0f : ch->vdiv * ch->vfactor * 10.0f;
ctx->channel_vpos[i] = ch->vdiv * ch->vfactor >= 500 ? ch->vpos / 1000 : ch->vpos;
i++;
}
return SR_OK;
}
static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
GVariant *gvar;
GString *header;
GSList *l;
time_t t;
int num_channels, i;
ctx = o->priv;
header = g_string_sized_new(512);
/* Some metadata */
t = time(NULL);
g_string_append_printf(header, "; CSV, generated by %s on %s",
PACKAGE_STRING, ctime(&t));
/* Columns / channels */
if (ctx->type == SR_CHANNEL_LOGIC)
num_channels = g_slist_length(o->sdi->channels);
else
num_channels = ctx->num_enabled_channels;
g_string_append_printf(header, "; Channels (%d/%d)\n",
ctx->num_enabled_channels, num_channels);
if (ctx->samplerate == 0) {
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
&gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
}
}
if (ctx->samplerate != 0) {
char *samplerate_s = sr_samplerate_string(ctx->samplerate);
g_string_append_printf(header, "; Sample rate: %s\n", samplerate_s);
g_free(samplerate_s);
}
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_LIMIT_SAMPLES,
&gvar) == SR_OK) {
uint64_t depth = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
char *depth_s = sr_samplecount_string(depth);
g_string_append_printf(header, "; Sample count: %s\n", depth_s);
g_free(depth_s);
}
if (ctx->type == SR_CHANNEL_LOGIC)
g_string_append_printf(header, "Time(s),");
for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
ch = l->data;
if (ch->type != ctx->type)
continue;
if (!ch->enabled)
continue;
if (ctx->type == SR_CHANNEL_DSO) {
char *unit_s = (ch->vdiv * ch->vfactor) >= 500 ? "V" : "mV";
g_string_append_printf(header, " %s (Unit: %s),", ch->name, unit_s);
} else {
g_string_append_printf(header, " %s,", ch->name);
}
}
if (o->sdi->channels)
/* Drop last separator. */
g_string_truncate(header, header->len - 1);
g_string_append_printf(header, "\n");
return header;
}
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
const struct sr_datafeed_logic *logic;
const struct sr_datafeed_dso *dso;
const struct sr_config *src;
GSList *l;
struct context *ctx;
int idx;
uint64_t i, j;
unsigned char *p, c;
*out = NULL;
if (!o || !o->sdi)
return SR_ERR_ARG;
if (!(ctx = o->priv))
return SR_ERR_ARG;
switch (packet->type) {
case SR_DF_META:
meta = packet->payload;
for (l = meta->config; l; l = l->next) {
src = l->data;
if (src->key != SR_CONF_SAMPLERATE)
continue;
ctx->samplerate = g_variant_get_uint64(src->data);
}
break;
case SR_DF_LOGIC:
logic = packet->payload;
if (!ctx->header_done) {
*out = gen_header(o);
ctx->header_done = TRUE;
} else {
*out = g_string_sized_new(512);
}
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
ctx->index++;
if (ctx->index > 1 && (*(uint64_t *)(logic->data + i) & ctx->mask) == ctx->pre_data)
continue;
g_string_append_printf(*out, "%0.10g", (ctx->index-1)*1.0/ctx->samplerate);
for (j = 0; j < ctx->num_enabled_channels; j++) {
idx = ctx->channel_index[j];
p = logic->data + i + idx / 8;
c = *p & (1 << (idx % 8));
g_string_append_c(*out, ctx->separator);
g_string_append_c(*out, c ? '1' : '0');
}
g_string_append_printf(*out, "\n");
ctx->pre_data = (*(uint64_t *)(logic->data + i) & ctx->mask);
}
break;
case SR_DF_DSO:
dso = packet->payload;
if (!ctx->header_done) {
*out = gen_header(o);
ctx->header_done = TRUE;
} else {
*out = g_string_sized_new(512);
}
for (i = 0; i < dso->num_samples; i++) {
for (j = 0; j < ctx->num_enabled_channels; j++) {
idx = ctx->channel_index[j];
p = dso->data + i * ctx->num_enabled_channels + idx * ((ctx->num_enabled_channels > 1) ? 1 : 0);
g_string_append_printf(*out, "%0.2f", (128 - *p) * ctx->channel_vdiv[j] / 255 - ctx->channel_vpos[j]);
g_string_append_c(*out, ctx->separator);
}
/* Drop last separator. */
g_string_truncate(*out, (*out)->len - 1);
g_string_append_printf(*out, "\n");
}
break;
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->sdi)
return SR_ERR_ARG;
if (o->priv) {
ctx = o->priv;
g_free(ctx->channel_index);
g_free(o->priv);
o->priv = NULL;
}
return SR_OK;
}
SR_PRIV struct sr_output_module output_csv = {
.id = "csv",
.name = "CSV",
.desc = "Comma-separated values",
.exts = (const char*[]){"csv", NULL},
.options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

@ -0,0 +1,229 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* 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 <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE_STRING and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
#define LOG_PREFIX "output/gnuplot"
struct context {
unsigned int num_enabled_channels;
uint64_t samplerate;
uint64_t samplecount;
gboolean header_done;
uint8_t *prevsample;
int *channel_index;
};
static const char *gnuplot_header = "\
# Sample data in space-separated columns format usable by gnuplot.\n";
static const char *gnuplot_header2 = "\
#\n# Column\tChannel\n\
# -----------------------------------------------------------------------------\n\
# 0\t\tSample counter (for internal gnuplot purposes)\n";
static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
unsigned int i;
(void)options;
if (!o || !o->sdi)
return SR_ERR_ARG;
ctx = g_malloc0(sizeof(struct context));
o->priv = ctx;
ctx->num_enabled_channels = 0;
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
ctx->num_enabled_channels++;
}
if (ctx->num_enabled_channels <= 0) {
sr_err("No logic channel enabled.");
return SR_ERR;
}
ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
/* Once more to map the enabled channels. */
for (i = 0, l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
ctx->channel_index[i++] = ch->index;
}
return SR_OK;
}
static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
GVariant *gvar;
GString *header;
time_t t;
unsigned int num_channels, i;
char *samplerate_s;
ctx = o->priv;
if (ctx->samplerate == 0) {
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
&gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
}
}
t = time(NULL);
header = g_string_sized_new(512);
g_string_printf(header, "%s", gnuplot_header);
g_string_append_printf(header, "# Generated by %s on %s",
PACKAGE_STRING, ctime(&t));
num_channels = g_slist_length(o->sdi->channels);
g_string_append_printf(header, "# Acquisition with %d/%d channels",
ctx->num_enabled_channels, num_channels);
if (ctx->samplerate != 0) {
samplerate_s = sr_samplerate_string(ctx->samplerate);
g_string_append_printf(header, " at %s", samplerate_s);
g_free(samplerate_s);
}
g_string_append_printf(header, "\n");
g_string_append_printf(header, "%s", gnuplot_header2);
/* Columns / channels */
for (i = 0; i < ctx->num_enabled_channels; i++) {
ch = g_slist_nth_data(o->sdi->channels, ctx->channel_index[i]);
g_string_append_printf(header, "# %d\t\t%s\n", i + 1, ch->name);
}
return header;
}
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
const struct sr_datafeed_logic *logic;
const struct sr_config *src;
GSList *l;
struct context *ctx;
const uint8_t *sample;
unsigned int curbit, p, idx, i;
*out = NULL;
if (!o || !o->priv)
return SR_ERR_BUG;
ctx = o->priv;
if (packet->type == SR_DF_META) {
meta = packet->payload;
for (l = meta->config; l; l = l->next) {
src = l->data;
if (src->key != SR_CONF_SAMPLERATE)
continue;
ctx->samplerate = g_variant_get_uint64(src->data);
}
}
if (packet->type != SR_DF_LOGIC)
return SR_OK;
logic = packet->payload;
if (!ctx->prevsample) {
/* Can't allocate this until we know the stream's unitsize. */
ctx->prevsample = g_malloc0(logic->unitsize);
}
if (!ctx->header_done) {
*out = gen_header(o);
ctx->header_done = TRUE;
} else {
*out = g_string_sized_new(512);
}
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
sample = logic->data + i;
ctx->samplecount++;
/*
* Don't output the same sample multiple times, but make
* sure to output at least the first and last sample.
*/
if (i > 0 && i < logic->length - logic->unitsize) {
if (!memcmp(sample, ctx->prevsample, logic->unitsize))
continue;
}
memcpy(ctx->prevsample, sample, logic->unitsize);
/* The first column is a counter (needed for gnuplot). */
g_string_append_printf(*out, "%" PRIu64 "\t", ctx->samplecount);
/* The next columns are the values of all channels. */
for (p = 0; p < ctx->num_enabled_channels; p++) {
idx = ctx->channel_index[p];
curbit = (sample[idx / 8] & ((uint8_t) (1 << (idx % 8)))) >> (idx % 8);
g_string_append_printf(*out, "%d ", curbit);
}
g_string_append_printf(*out, "\n");
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->priv)
return SR_ERR_BUG;
ctx = o->priv;
g_free(ctx->channel_index);
g_free(ctx->prevsample);
g_free(ctx);
return SR_OK;
}
SR_PRIV struct sr_output_module output_gnuplot = {
.id = "gnuplot",
.name = "Gnuplot",
.desc = "Gnuplot data file format",
.exts = (const char*[]){"dat", NULL},
.options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

@ -1,251 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/analog: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
struct context {
int num_enabled_probes;
GPtrArray *probelist;
};
static int init(struct sr_output *o)
{
struct context *ctx;
struct sr_channel *probe;
GSList *l;
sr_spew("Initializing output module.");
if (!o || !o->sdi)
return SR_ERR_ARG;
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
sr_err("Output module context malloc failed.");
return SR_ERR_MALLOC;
}
o->internal = ctx;
/* Get the number of probes and their names. */
ctx->probelist = g_ptr_array_new();
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (!probe || !probe->enabled)
continue;
g_ptr_array_add(ctx->probelist, probe->name);
ctx->num_enabled_probes++;
}
return SR_OK;
}
static void si_printf(float value, GString *out, char *unitstr)
{
float v;
if (signbit(value))
v = -(value);
else
v = value;
if (v < 1e-12 || v > 1e+12)
g_string_append_printf(out, "%f %s", value, unitstr);
else if (v > 1e+9)
g_string_append_printf(out, "%f G%s", value / 1e+9, unitstr);
else if (v > 1e+6)
g_string_append_printf(out, "%f M%s", value / 1e+6, unitstr);
else if (v > 1e+3)
g_string_append_printf(out, "%f k%s", value / 1e+3, unitstr);
else if (v < 1e-9)
g_string_append_printf(out, "%f n%s", value * 1e+9, unitstr);
else if (v < 1e-6)
g_string_append_printf(out, "%f u%s", value * 1e+6, unitstr);
else if (v < 1e-3)
g_string_append_printf(out, "%f m%s", value * 1e+3, unitstr);
else
g_string_append_printf(out, "%f %s", value, unitstr);
}
static void fancyprint(int unit, int mqflags, float value, GString *out)
{
switch (unit) {
case SR_UNIT_VOLT:
si_printf(value, out, "V");
break;
case SR_UNIT_AMPERE:
si_printf(value, out, "A");
break;
case SR_UNIT_OHM:
si_printf(value, out, "");
g_string_append_unichar(out, 0x2126);
break;
case SR_UNIT_FARAD:
si_printf(value, out, "F");
break;
case SR_UNIT_KELVIN:
si_printf(value, out, "K");
break;
case SR_UNIT_CELSIUS:
si_printf(value, out, "");
g_string_append_unichar(out, 0x00b0);
g_string_append_c(out, 'C');
break;
case SR_UNIT_FAHRENHEIT:
si_printf(value, out, "");
g_string_append_unichar(out, 0x00b0);
g_string_append_c(out, 'F');
break;
case SR_UNIT_HERTZ:
si_printf(value, out, "Hz");
break;
case SR_UNIT_PERCENTAGE:
g_string_append_printf(out, "%f%%", value);
break;
case SR_UNIT_BOOLEAN:
if (value > 0)
g_string_append_printf(out, "TRUE");
else
g_string_append_printf(out, "FALSE");
break;
case SR_UNIT_SECOND:
si_printf(value, out, "s");
break;
case SR_UNIT_SIEMENS:
si_printf(value, out, "S");
break;
case SR_UNIT_DECIBEL_MW:
si_printf(value, out, "dBu");
break;
case SR_UNIT_DECIBEL_VOLT:
si_printf(value, out, "dBV");
break;
case SR_UNIT_DECIBEL_SPL:
if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
si_printf(value, out, "dB(A)");
else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_C)
si_printf(value, out, "dB(C)");
else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_Z)
si_printf(value, out, "dB(Z)");
else
/* No frequency weighting, or non-standard "flat" */
si_printf(value, out, "dB(SPL)");
if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_S)
g_string_append(out, " S");
else if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
g_string_append(out, " F");
if (mqflags & SR_MQFLAG_SPL_LAT)
g_string_append(out, " LAT");
else if (mqflags & SR_MQFLAG_SPL_PCT_OVER_ALARM)
/* Not a standard function for SLMs, so this is
* a made-up notation. */
g_string_append(out, " %oA");
break;
case SR_UNIT_CONCENTRATION:
g_string_append_printf(out, "%f ppm", value * 1000000);
break;
default:
si_printf(value, out, "");
break;
}
if ((mqflags & (SR_MQFLAG_AC | SR_MQFLAG_DC)) == (SR_MQFLAG_AC | SR_MQFLAG_DC))
g_string_append_printf(out, " AC+DC");
else if (mqflags & SR_MQFLAG_AC)
g_string_append_printf(out, " AC");
else if (mqflags & SR_MQFLAG_DC)
g_string_append_printf(out, " DC");
g_string_append_c(out, '\n');
}
static int receive(struct sr_output *o, const struct sr_dev_inst *sdi,
const struct sr_datafeed_packet *packet, GString **out)
{
const struct sr_datafeed_analog *analog;
struct sr_channel *probe;
GSList *l;
const float *fdata;
int i, p;
(void)sdi;
*out = NULL;
if (!o || !o->sdi)
return SR_ERR_ARG;
switch (packet->type) {
case SR_DF_FRAME_BEGIN:
*out = g_string_new("FRAME-BEGIN\n");
break;
case SR_DF_FRAME_END:
*out = g_string_new("FRAME-END\n");
break;
case SR_DF_ANALOG:
analog = packet->payload;
fdata = (const float *)analog->data;
*out = g_string_sized_new(512);
for (i = 0; i < analog->num_samples; i++) {
for (l = analog->probes, p = 0; l; l = l->next, p++) {
probe = l->data;
g_string_append_printf(*out, "%s: ", probe->name);
fancyprint(analog->unit, analog->mqflags,
fdata[i + p], *out);
}
}
break;
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->sdi)
return SR_ERR_ARG;
ctx = o->internal;
g_ptr_array_free(ctx->probelist, 1);
g_free(ctx);
o->internal = NULL;
return SR_OK;
}
SR_PRIV struct sr_output_format output_analog = {
.id = "analog",
.description = "Analog data",
.df_type = SR_DF_ANALOG,
.init = init,
.receive = receive,
.cleanup = cleanup
};

View File

@ -1,77 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* 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 <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/binary: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
static int data(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
{
uint8_t *outbuf;
(void)o;
if (!data_in) {
sr_err("%s: data_in was NULL", __func__);
return SR_ERR_ARG;
}
if (!length_out) {
sr_err("%s: length_out was NULL", __func__);
return SR_ERR_ARG;
}
if (length_in == 0) {
sr_err("%s: length_in was 0", __func__);
return SR_ERR_ARG;
}
if (!(outbuf = g_try_malloc0(length_in))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
memcpy(outbuf, data_in, length_in);
*data_out = outbuf;
*length_out = length_in;
return SR_OK;
}
SR_PRIV struct sr_output_format output_binary = {
.id = "binary",
.description = "Raw binary",
.df_type = SR_DF_LOGIC,
.init = NULL,
.data = data,
.event = NULL,
};

View File

@ -1,225 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
*
* 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 <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE_STRING and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/csv: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
struct context {
unsigned int num_enabled_probes;
unsigned int unitsize;
uint64_t samplerate;
GString *header;
char separator;
};
/*
* TODO:
* - Option to specify delimiter character and/or string.
* - Option to (not) print metadata as comments.
* - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
* - Option to (not) print samplenumber / time as extra column.
* - Option to "compress" output (only print changed samples, VCD-like).
* - Option to print comma-separated bits, or whole bytes/words (for 8/16
* probe LAs) as ASCII/hex etc. etc.
* - Trigger support.
*/
static int init(struct sr_output *o)
{
struct context *ctx;
struct sr_channel *probe;
GSList *l;
GVariant *gvar;
int num_probes;
time_t t;
if (!o) {
sr_err("%s: o was NULL", __func__);
return SR_ERR_ARG;
}
if (!o->sdi) {
sr_err("%s: o->sdi was NULL", __func__);
return SR_ERR_ARG;
}
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
sr_err("%s: ctx malloc failed", __func__);
return SR_ERR_MALLOC;
}
o->internal = ctx;
/* Get the number of probes, and the unitsize. */
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (probe->enabled)
ctx->num_enabled_probes++;
}
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
num_probes = g_slist_length(o->sdi->channels);
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
} else
ctx->samplerate = 0;
ctx->separator = ',';
ctx->header = g_string_sized_new(512);
t = time(NULL);
/* Some metadata */
g_string_append_printf(ctx->header, "; CSV, generated by %s on %s",
PACKAGE_STRING, ctime(&t));
g_string_append_printf(ctx->header, "; Samplerate: %"PRIu64"\n",
ctx->samplerate);
/* Columns / channels */
g_string_append_printf(ctx->header, "; Channels (%d/%d): ",
ctx->num_enabled_probes, num_probes);
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (probe->enabled)
g_string_append_printf(ctx->header, "%s, ", probe->name);
}
g_string_append_printf(ctx->header, "\n");
return SR_OK;
}
static int event(struct sr_output *o, int event_type, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
if (!o) {
sr_err("%s: o was NULL", __func__);
return SR_ERR_ARG;
}
if (!(ctx = o->internal)) {
sr_err("%s: o->internal was NULL", __func__);
return SR_ERR_ARG;
}
if (!data_out) {
sr_err("%s: data_out was NULL", __func__);
return SR_ERR_ARG;
}
switch (event_type) {
case SR_DF_TRIGGER:
sr_dbg("%s: SR_DF_TRIGGER event", __func__);
/* TODO */
*data_out = NULL;
*length_out = 0;
break;
case SR_DF_END:
sr_dbg("%s: SR_DF_END event", __func__);
/* TODO */
*data_out = NULL;
*length_out = 0;
g_free(o->internal);
o->internal = NULL;
break;
default:
sr_err("%s: unsupported event type: %d", __func__, event_type);
*data_out = NULL;
*length_out = 0;
break;
}
return SR_OK;
}
static int data(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
{
struct context *ctx;
GString *outstr;
uint64_t sample, i;
int j;
if (!o) {
sr_err("%s: o was NULL", __func__);
return SR_ERR_ARG;
}
if (!(ctx = o->internal)) {
sr_err("%s: o->internal was NULL", __func__);
return SR_ERR_ARG;
}
if (!data_in) {
sr_err("%s: data_in was NULL", __func__);
return SR_ERR_ARG;
}
if (ctx->header) {
/* First data packet. */
outstr = ctx->header;
ctx->header = NULL;
} else {
outstr = g_string_sized_new(512);
}
for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
memcpy(&sample, data_in + i, ctx->unitsize);
for (j = ctx->num_enabled_probes - 1; j >= 0; j--) {
g_string_append_printf(outstr, "%d%c",
(int)((sample & (1 << j)) >> j),
ctx->separator);
}
g_string_append_printf(outstr, "\n");
}
*data_out = (uint8_t *)outstr->str;
*length_out = outstr->len;
g_string_free(outstr, FALSE);
return SR_OK;
}
SR_PRIV struct sr_output_format output_csv = {
.id = "csv",
.description = "Comma-separated values (CSV)",
.df_type = SR_DF_LOGIC,
.init = init,
.data = data,
.event = event,
};

View File

@ -1,231 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
*
* 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 <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/vcd: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
struct context {
int num_enabled_probes;
GArray *probeindices;
GString *header;
uint8_t *prevsample;
int period;
uint64_t samplerate;
unsigned int unitsize;
};
static const char *vcd_header_comment = "\
$comment\n Acquisition with %d/%d probes at %s\n$end\n";
static int init(struct sr_output *o)
{
struct context *ctx;
struct sr_channel *probe;
GSList *l;
GVariant *gvar;
int num_probes, i;
char *samplerate_s, *frequency_s, *timestamp;
time_t t;
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
sr_err("%s: ctx malloc failed", __func__);
return SR_ERR_MALLOC;
}
o->internal = ctx;
ctx->num_enabled_probes = 0;
ctx->probeindices = g_array_new(FALSE, FALSE, sizeof(int));
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (!probe->enabled)
continue;
ctx->probeindices = g_array_append_val(
ctx->probeindices, probe->index);
ctx->num_enabled_probes++;
}
if (ctx->num_enabled_probes > 94) {
sr_err("VCD only supports 94 probes.");
return SR_ERR;
}
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
ctx->header = g_string_sized_new(512);
num_probes = g_slist_length(o->sdi->channels);
/* timestamp */
t = time(NULL);
timestamp = g_strdup(ctime(&t));
timestamp[strlen(timestamp)-1] = 0;
g_string_printf(ctx->header, "$date %s $end\n", timestamp);
g_free(timestamp);
/* generator */
g_string_append_printf(ctx->header, "$version %s %s $end\n",
PACKAGE, PACKAGE_VERSION);
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
if (!((samplerate_s = sr_samplerate_string(ctx->samplerate)))) {
g_string_free(ctx->header, TRUE);
g_free(ctx);
return SR_ERR;
}
g_string_append_printf(ctx->header, vcd_header_comment,
ctx->num_enabled_probes, num_probes, samplerate_s);
g_free(samplerate_s);
}
/* timescale */
/* VCD can only handle 1/10/100 (s - fs), so scale up first */
if (ctx->samplerate > SR_MHZ(1))
ctx->period = SR_GHZ(1);
else if (ctx->samplerate > SR_KHZ(1))
ctx->period = SR_MHZ(1);
else
ctx->period = SR_KHZ(1);
if (!(frequency_s = sr_period_string(ctx->period))) {
g_string_free(ctx->header, TRUE);
g_free(ctx);
return SR_ERR;
}
g_string_append_printf(ctx->header, "$timescale %s $end\n", frequency_s);
g_free(frequency_s);
/* scope */
g_string_append_printf(ctx->header, "$scope module %s $end\n", PACKAGE);
/* Wires / channels */
for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
probe = l->data;
if (!probe->enabled)
continue;
g_string_append_printf(ctx->header, "$var wire 1 %c %s $end\n",
(char)('!' + i), probe->name);
}
g_string_append(ctx->header, "$upscope $end\n"
"$enddefinitions $end\n$dumpvars\n");
if (!(ctx->prevsample = g_try_malloc0(ctx->unitsize))) {
g_string_free(ctx->header, TRUE);
g_free(ctx);
sr_err("%s: ctx->prevsample malloc failed", __func__);
return SR_ERR_MALLOC;
}
return SR_OK;
}
static int receive(struct sr_output *o, const struct sr_dev_inst *sdi,
const struct sr_datafeed_packet *packet, GString **out)
{
const struct sr_datafeed_logic *logic;
struct context *ctx;
unsigned int i;
int p, curbit, prevbit, index;
uint8_t *sample;
static uint64_t samplecount = 0;
(void)sdi;
*out = NULL;
if (!o || !o->internal)
return SR_ERR_ARG;
ctx = o->internal;
if (packet->type == SR_DF_END) {
*out = g_string_new("$dumpoff\n$end\n");
return SR_OK;
} else if (packet->type != SR_DF_LOGIC)
return SR_OK;
if (ctx->header) {
/* The header is still here, this must be the first packet. */
*out = ctx->header;
ctx->header = NULL;
} else {
*out = g_string_sized_new(512);
}
logic = packet->payload;
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
samplecount++;
sample = logic->data + i;
for (p = 0; p < ctx->num_enabled_probes; p++) {
index = g_array_index(ctx->probeindices, int, p);
curbit = (sample[p / 8] & (((uint8_t) 1) << index)) >> index;
prevbit = (ctx->prevsample[p / 8] & (((uint64_t) 1) << index)) >> index;
/* VCD only contains deltas/changes of signals. */
if (prevbit == curbit)
continue;
/* Output which signal changed to which value. */
g_string_append_printf(*out, "#%" PRIu64 "\n%i%c\n",
(uint64_t)(((float)samplecount / ctx->samplerate)
* ctx->period), curbit, (char)('!' + p));
}
memcpy(ctx->prevsample, sample, ctx->unitsize);
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->internal)
return SR_ERR_ARG;
ctx = o->internal;
g_free(ctx);
return SR_OK;
}
struct sr_output_format output_vcd = {
.id = "vcd",
.description = "Value Change Dump (VCD)",
.df_type = SR_DF_LOGIC,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

@ -1,7 +1,7 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
*
* 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
@ -17,64 +17,327 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
/** @cond PRIVATE */
#define LOG_PREFIX "output"
/** @endcond */
/**
* @file
*
* Output file/data format handling.
* Output module handling.
*/
/**
* @defgroup grp_output Output formats
* @defgroup grp_output Output modules
*
* Output file/data format handling.
* Output module handling.
*
* libsigrok supports several output (file) formats, e.g. binary, VCD,
* gnuplot, and so on. It provides an output API that frontends can use.
* New output formats can be added/implemented in libsigrok without having
* libsigrok supports several output modules for file formats such as binary,
* VCD, gnuplot, and so on. It provides an output API that frontends can use.
* New output modules can be added/implemented in libsigrok without having
* to change the frontends at all.
*
* All output modules are fed data in a stream. Devices that can stream data
* into libsigrok live, instead of storing and then transferring the whole
* buffer, can thus generate output live.
* into libsigrok, instead of storing and then transferring the whole buffer,
* can thus generate output live.
*
* Output modules are responsible for allocating enough memory to store
* their own output, and passing a pointer to that memory (and length) of
* the allocated memory back to the caller. The caller is then expected to
* free this memory when finished with it.
* Output modules generate a newly allocated GString. The caller is then
* expected to free this with g_string_free() when finished with it.
*
* @{
*/
/** @cond PRIVATE */
extern SR_PRIV struct sr_output_format output_text_bits;
extern SR_PRIV struct sr_output_format output_text_hex;
extern SR_PRIV struct sr_output_format output_text_ascii;
extern SR_PRIV struct sr_output_format output_binary;
extern SR_PRIV struct sr_output_format output_vcd;
extern SR_PRIV struct sr_output_format output_csv;
extern SR_PRIV struct sr_output_format output_analog;
/* extern SR_PRIV struct sr_output_format output_analog_gnuplot; */
extern SR_PRIV struct sr_output_module output_bits;
extern SR_PRIV struct sr_output_module output_hex;
extern SR_PRIV struct sr_output_module output_ascii;
extern SR_PRIV struct sr_output_module output_binary;
extern SR_PRIV struct sr_output_module output_vcd;
extern SR_PRIV struct sr_output_module output_ols;
extern SR_PRIV struct sr_output_module output_gnuplot;
extern SR_PRIV struct sr_output_module output_chronovu_la8;
extern SR_PRIV struct sr_output_module output_csv;
extern SR_PRIV struct sr_output_module output_analog;
extern SR_PRIV struct sr_output_module output_srzip;
extern SR_PRIV struct sr_output_module output_wav;
/* @endcond */
static struct sr_output_format *output_module_list[] = {
&output_text_bits,
&output_text_hex,
&output_text_ascii,
&output_binary,
&output_vcd,
static const struct sr_output_module *output_module_list[] = {
&output_csv,
&output_vcd,
&output_gnuplot,
&output_srzip,
/*&output_ascii,
&output_binary,
&output_bits,
&output_hex,
&output_ols,
&output_chronovu_la8,
&output_analog,
/* &output_analog_gnuplot, */
&output_wav,*/
NULL,
};
SR_API struct sr_output_format **sr_output_list(void)
/**
* Returns a NULL-terminated list of all available output modules.
*
* @since 0.4.0
*/
SR_API const struct sr_output_module **sr_output_list(void)
{
return output_module_list;
}
/**
* Returns the specified output module's ID.
*
* @since 0.4.0
*/
SR_API const char *sr_output_id_get(const struct sr_output_module *omod)
{
if (!omod) {
sr_err("Invalid output module NULL!");
return NULL;
}
return omod->id;
}
/**
* Returns the specified output module's name.
*
* @since 0.4.0
*/
SR_API const char *sr_output_name_get(const struct sr_output_module *omod)
{
if (!omod) {
sr_err("Invalid output module NULL!");
return NULL;
}
return omod->name;
}
/**
* Returns the specified output module's description.
*
* @since 0.4.0
*/
SR_API const char *sr_output_description_get(const struct sr_output_module *omod)
{
if (!omod) {
sr_err("Invalid output module NULL!");
return NULL;
}
return omod->desc;
}
/**
* Returns the specified output module's file extensions typical for the file
* format, as a NULL terminated array, or returns a NULL pointer if there is
* no preferred extension.
* @note these are a suggestions only.
*
* @since 0.4.0
*/
SR_API const char *const *sr_output_extensions_get(
const struct sr_output_module *omod)
{
if (!omod) {
sr_err("Invalid output module NULL!");
return NULL;
}
return omod->exts;
}
/**
* Return the output module with the specified ID, or NULL if no module
* with that id is found.
*
* @since 0.4.0
*/
SR_API const struct sr_output_module *sr_output_find(char *id)
{
int i;
for (i = 0; output_module_list[i]; i++) {
if (!strcmp(output_module_list[i]->id, id))
return output_module_list[i];
}
return NULL;
}
/**
* Returns a NULL-terminated array of struct sr_option, or NULL if the
* module takes no options.
*
* Each call to this function must be followed by a call to
* sr_output_options_free().
*
* @since 0.4.0
*/
SR_API const struct sr_option **sr_output_options_get(const struct sr_output_module *omod)
{
const struct sr_option *mod_opts, **opts;
int size, i;
if (!omod || !omod->options)
return NULL;
mod_opts = omod->options();
for (size = 0; mod_opts[size].id; size++)
;
opts = g_malloc((size + 1) * sizeof(struct sr_option *));
for (i = 0; i < size; i++)
opts[i] = &mod_opts[i];
opts[i] = NULL;
return opts;
}
/**
* After a call to sr_output_options_get(), this function cleans up all
* resources returned by that call.
*
* @since 0.4.0
*/
SR_API void sr_output_options_free(const struct sr_option **options)
{
int i;
if (!options)
return;
for (i = 0; options[i]; i++) {
if (options[i]->def) {
g_variant_unref(options[i]->def);
((struct sr_option *)options[i])->def = NULL;
}
if (options[i]->values) {
g_slist_free_full(options[i]->values, (GDestroyNotify)g_variant_unref);
((struct sr_option *)options[i])->values = NULL;
}
}
g_free(options);
}
/**
* Create a new output instance using the specified output module.
*
* <code>options</code> is a *HashTable with the keys corresponding with
* the module options' <code>id</code> field. The values should be GVariant
* pointers with sunk * references, of the same GVariantType as the option's
* default value.
*
* The sr_dev_inst passed in can be used by the instance to determine
* channel names, samplerate, and so on.
*
* @since 0.4.0
*/
SR_API const struct sr_output *sr_output_new(const struct sr_output_module *omod,
GHashTable *options, const struct sr_dev_inst *sdi)
{
struct sr_output *op;
const struct sr_option *mod_opts;
const GVariantType *gvt;
GHashTable *new_opts;
GHashTableIter iter;
gpointer key, value;
int i;
op = g_malloc(sizeof(struct sr_output));
op->module = omod;
op->sdi = sdi;
new_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify)g_variant_unref);
if (omod->options) {
mod_opts = omod->options();
for (i = 0; mod_opts[i].id; i++) {
if (options && g_hash_table_lookup_extended(options,
mod_opts[i].id, &key, &value)) {
/* Pass option along. */
gvt = g_variant_get_type(mod_opts[i].def);
if (!g_variant_is_of_type(value, gvt)) {
sr_err("Invalid type for '%s' option.", key);
g_free(op);
return NULL;
}
g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
g_variant_ref(value));
} else {
/* Option not given: insert the default value. */
g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
g_variant_ref(mod_opts[i].def));
}
}
/* Make sure no invalid options were given. */
if (options) {
g_hash_table_iter_init(&iter, options);
while (g_hash_table_iter_next(&iter, &key, &value)) {
if (!g_hash_table_lookup(new_opts, key)) {
sr_err("Output module '%s' has no option '%s'", omod->id, key);
g_hash_table_destroy(new_opts);
g_free(op);
return NULL;
}
}
}
}
if (op->module->init && op->module->init(op, new_opts) != SR_OK) {
g_free(op);
op = NULL;
}
if (new_opts)
g_hash_table_destroy(new_opts);
return op;
}
/**
* Send a packet to the specified output instance.
*
* The instance's output is returned as a newly allocated GString,
* which must be freed by the caller.
*
* @since 0.4.0
*/
SR_API int sr_output_send(const struct sr_output *o,
const struct sr_datafeed_packet *packet, GString **out)
{
return o->module->receive(o, packet, out);
}
/**
* Free the specified output instance and all associated resources.
*
* @since 0.4.0
*/
SR_API int sr_output_free(const struct sr_output *o)
{
int ret;
if (!o)
return SR_ERR_ARG;
ret = SR_OK;
if (o->module->cleanup)
ret = o->module->cleanup((struct sr_output *)o);
g_free((gpointer)o);
return ret;
}
/** @} */

View File

@ -0,0 +1,321 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <zip.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#define LOG_PREFIX "output/srzip"
struct out_context {
gboolean zip_created;
uint64_t samplerate;
char *filename;
};
static int init(struct sr_output *o, GHashTable *options)
{
struct out_context *outc;
outc = g_malloc0(sizeof(struct out_context));
o->priv = outc;
outc->filename = g_strdup(g_variant_get_string(g_hash_table_lookup(options, "filename"), NULL));
if (strlen(outc->filename) == 0)
return SR_ERR_ARG;
return SR_OK;
}
static int zip_create(const struct sr_output *o)
{
struct out_context *outc;
struct sr_channel *ch;
FILE *meta;
struct zip *zipfile;
struct zip_source *versrc, *metasrc;
GVariant *gvar;
GSList *l;
int tmpfile, ret;
char version[1], metafile[32], *s;
outc = o->priv;
if (outc->samplerate == 0) {
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
&gvar) == SR_OK) {
outc->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
}
}
/* Quietly delete it first, libzip wants replace ops otherwise. */
unlink(outc->filename);
if (!(zipfile = zip_open(outc->filename, ZIP_CREATE, &ret)))
return SR_ERR;
/* "version" */
version[0] = '2';
if (!(versrc = zip_source_buffer(zipfile, version, 1, 0)))
return SR_ERR;
if (zip_add(zipfile, "version", versrc) == -1) {
sr_info("Error saving version into zipfile: %s.",
zip_strerror(zipfile));
return SR_ERR;
}
/* init "metadata" */
strcpy(metafile, "sigrok-meta-XXXXXX");
if ((tmpfile = g_mkstemp(metafile)) == -1)
return SR_ERR;
close(tmpfile);
meta = g_fopen(metafile, "wb");
fprintf(meta, "[global]\n");
fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION);
fprintf(meta, "[device 1]\ncapturefile = logic-1\n");
fprintf(meta, "total probes = %d\n", g_slist_length(o->sdi->channels));
s = sr_samplerate_string(outc->samplerate);
fprintf(meta, "samplerate = %s\n", s);
g_free(s);
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
fprintf(meta, "probe%d = %s\n", ch->index + 1, ch->name);
}
fclose(meta);
if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) {
unlink(metafile);
return SR_ERR;
}
if (zip_add(zipfile, "metadata", metasrc) == -1) {
unlink(metafile);
return SR_ERR;
}
if ((ret = zip_close(zipfile)) == -1) {
sr_info("Error saving zipfile: %s.", zip_strerror(zipfile));
unlink(metafile);
return SR_ERR;
}
unlink(metafile);
return SR_OK;
}
static int zip_append(const struct sr_output *o, unsigned char *buf,
int unitsize, int length)
{
struct out_context *outc;
struct zip *archive;
struct zip_source *logicsrc;
zip_int64_t num_files;
struct zip_file *zf;
struct zip_stat zs;
struct zip_source *metasrc;
GKeyFile *kf;
GError *error;
gsize len;
int chunk_num, next_chunk_num, tmpfile, ret, i;
const char *entry_name;
char *metafile, tmpname[32], chunkname[16];
outc = o->priv;
if (!(archive = zip_open(outc->filename, 0, &ret)))
return SR_ERR;
if (zip_stat(archive, "metadata", 0, &zs) == -1)
return SR_ERR;
metafile = g_malloc(zs.size);
zf = zip_fopen_index(archive, zs.index, 0);
zip_fread(zf, metafile, zs.size);
zip_fclose(zf);
/*
* If the file was only initialized but doesn't yet have any
* data it in, it won't have a unitsize field in metadata yet.
*/
error = NULL;
kf = g_key_file_new();
if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) {
sr_err("Failed to parse metadata: %s.", error->message);
return SR_ERR;
}
g_free(metafile);
tmpname[0] = '\0';
if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) {
if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
sr_err("Failed to check unitsize key: %s", error ? error->message : "?");
return SR_ERR;
}
/* Add unitsize field. */
g_key_file_set_integer(kf, "device 1", "unitsize", unitsize);
metafile = g_key_file_to_data(kf, &len, &error);
strcpy(tmpname, "sigrok-meta-XXXXXX");
if ((tmpfile = g_mkstemp(tmpname)) == -1)
return SR_ERR;
if (write(tmpfile, metafile, len) < 0) {
sr_dbg("Failed to create new metadata: %s", strerror(errno));
g_free(metafile);
unlink(tmpname);
return SR_ERR;
}
close(tmpfile);
if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) {
sr_err("Failed to create zip source for metadata.");
g_free(metafile);
unlink(tmpname);
return SR_ERR;
}
if (zip_replace(archive, zs.index, metasrc) == -1) {
sr_err("Failed to replace metadata file.");
g_free(metafile);
unlink(tmpname);
return SR_ERR;
}
g_free(metafile);
}
g_key_file_free(kf);
next_chunk_num = 1;
num_files = zip_get_num_entries(archive, 0);
for (i = 0; i < num_files; i++) {
entry_name = zip_get_name(archive, i, 0);
if (strncmp(entry_name, "logic-1", 7))
continue;
if (strlen(entry_name) == 7) {
/* This file has no extra chunks, just a single "logic-1".
* Rename it to "logic-1-1" * and continue with chunk 2. */
if (zip_rename(archive, i, "logic-1-1") == -1) {
sr_err("Failed to rename 'logic-1' to 'logic-1-1'.");
unlink(tmpname);
return SR_ERR;
}
next_chunk_num = 2;
break;
} else if (strlen(entry_name) > 8 && entry_name[7] == '-') {
chunk_num = strtoull(entry_name + 8, NULL, 10);
if (chunk_num >= next_chunk_num)
next_chunk_num = chunk_num + 1;
}
}
snprintf(chunkname, 15, "logic-1-%d", next_chunk_num);
if (!(logicsrc = zip_source_buffer(archive, buf, length, FALSE))) {
unlink(tmpname);
return SR_ERR;
}
if (zip_add(archive, chunkname, logicsrc) == -1) {
unlink(tmpname);
return SR_ERR;
}
if ((ret = zip_close(archive)) == -1) {
sr_info("error saving session file: %s", zip_strerror(archive));
unlink(tmpname);
return SR_ERR;
}
unlink(tmpname);
return SR_OK;
}
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
struct out_context *outc;
const struct sr_datafeed_meta *meta;
const struct sr_datafeed_logic *logic;
const struct sr_config *src;
GSList *l;
int ret;
*out = NULL;
if (!o || !o->sdi || !(outc = o->priv))
return SR_ERR_ARG;
switch (packet->type) {
case SR_DF_META:
meta = packet->payload;
for (l = meta->config; l; l = l->next) {
src = l->data;
if (src->key != SR_CONF_SAMPLERATE)
continue;
outc->samplerate = g_variant_get_uint64(src->data);
}
break;
case SR_DF_LOGIC:
if (!outc->zip_created) {
if ((ret = zip_create(o)) != SR_OK)
return ret;
outc->zip_created = TRUE;
}
logic = packet->payload;
ret = zip_append(o, logic->data, logic->unitsize, logic->length);
break;
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct out_context *outc;
outc = o->priv;
g_free(outc->filename);
g_free(outc);
o->priv = NULL;
return SR_OK;
}
static struct sr_option options[] = {
{ "filename", "Filename", "File to write", NULL, NULL },
{0}
};
static const struct sr_option *get_options(void)
{
if (!options[0].def)
options[0].def = g_variant_ref_sink(g_variant_new_string(""));
return options;
}
SR_PRIV struct sr_output_module output_srzip = {
.id = "srzip",
.name = "srzip",
.desc = "srzip session file",
.exts = (const char*[]){"sr", NULL},
.options = get_options,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

@ -1,33 +0,0 @@
##
## This file is part of the libsigrok project.
##
## Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
##
## 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
##
# Local lib, this is NOT meant to be installed!
noinst_LTLIBRARIES = libsigrok4DSLoutputtext.la
libsigrok4DSLoutputtext_la_SOURCES = \
text.c \
text.h \
bits.c \
hex.c \
ascii.c
libsigrok4DSLoutputtext_la_CFLAGS = \
-I$(top_srcdir)

View File

@ -1,136 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/ascii: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV int init_ascii(struct sr_output *o)
{
return init(o, DEFAULT_BPL_ASCII, MODE_ASCII);
}
SR_PRIV int data_ascii(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
unsigned int outsize, offset, p;
int max_linelen;
const uint8_t *sample;
uint8_t *outbuf;
ctx = o->internal;
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
+ ctx->samples_per_line / 8;
/*
* Calculate space needed for probes. Set aside 512 bytes for
* extra output, e.g. trigger.
*/
outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
* (ctx->num_enabled_probes * max_linelen);
if (!(outbuf = g_try_malloc0(outsize + 1))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
outbuf[0] = '\0';
if (ctx->header) {
/* The header is still here, this must be the first packet. */
strncpy((char *)outbuf, ctx->header, outsize);
g_free(ctx->header);
ctx->header = NULL;
}
if (length_in >= ctx->unitsize) {
for (offset = 0; offset <= length_in - ctx->unitsize;
offset += ctx->unitsize) {
sample = data_in + offset;
char tmpval[ctx->num_enabled_probes];
for (p = 0; p < ctx->num_enabled_probes; p++) {
uint8_t curbit = (sample[p / 8] & ((uint8_t) 1 << (p % 8)));
uint8_t prevbit = (ctx->prevsample[p / 8] &
((uint8_t) 1 << (p % 8)));
if (curbit < prevbit && ctx->line_offset > 0) {
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset-1] = '\\';
}
if (curbit > prevbit) {
tmpval[p] = '/';
} else {
if (curbit)
tmpval[p] = '"';
else
tmpval[p] = '.';
}
}
/* End of line. */
if (ctx->spl_cnt >= ctx->samples_per_line) {
flush_linebufs(ctx, outbuf);
ctx->line_offset = ctx->spl_cnt = 0;
ctx->mark_trigger = -1;
}
for (p = 0; p < ctx->num_enabled_probes; p++) {
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset] = tmpval[p];
}
ctx->line_offset++;
ctx->spl_cnt++;
memcpy(ctx->prevsample, sample, ctx->unitsize);
}
} else {
sr_info("Short buffer (length_in=%" PRIu64 ").", length_in);
}
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
return SR_OK;
}
SR_PRIV struct sr_output_format output_text_ascii = {
.id = "ascii",
.description = "ASCII",
.df_type = SR_DF_LOGIC,
.init = init_ascii,
.data = data_ascii,
.event = event,
};

View File

@ -1,119 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/bits: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV int init_bits(struct sr_output *o)
{
return init(o, DEFAULT_BPL_BITS, MODE_BITS);
}
SR_PRIV int data_bits(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
unsigned int outsize, offset, p;
int max_linelen;
const uint8_t *sample;
uint8_t *outbuf, c;
ctx = o->internal;
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
+ ctx->samples_per_line / 8;
/*
* Calculate space needed for probes. Set aside 512 bytes for
* extra output, e.g. trigger.
*/
outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
* (ctx->num_enabled_probes * max_linelen);
if (!(outbuf = g_try_malloc0(outsize + 1))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
outbuf[0] = '\0';
if (ctx->header) {
/* The header is still here, this must be the first packet. */
strncpy((char *)outbuf, ctx->header, outsize);
g_free(ctx->header);
ctx->header = NULL;
}
if (length_in >= ctx->unitsize) {
for (offset = 0; offset <= length_in - ctx->unitsize;
offset += ctx->unitsize) {
sample = data_in + offset;
for (p = 0; p < ctx->num_enabled_probes; p++) {
c = (sample[p / 8] & ((uint8_t) 1 << (p % 8))) ? '1' : '0';
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset] = c;
}
ctx->line_offset++;
ctx->spl_cnt++;
/* Add a space every 8th bit. */
if ((ctx->spl_cnt & 7) == 0) {
for (p = 0; p < ctx->num_enabled_probes; p++)
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset] = ' ';
ctx->line_offset++;
}
/* End of line. */
if (ctx->spl_cnt >= ctx->samples_per_line) {
flush_linebufs(ctx, outbuf);
ctx->line_offset = ctx->spl_cnt = 0;
ctx->mark_trigger = -1;
}
}
} else {
sr_info("Short buffer (length_in=%" PRIu64 ").", length_in);
}
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
return SR_OK;
}
SR_PRIV struct sr_output_format output_text_bits = {
.id = "bits",
.description = "Bits",
.df_type = SR_DF_LOGIC,
.init = init_bits,
.data = data_bits,
.event = event,
};

View File

@ -1,112 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/hex: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV int init_hex(struct sr_output *o)
{
return init(o, DEFAULT_BPL_HEX, MODE_HEX);
}
SR_PRIV int data_hex(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
unsigned int outsize, offset, p;
int max_linelen;
const uint8_t *sample;
uint8_t *outbuf;
ctx = o->internal;
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
+ ctx->samples_per_line / 2;
outsize = length_in / ctx->unitsize * ctx->num_enabled_probes
/ ctx->samples_per_line * max_linelen + 512;
if (!(outbuf = g_try_malloc0(outsize + 1))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
outbuf[0] = '\0';
if (ctx->header) {
/* The header is still here, this must be the first packet. */
strncpy((char *)outbuf, ctx->header, outsize);
g_free(ctx->header);
ctx->header = NULL;
}
ctx->line_offset = 0;
for (offset = 0; offset <= length_in - ctx->unitsize;
offset += ctx->unitsize) {
sample = data_in + offset;
for (p = 0; p < ctx->num_enabled_probes; p++) {
ctx->linevalues[p] <<= 1;
if (sample[p / 8] & ((uint8_t) 1 << (p % 8)))
ctx->linevalues[p] |= 1;
sprintf((char *)ctx->linebuf + (p * ctx->linebuf_len) +
ctx->line_offset, "%.2x", ctx->linevalues[p]);
}
ctx->spl_cnt++;
/* Add a space after every complete hex byte. */
if ((ctx->spl_cnt & 7) == 0) {
for (p = 0; p < ctx->num_enabled_probes; p++)
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset + 2] = ' ';
ctx->line_offset += 3;
}
/* End of line. */
if (ctx->spl_cnt >= ctx->samples_per_line) {
flush_linebufs(ctx, outbuf);
ctx->line_offset = ctx->spl_cnt = 0;
}
}
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
return SR_OK;
}
SR_PRIV struct sr_output_format output_text_hex = {
.id = "hex",
.description = "Hexadecimal",
.df_type = SR_DF_LOGIC,
.init = init_hex,
.data = data_hex,
.event = event,
};

View File

@ -1,208 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE_STRING and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/text: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV void flush_linebufs(struct context *ctx, uint8_t *outbuf)
{
static int max_probename_len = 0;
int len, i;
GSList *l;
char *probe_name;
if (ctx->linebuf[0] == 0)
return;
if (max_probename_len == 0) {
/* First time through... */
for (l = ctx->probenames; l; l = l->next) {
probe_name = l->data;
len = strlen(probe_name);
if (len > max_probename_len)
max_probename_len = len;
}
}
for (i = 0, l = ctx->probenames; l; l = l->next, i++) {
probe_name = l->data;
sprintf((char *)outbuf + strlen((const char *)outbuf),
"%*s:%s\n", max_probename_len,
probe_name, ctx->linebuf + i * ctx->linebuf_len);
}
/* Mark trigger with a ^ character. */
if (ctx->mark_trigger != -1)
{
int space_offset = ctx->mark_trigger / 8;
if (ctx->mode == MODE_ASCII)
space_offset = 0;
sprintf((char *)outbuf + strlen((const char *)outbuf),
"T:%*s^\n", ctx->mark_trigger + space_offset, "");
}
memset(ctx->linebuf, 0, i * ctx->linebuf_len);
}
SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode)
{
struct context *ctx;
struct sr_channel *probe;
GSList *l;
GVariant *gvar;
uint64_t samplerate;
int num_probes, ret;
char *samplerate_s;
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
sr_err("%s: ctx malloc failed", __func__);
return SR_ERR_MALLOC;
}
o->internal = ctx;
ctx->num_enabled_probes = 0;
ctx->probenames = NULL;
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (!probe->enabled)
continue;
ctx->probenames = g_slist_append(ctx->probenames, probe->name);
ctx->num_enabled_probes++;
}
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
ctx->line_offset = 0;
ctx->spl_cnt = 0;
ctx->mark_trigger = -1;
ctx->mode = mode;
ret = SR_OK;
if (o->param && o->param[0]) {
ctx->samples_per_line = strtoul(o->param, NULL, 10);
if (ctx->samples_per_line < 1) {
ret = SR_ERR;
goto err;
}
} else
ctx->samples_per_line = default_spl;
if (!(ctx->header = g_try_malloc0(512))) {
sr_err("%s: ctx->header malloc failed", __func__);
ret = SR_ERR_MALLOC;
goto err;
}
snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING);
num_probes = g_slist_length(o->sdi->channels);
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
if (!(samplerate_s = sr_samplerate_string(samplerate))) {
ret = SR_ERR;
goto err;
}
snprintf(ctx->header + strlen(ctx->header),
511 - strlen(ctx->header),
"Acquisition with %d/%d probes at %s\n",
ctx->num_enabled_probes, num_probes, samplerate_s);
g_free(samplerate_s);
}
ctx->linebuf_len = ctx->samples_per_line * 2 + 4;
if (!(ctx->linebuf = g_try_malloc0(num_probes * ctx->linebuf_len))) {
sr_err("%s: ctx->linebuf malloc failed", __func__);
ret = SR_ERR_MALLOC;
goto err;
}
if (!(ctx->linevalues = g_try_malloc0(num_probes))) {
sr_err("%s: ctx->linevalues malloc failed", __func__);
ret = SR_ERR_MALLOC;
}
if (mode == MODE_ASCII &&
!(ctx->prevsample = g_try_malloc0(num_probes / 8))) {
sr_err("%s: ctx->prevsample malloc failed", __func__);
ret = SR_ERR_MALLOC;
}
err:
if (ret != SR_OK) {
g_free(ctx->header);
g_free(ctx);
}
return ret;
}
SR_PRIV int event(struct sr_output *o, int event_type, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
int outsize;
uint8_t *outbuf;
ctx = o->internal;
switch (event_type) {
case SR_DF_TRIGGER:
ctx->mark_trigger = ctx->spl_cnt;
*data_out = NULL;
*length_out = 0;
break;
case SR_DF_END:
outsize = ctx->num_enabled_probes
* (ctx->samples_per_line + 20) + 512;
if (!(outbuf = g_try_malloc0(outsize))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
flush_linebufs(ctx, outbuf);
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
g_free(o->internal);
o->internal = NULL;
break;
default:
*data_out = NULL;
*length_out = 0;
break;
}
return SR_OK;
}

View File

@ -1,69 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_OUTPUT_TEXT_TEXT_H
#define LIBSIGROK_OUTPUT_TEXT_TEXT_H
#define DEFAULT_BPL_BITS 64
#define DEFAULT_BPL_HEX 192
#define DEFAULT_BPL_ASCII 74
enum outputmode {
MODE_BITS = 1,
MODE_HEX,
MODE_ASCII,
};
struct context {
unsigned int num_enabled_probes;
int samples_per_line;
unsigned int unitsize;
int line_offset;
int linebuf_len;
GSList *probenames;
uint8_t *linebuf;
int spl_cnt;
uint8_t *linevalues;
char *header;
int mark_trigger;
uint8_t *prevsample;
enum outputmode mode;
};
SR_PRIV void flush_linebufs(struct context *ctx, uint8_t *outbuf);
SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode);
SR_PRIV int event(struct sr_output *o, int event_type, uint8_t **data_out,
uint64_t *length_out);
SR_PRIV int init_bits(struct sr_output *o);
SR_PRIV int data_bits(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out);
SR_PRIV int init_hex(struct sr_output *o);
SR_PRIV int data_hex(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out);
SR_PRIV int init_ascii(struct sr_output *o);
SR_PRIV int data_ascii(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out);
#endif

271
libsigrok4DSL/output/vcd.c Normal file
View File

@ -0,0 +1,271 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
*
* 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 <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
#define LOG_PREFIX "output/vcd"
struct context {
int num_enabled_channels;
GArray *channelindices;
uint8_t *prevsample;
gboolean header_done;
int period;
int *channel_index;
uint64_t samplerate;
uint64_t samplecount;
};
static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
int num_enabled_channels, i;
(void)options;
num_enabled_channels = 0;
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
num_enabled_channels++;
}
if (num_enabled_channels > 94) {
sr_err("VCD only supports 94 channels.");
return SR_ERR;
}
ctx = g_malloc0(sizeof(struct context));
o->priv = ctx;
ctx->num_enabled_channels = num_enabled_channels;
ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
/* Once more to map the enabled channels. */
for (i = 0, l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
ctx->channel_index[i++] = ch->index;
}
return SR_OK;
}
static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
GVariant *gvar;
GString *header;
GSList *l;
time_t t;
int num_channels, i;
char *samplerate_s, *frequency_s, *timestamp;
ctx = o->priv;
header = g_string_sized_new(512);
num_channels = g_slist_length(o->sdi->channels);
/* timestamp */
t = time(NULL);
timestamp = g_strdup(ctime(&t));
timestamp[strlen(timestamp)-1] = 0;
g_string_printf(header, "$date %s $end\n", timestamp);
g_free(timestamp);
/* generator */
g_string_append_printf(header, "$version %s %s $end\n",
PACKAGE, PACKAGE_VERSION);
g_string_append_printf(header, "$comment\n Acquisition with "
"%d/%d channels", ctx->num_enabled_channels, num_channels);
if (ctx->samplerate == 0) {
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
&gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
}
}
if (ctx->samplerate != 0) {
samplerate_s = sr_samplerate_string(ctx->samplerate);
g_string_append_printf(header, " at %s", samplerate_s);
g_free(samplerate_s);
}
g_string_append_printf(header, "\n$end\n");
/* timescale */
/* VCD can only handle 1/10/100 (s - fs), so scale up first */
if (ctx->samplerate > SR_MHZ(1))
ctx->period = SR_GHZ(1);
else if (ctx->samplerate > SR_KHZ(1))
ctx->period = SR_MHZ(1);
else
ctx->period = SR_KHZ(1);
frequency_s = sr_period_string(ctx->period);
g_string_append_printf(header, "$timescale %s $end\n", frequency_s);
g_free(frequency_s);
/* scope */
g_string_append_printf(header, "$scope module %s $end\n", PACKAGE);
/* Wires / channels */
for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
g_string_append_printf(header, "$var wire 1 %c %s $end\n",
(char)('!' + i), ch->name);
}
g_string_append(header, "$upscope $end\n$enddefinitions $end\n");
return header;
}
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
const struct sr_datafeed_logic *logic;
const struct sr_config *src;
GSList *l;
struct context *ctx;
unsigned int i;
int p, curbit, prevbit, index;
uint8_t *sample;
gboolean timestamp_written;
*out = NULL;
if (!o || !o->priv)
return SR_ERR_BUG;
ctx = o->priv;
switch (packet->type) {
case SR_DF_META:
meta = packet->payload;
for (l = meta->config; l; l = l->next) {
src = l->data;
if (src->key != SR_CONF_SAMPLERATE)
continue;
ctx->samplerate = g_variant_get_uint64(src->data);
}
break;
case SR_DF_LOGIC:
logic = packet->payload;
if (!ctx->header_done) {
*out = gen_header(o);
ctx->header_done = TRUE;
} else {
*out = g_string_sized_new(512);
}
if (!ctx->prevsample) {
/* Can't allocate this until we know the stream's unitsize. */
ctx->prevsample = g_malloc0(logic->unitsize);
}
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
sample = logic->data + i;
timestamp_written = FALSE;
for (p = 0; p < ctx->num_enabled_channels; p++) {
index = ctx->channel_index[p];
curbit = ((unsigned)sample[index / 8]
>> (index % 8)) & 1;
prevbit = ((unsigned)ctx->prevsample[index / 8]
>> (index % 8)) & 1;
/* VCD only contains deltas/changes of signals. */
if (prevbit == curbit && ctx->samplecount > 0)
continue;
/* Output timestamp of subsequent signal changes. */
if (!timestamp_written)
g_string_append_printf(*out, "#%.0f",
(double)ctx->samplecount /
ctx->samplerate * ctx->period);
/* Output which signal changed to which value. */
g_string_append_c(*out, ' ');
g_string_append_c(*out, '0' + curbit);
g_string_append_c(*out, '!' + p);
timestamp_written = TRUE;
}
if (timestamp_written)
g_string_append_c(*out, '\n');
ctx->samplecount++;
memcpy(ctx->prevsample, sample, logic->unitsize);
}
break;
case SR_DF_END:
/* Write final timestamp as length indicator. */
*out = g_string_sized_new(512);
g_string_printf(*out, "#%.0f\n",
(double)ctx->samplecount / ctx->samplerate * ctx->period);
break;
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->priv)
return SR_ERR_ARG;
ctx = o->priv;
g_free(ctx->prevsample);
g_free(ctx->channel_index);
g_free(ctx);
return SR_OK;
}
struct sr_output_module output_vcd = {
.id = "vcd",
.name = "VCD",
.desc = "Value Change Dump",
.exts = (const char*[]){"vcd", NULL},
.options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

@ -132,7 +132,7 @@ SR_API struct sr_input_format **sr_input_list(void);
/*--- output/output.c -------------------------------------------------------*/
SR_API struct sr_output_format **sr_output_list(void);
SR_API const struct sr_output_module **sr_output_list(void);
/*--- strutil.c -------------------------------------------------------------*/
@ -141,6 +141,7 @@ SR_API char *sr_iec_string_u64(uint64_t x, const char *unit);
SR_API char *sr_samplerate_string(uint64_t samplerate);
SR_API char *sr_samplecount_string(uint64_t samplecount);
SR_API char *sr_period_string(uint64_t frequency);
SR_API char *sr_time_string(uint64_t time);
SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q);
SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi,
const char *triggerstring);

View File

@ -211,6 +211,47 @@ SR_API char *sr_period_string(uint64_t frequency)
return o;
}
/**
* Convert a numeric time(ns) value to the "natural" string representation
* of its period.
*
* E.g. a value of 3000000 would be converted to "3 ms", 20000 to "20 us".
*
* @param time The time in ns.
*
* @return A g_try_malloc()ed string representation of the time value,
* or NULL upon errors. The caller is responsible to g_free() the
* memory.
*/
SR_API char *sr_time_string(uint64_t time)
{
char *o;
int r;
/* Allocate enough for a uint64_t as string + " ms". */
if (!(o = g_try_malloc0(30 + 1))) {
sr_err("%s: o malloc failed", __func__);
return NULL;
}
if (time >= 1000000000)
r = snprintf(o, 30, "%" PRIu64 " s", time / 1000000000);
else if (time >= 1000000)
r = snprintf(o, 30, "%" PRIu64 " ms", time / 1000000);
else if (time >= 1000)
r = snprintf(o, 30, "%" PRIu64 " us", time / 1000);
else
r = snprintf(o, 30, "%" PRIu64 " ns", time);
if (r < 0) {
/* Something went wrong... */
g_free(o);
return NULL;
}
return o;
}
/**
* Convert a numeric voltage value to the "natural" string representation
* of its voltage value. The voltage is specified as a rational number's

69
libsigrok4DSL/version.h Normal file
View File

@ -0,0 +1,69 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_VERSION_H
#define LIBSIGROK_VERSION_H
/**
* @file
*
* Version number definitions and macros.
*/
/**
* @ingroup grp_versions
*
* @{
*/
/*
* Package version macros (can be used for conditional compilation).
*/
/** The libsigrok package 'major' version number. */
#define SR_PACKAGE_VERSION_MAJOR 0
/** The libsigrok package 'minor' version number. */
#define SR_PACKAGE_VERSION_MINOR 2
/** The libsigrok package 'micro' version number. */
#define SR_PACKAGE_VERSION_MICRO 0
/** The libsigrok package version ("major.minor.micro") as string. */
#define SR_PACKAGE_VERSION_STRING "0.2.0"
/*
* Library/libtool version macros (can be used for conditional compilation).
*/
/** The libsigrok libtool 'current' version number. */
#define SR_LIB_VERSION_CURRENT 1
/** The libsigrok libtool 'revision' version number. */
#define SR_LIB_VERSION_REVISION 2
/** The libsigrok libtool 'age' version number. */
#define SR_LIB_VERSION_AGE 0
/** The libsigrok libtool version ("current:revision:age") as string. */
#define SR_LIB_VERSION_STRING "1:2:0"
/** @} */
#endif