mirror of
https://github.com/DreamSourceLab/DSView.git
synced 2025-01-23 13:42:55 +08:00
Merge branch 'release-0.93'
This commit is contained in:
commit
56dc212337
13
.gitignore
vendored
13
.gitignore
vendored
@ -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*
|
||||
|
@ -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 |
@ -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.";
|
||||
|
@ -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);
|
||||
|
@ -120,6 +120,8 @@ public:
|
||||
|
||||
void options_changed(bool changed);
|
||||
|
||||
uint64_t sample_count() const;
|
||||
|
||||
private:
|
||||
boost::optional<uint64_t> wait_for_data() const;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QApplication>
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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()));
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -90,6 +90,8 @@ private slots:
|
||||
*/
|
||||
void update_device_list();
|
||||
|
||||
void reload();
|
||||
|
||||
void show_session_error(
|
||||
const QString text, const QString info_text);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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++)
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
@ -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"));
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
/**
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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.
@ -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++;
|
||||
}
|
||||
|
@ -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
|
||||
])
|
||||
|
@ -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;
|
||||
|
@ -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) ||
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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
283
libsigrok4DSL/output/csv.c
Normal 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,
|
||||
};
|
229
libsigrok4DSL/output/gnuplot.c
Normal file
229
libsigrok4DSL/output/gnuplot.c
Normal 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,
|
||||
};
|
@ -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
|
||||
};
|
@ -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,
|
||||
};
|
@ -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,
|
||||
};
|
@ -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,
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
321
libsigrok4DSL/output/srzip.c
Normal file
321
libsigrok4DSL/output/srzip.c
Normal 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,
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
};
|
@ -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,
|
||||
};
|
@ -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,
|
||||
};
|
@ -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;
|
||||
}
|
@ -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
271
libsigrok4DSL/output/vcd.c
Normal 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,
|
||||
};
|
@ -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);
|
||||
|
@ -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
69
libsigrok4DSL/version.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user