Merge pull request #50 from asanza/develop

Add support for export capture data into multiple file formats.
This commit is contained in:
DreamSourceLab 2015-04-20 11:37:02 +08:00
commit 1b1bb88e75
43 changed files with 1714 additions and 1670 deletions

View File

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

View File

@ -30,7 +30,7 @@
#include <getopt.h>
#include <QtGui/QApplication>
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QDir>

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@ namespace dialogs {
const QString WaitingDialog::TIPS_INFO = "Waiting";
WaitingDialog::WaitingDialog(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst) :
WaitingDialog::WaitingDialog(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst) :
QDialog(parent),
_dev_inst(dev_inst),
_button_box(QDialogButtonBox::Save | QDialogButtonBox::Abort,

View File

@ -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,
@ -520,7 +519,7 @@ void MainWindow::on_screenShot()
tr("%1 Files (*.%2);;All Files (*)")
.arg(format.toUpper()).arg(format));
if (!fileName.isEmpty())
pixmap.save(fileName, format.toAscii());
pixmap.save(fileName, format.toLatin1());
}
void MainWindow::on_save()

View File

@ -54,6 +54,9 @@
#include <QDebug>
#include <QMessageBox>
#include <QProgressDialog>
#include <QFile>
#include <QtConcurrent/QtConcurrent>
#include <boost/foreach.hpp>
@ -179,6 +182,103 @@ 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;
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){
const deque< boost::shared_ptr<pv::data::LogicSnapshot> > &snapshots =
_logic_data->get_snapshots();
if(snapshots.empty())
return;
const boost::shared_ptr<pv::data::LogicSnapshot> & snapshot =
snapshots.front();
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;
struct sr_output output;
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);
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 = 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;
}
});
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;

View File

@ -43,6 +43,7 @@
#include <QMap>
#include <QVariant>
#include <QTimer>
#include <QtConcurrent/QtConcurrent>
#include <libsigrok4DSL/libsigrok.h>
#include <libusb.h>
@ -86,8 +87,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 +117,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 +137,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 +288,15 @@ signals:
void malloc_error();
void zero_adj();
void progressSaveFileValueChanged(int percent);
public slots:
void reload();
void refresh();
private slots:
void cancelSaveFile();
private:
// TODO: This should not be necessary. Multiple concurrent
// sessions should should be supported and it should be

View File

@ -48,7 +48,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) :
_action_open = new QAction(this);
_action_open->setText(QApplication::translate(
"File", "&Open...", 0, QApplication::UnicodeUTF8));
"File", "&Open...", 0));
_action_open->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/open.png")));
_action_open->setObjectName(QString::fromUtf8("actionOpen"));
@ -57,16 +57,24 @@ FileBar::FileBar(SigSession &session, QWidget *parent) :
_action_save = new QAction(this);
_action_save->setText(QApplication::translate(
"File", "&Save...", 0, QApplication::UnicodeUTF8));
"File", "&Save...", 0));
_action_save->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/save.png")));
_action_save->setObjectName(QString::fromUtf8("actionSave"));
_file_button.addAction(_action_save);
connect(_action_save, SIGNAL(triggered()), this, SLOT(on_actionSave_triggered()));
_action_export = new QAction(this);
_action_export->setText(QApplication::translate("File", "&Export...", 0));
_action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/instant.png")));
_action_export->setObjectName(QString::fromUtf8("actionExport"));
_file_button.addAction(_action_export);
connect(_action_export, SIGNAL(triggered()), this, SLOT(on_actionExport_triggered()));
_action_capture = new QAction(this);
_action_capture->setText(QApplication::translate(
"File", "&Capture...", 0, QApplication::UnicodeUTF8));
"File", "&Capture...", 0));
_action_capture->setIcon(QIcon::fromTheme("file",
QIcon(":/icons/capture.png")));
_action_capture->setObjectName(QString::fromUtf8("actionCapture"));
@ -84,7 +92,7 @@ void FileBar::on_actionOpen_triggered()
// Show the dialog
const QString file_name = QFileDialog::getOpenFileName(
this, tr("Open File"), "", tr(
"DSView Sessions (*.dsl)"));
"DSView Sessions (*.dsl);;All Files (*.*)"));
if (!file_name.isEmpty())
load_file(file_name);
}
@ -108,6 +116,45 @@ 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 if (_session.get_device()->dev_inst()->mode != LOGIC) {
QMessageBox msg(this);
msg.setText("Export Data");
msg.setInformativeText("DSLogic currently only support exporting logic data to file!");
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 +176,13 @@ void FileBar::on_actionSave_triggered()
msg.setIcon(QMessageBox::Warning);
msg.exec();
}else {
const QString file_name = QFileDialog::getSaveFileName(
QString file_name = QFileDialog::getSaveFileName(
this, tr("Save File"), "",
tr("DSView Session (*.dsl)"));
if (!file_name.isEmpty()) {
QFileInfo f(file_name);
if(f.suffix().compare("dsl"))
file_name.append(tr(".dsl"));
_session.save_file(file_name.toStdString());
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -109,7 +109,7 @@ 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),
@ -173,7 +173,7 @@ DsoSignal::~DsoSignal()
{
}
shared_ptr<pv::data::SignalData> DsoSignal::data() const
boost::shared_ptr<pv::data::SignalData> DsoSignal::data() const
{
return _data;
}
@ -582,7 +582,7 @@ void DsoSignal::paint_mid(QPainter &p, int left, int right)
return;
_scale = height * 1.0f / 256;
const shared_ptr<pv::data::DsoSnapshot> &snapshot =
const boost::shared_ptr<pv::data::DsoSnapshot> &snapshot =
snapshots.front();
const uint16_t number_channels = snapshot->get_channel_num();
@ -846,8 +846,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 +856,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;

View File

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

View File

@ -160,7 +160,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event)
const boost::shared_ptr<Trace> mTrace =
get_mTrace(action, event->pos());
if (action == Trace::LABEL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
dsoSig->auto_set();
}
@ -239,8 +239,8 @@ void Header::mousePressEvent(QMouseEvent *event)
else
mTrace->set_trig(Trace::EDGETRIG);
} else if (action == Trace::VDIAL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
boost::shared_ptr<view::DsoSignal> dsoSig;
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_hDialActive(false);
if (t != mTrace) {
@ -251,17 +251,17 @@ void Header::mousePressEvent(QMouseEvent *event)
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace))
dsoSig->set_vDialActive(!dsoSig->get_vDialActive());
} else if (action == Trace::HDIAL && mTrace) {
shared_ptr<view::DsoSignal> dsoSig;
boost::shared_ptr<view::DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
if (dsoSig->get_hDialActive()) {
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_vDialActive(false);
dsoSig->set_hDialActive(false);
}
}
} else {
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
dsoSig->set_vDialActive(false);
dsoSig->set_hDialActive(true);
@ -270,12 +270,12 @@ 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);
@ -287,7 +287,7 @@ void Header::mousePressEvent(QMouseEvent *event)
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 +330,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 +407,7 @@ void Header::mouseMoveEvent(QMouseEvent *event)
// Ensure the Trace is selected
sig->select(true);
} else {
shared_ptr<DsoSignal> dsoSig;
boost::shared_ptr<DsoSignal> dsoSig;
if (dsoSig = dynamic_pointer_cast<DsoSignal>(sig)) {
dsoSig->set_zeroPos(y);
dsoSig->select(false);

View File

@ -85,12 +85,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;
}

View File

@ -27,7 +27,7 @@
#include <boost/foreach.hpp>
#include <QtGui/QApplication>
#include <QApplication>
#include <QEvent>
#include <QMouseEvent>
#include <QScrollBar>
@ -211,10 +211,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,19 +273,19 @@ 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());
#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(
vector< boost::shared_ptr<Trace> > traces(
sigs.size() + decode_sigs.size());
#else
vector< shared_ptr<Trace> > traces(sigs.size());
vector< boost::shared_ptr<Trace> > traces(sigs.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);
@ -295,8 +295,8 @@ vector< shared_ptr<Trace> > View::get_traces() const
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);
@ -379,14 +379,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 +406,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;
@ -473,8 +473,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) ||
@ -489,7 +489,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);
@ -557,9 +557,9 @@ int View::headerWidth()
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);
@ -796,8 +796,8 @@ int View::get_view_width()
{
int view_width = 0;
if (_session.get_device()->dev_inst()->mode == DSO) {
const vector< shared_ptr<Signal> > sigs(_session.get_signals());
BOOST_FOREACH(const shared_ptr<Signal> s, sigs) {
const vector< boost::shared_ptr<Signal> > sigs(_session.get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
view_width = max((double)view_width, s->get_view_rect().width());
}
} else {

View File

@ -75,7 +75,7 @@ public:
static const QSizeF LabelPadding;
static const int WellPixelsPerSample = 10.0f;
static const double MaxViewRate = 1.0f;
static constexpr double MaxViewRate = 1.0f;
static const int MaxPixelsPerSample = 100.0f;
public:

View File

@ -79,8 +79,8 @@ 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());
}
@ -105,8 +105,8 @@ 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());
@ -132,7 +132,7 @@ void Viewport::paintEvent(QPaintEvent *event)
paintSignals(p);
}
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (t->enabled())
@ -148,7 +148,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 ||
@ -162,7 +162,7 @@ void Viewport::paintSignals(QPainter &p)
QPainter dbp(&pixmap);
dbp.initFrom(this);
//p.setRenderHint(QPainter::Antialiasing, false);
BOOST_FOREACH(const shared_ptr<Trace> t, traces)
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces)
{
assert(t);
if (t->enabled())
@ -361,10 +361,10 @@ void Viewport::mousePressEvent(QMouseEvent *event)
// _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;
@ -387,7 +387,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 {
@ -503,7 +503,7 @@ void Viewport::measure()
const vector< boost::shared_ptr<Signal> > sigs(_view.session().get_signals());
BOOST_FOREACH(const boost::shared_ptr<Signal> s, sigs) {
assert(s);
shared_ptr<view::LogicSignal> logicSig;
boost::shared_ptr<view::LogicSignal> logicSig;
if (logicSig = dynamic_pointer_cast<view::LogicSignal>(s)) {
if (logicSig->measure(_view.hover_point(), _cur_sample, _nxt_sample, _thd_sample)) {
_measure_shown = true;

View File

@ -47,6 +47,7 @@ class Viewport : public QWidget
public:
static const int HitCursorMargin = 10;
static const double HitCursorTimeMargin;
public:
explicit Viewport(View &parent);

View File

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

View File

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

View File

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

View File

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

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

@ -0,0 +1,225 @@
/*
* 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;
};
/*
* 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;
(void)options;
if (!o || !o->sdi)
return SR_ERR_ARG;
ctx = g_malloc0(sizeof(struct context));
o->priv = ctx;
ctx->separator = ',';
/* Get the number of channels, and the unitsize. */
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++;
}
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;
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 */
num_channels = g_slist_length(o->sdi->channels);
g_string_append_printf(header, "; Channels (%d/%d):",
ctx->num_enabled_channels, num_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, " %s,", ch->name);
}
if (o->sdi->channels)
/* Drop last separator. */
g_string_truncate(header, header->len - 1);
g_string_append_printf(header, "\n");
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, "; Samplerate: %s\n", samplerate_s);
g_free(samplerate_s);
}
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;
int idx;
uint64_t i, j;
gchar *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) {
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, c ? '1' : '0');
g_string_append_c(*out, ctx->separator);
}
if (j) {
/* Drop last separator. */
g_string_truncate(*out, (*out)->len - 1);
}
g_string_append_printf(*out, "\n");
}
break;
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->sdi)
return SR_ERR_ARG;
if (o->priv) {
ctx = o->priv;
g_free(ctx->channel_index);
g_free(o->priv);
o->priv = NULL;
}
return SR_OK;
}
SR_PRIV struct sr_output_module output_csv = {
.id = "csv",
.name = "CSV",
.desc = "Comma-separated values",
.exts = (const char*[]){"csv", NULL},
.options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

@ -0,0 +1,229 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE_STRING and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
#define LOG_PREFIX "output/gnuplot"
struct context {
unsigned int num_enabled_channels;
uint64_t samplerate;
uint64_t samplecount;
gboolean header_done;
uint8_t *prevsample;
int *channel_index;
};
static const char *gnuplot_header = "\
# Sample data in space-separated columns format usable by gnuplot.\n";
static const char *gnuplot_header2 = "\
#\n# Column\tChannel\n\
# -----------------------------------------------------------------------------\n\
# 0\t\tSample counter (for internal gnuplot purposes)\n";
static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
unsigned int i;
(void)options;
if (!o || !o->sdi)
return SR_ERR_ARG;
ctx = g_malloc0(sizeof(struct context));
o->priv = ctx;
ctx->num_enabled_channels = 0;
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
ctx->num_enabled_channels++;
}
if (ctx->num_enabled_channels <= 0) {
sr_err("No logic channel enabled.");
return SR_ERR;
}
ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
/* Once more to map the enabled channels. */
for (i = 0, l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
ctx->channel_index[i++] = ch->index;
}
return SR_OK;
}
static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
GVariant *gvar;
GString *header;
time_t t;
unsigned int num_channels, i;
char *samplerate_s;
ctx = o->priv;
if (ctx->samplerate == 0) {
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
&gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
}
}
t = time(NULL);
header = g_string_sized_new(512);
g_string_printf(header, "%s", gnuplot_header);
g_string_append_printf(header, "# Generated by %s on %s",
PACKAGE_STRING, ctime(&t));
num_channels = g_slist_length(o->sdi->channels);
g_string_append_printf(header, "# Acquisition with %d/%d channels",
ctx->num_enabled_channels, num_channels);
if (ctx->samplerate != 0) {
samplerate_s = sr_samplerate_string(ctx->samplerate);
g_string_append_printf(header, " at %s", samplerate_s);
g_free(samplerate_s);
}
g_string_append_printf(header, "\n");
g_string_append_printf(header, "%s", gnuplot_header2);
/* Columns / channels */
for (i = 0; i < ctx->num_enabled_channels; i++) {
ch = g_slist_nth_data(o->sdi->channels, ctx->channel_index[i]);
g_string_append_printf(header, "# %d\t\t%s\n", i + 1, ch->name);
}
return header;
}
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
const struct sr_datafeed_logic *logic;
const struct sr_config *src;
GSList *l;
struct context *ctx;
const uint8_t *sample;
unsigned int curbit, p, idx, i;
*out = NULL;
if (!o || !o->priv)
return SR_ERR_BUG;
ctx = o->priv;
if (packet->type == SR_DF_META) {
meta = packet->payload;
for (l = meta->config; l; l = l->next) {
src = l->data;
if (src->key != SR_CONF_SAMPLERATE)
continue;
ctx->samplerate = g_variant_get_uint64(src->data);
}
}
if (packet->type != SR_DF_LOGIC)
return SR_OK;
logic = packet->payload;
if (!ctx->prevsample) {
/* Can't allocate this until we know the stream's unitsize. */
ctx->prevsample = g_malloc0(logic->unitsize);
}
if (!ctx->header_done) {
*out = gen_header(o);
ctx->header_done = TRUE;
} else {
*out = g_string_sized_new(512);
}
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
sample = logic->data + i;
ctx->samplecount++;
/*
* Don't output the same sample multiple times, but make
* sure to output at least the first and last sample.
*/
if (i > 0 && i < logic->length - logic->unitsize) {
if (!memcmp(sample, ctx->prevsample, logic->unitsize))
continue;
}
memcpy(ctx->prevsample, sample, logic->unitsize);
/* The first column is a counter (needed for gnuplot). */
g_string_append_printf(*out, "%" PRIu64 "\t", ctx->samplecount);
/* The next columns are the values of all channels. */
for (p = 0; p < ctx->num_enabled_channels; p++) {
idx = ctx->channel_index[p];
curbit = (sample[idx / 8] & ((uint8_t) (1 << (idx % 8)))) >> (idx % 8);
g_string_append_printf(*out, "%d ", curbit);
}
g_string_append_printf(*out, "\n");
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->priv)
return SR_ERR_BUG;
ctx = o->priv;
g_free(ctx->channel_index);
g_free(ctx->prevsample);
g_free(ctx);
return SR_OK;
}
SR_PRIV struct sr_output_module output_gnuplot = {
.id = "gnuplot",
.name = "Gnuplot",
.desc = "Gnuplot data file format",
.exts = (const char*[]){"dat", NULL},
.options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

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

View File

@ -1,77 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/binary: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
static int data(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
{
uint8_t *outbuf;
(void)o;
if (!data_in) {
sr_err("%s: data_in was NULL", __func__);
return SR_ERR_ARG;
}
if (!length_out) {
sr_err("%s: length_out was NULL", __func__);
return SR_ERR_ARG;
}
if (length_in == 0) {
sr_err("%s: length_in was 0", __func__);
return SR_ERR_ARG;
}
if (!(outbuf = g_try_malloc0(length_in))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
memcpy(outbuf, data_in, length_in);
*data_out = outbuf;
*length_out = length_in;
return SR_OK;
}
SR_PRIV struct sr_output_format output_binary = {
.id = "binary",
.description = "Raw binary",
.df_type = SR_DF_LOGIC,
.init = NULL,
.data = data,
.event = NULL,
};

View File

@ -1,225 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE_STRING and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/csv: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
struct context {
unsigned int num_enabled_probes;
unsigned int unitsize;
uint64_t samplerate;
GString *header;
char separator;
};
/*
* TODO:
* - Option to specify delimiter character and/or string.
* - Option to (not) print metadata as comments.
* - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
* - Option to (not) print samplenumber / time as extra column.
* - Option to "compress" output (only print changed samples, VCD-like).
* - Option to print comma-separated bits, or whole bytes/words (for 8/16
* probe LAs) as ASCII/hex etc. etc.
* - Trigger support.
*/
static int init(struct sr_output *o)
{
struct context *ctx;
struct sr_channel *probe;
GSList *l;
GVariant *gvar;
int num_probes;
time_t t;
if (!o) {
sr_err("%s: o was NULL", __func__);
return SR_ERR_ARG;
}
if (!o->sdi) {
sr_err("%s: o->sdi was NULL", __func__);
return SR_ERR_ARG;
}
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
sr_err("%s: ctx malloc failed", __func__);
return SR_ERR_MALLOC;
}
o->internal = ctx;
/* Get the number of probes, and the unitsize. */
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (probe->enabled)
ctx->num_enabled_probes++;
}
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
num_probes = g_slist_length(o->sdi->channels);
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
} else
ctx->samplerate = 0;
ctx->separator = ',';
ctx->header = g_string_sized_new(512);
t = time(NULL);
/* Some metadata */
g_string_append_printf(ctx->header, "; CSV, generated by %s on %s",
PACKAGE_STRING, ctime(&t));
g_string_append_printf(ctx->header, "; Samplerate: %"PRIu64"\n",
ctx->samplerate);
/* Columns / channels */
g_string_append_printf(ctx->header, "; Channels (%d/%d): ",
ctx->num_enabled_probes, num_probes);
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (probe->enabled)
g_string_append_printf(ctx->header, "%s, ", probe->name);
}
g_string_append_printf(ctx->header, "\n");
return SR_OK;
}
static int event(struct sr_output *o, int event_type, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
if (!o) {
sr_err("%s: o was NULL", __func__);
return SR_ERR_ARG;
}
if (!(ctx = o->internal)) {
sr_err("%s: o->internal was NULL", __func__);
return SR_ERR_ARG;
}
if (!data_out) {
sr_err("%s: data_out was NULL", __func__);
return SR_ERR_ARG;
}
switch (event_type) {
case SR_DF_TRIGGER:
sr_dbg("%s: SR_DF_TRIGGER event", __func__);
/* TODO */
*data_out = NULL;
*length_out = 0;
break;
case SR_DF_END:
sr_dbg("%s: SR_DF_END event", __func__);
/* TODO */
*data_out = NULL;
*length_out = 0;
g_free(o->internal);
o->internal = NULL;
break;
default:
sr_err("%s: unsupported event type: %d", __func__, event_type);
*data_out = NULL;
*length_out = 0;
break;
}
return SR_OK;
}
static int data(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
{
struct context *ctx;
GString *outstr;
uint64_t sample, i;
int j;
if (!o) {
sr_err("%s: o was NULL", __func__);
return SR_ERR_ARG;
}
if (!(ctx = o->internal)) {
sr_err("%s: o->internal was NULL", __func__);
return SR_ERR_ARG;
}
if (!data_in) {
sr_err("%s: data_in was NULL", __func__);
return SR_ERR_ARG;
}
if (ctx->header) {
/* First data packet. */
outstr = ctx->header;
ctx->header = NULL;
} else {
outstr = g_string_sized_new(512);
}
for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
memcpy(&sample, data_in + i, ctx->unitsize);
for (j = ctx->num_enabled_probes - 1; j >= 0; j--) {
g_string_append_printf(outstr, "%d%c",
(int)((sample & (1 << j)) >> j),
ctx->separator);
}
g_string_append_printf(outstr, "\n");
}
*data_out = (uint8_t *)outstr->str;
*length_out = outstr->len;
g_string_free(outstr, FALSE);
return SR_OK;
}
SR_PRIV struct sr_output_format output_csv = {
.id = "csv",
.description = "Comma-separated values (CSV)",
.df_type = SR_DF_LOGIC,
.init = init,
.data = data,
.event = event,
};

View File

@ -1,231 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/vcd: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
struct context {
int num_enabled_probes;
GArray *probeindices;
GString *header;
uint8_t *prevsample;
int period;
uint64_t samplerate;
unsigned int unitsize;
};
static const char *vcd_header_comment = "\
$comment\n Acquisition with %d/%d probes at %s\n$end\n";
static int init(struct sr_output *o)
{
struct context *ctx;
struct sr_channel *probe;
GSList *l;
GVariant *gvar;
int num_probes, i;
char *samplerate_s, *frequency_s, *timestamp;
time_t t;
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
sr_err("%s: ctx malloc failed", __func__);
return SR_ERR_MALLOC;
}
o->internal = ctx;
ctx->num_enabled_probes = 0;
ctx->probeindices = g_array_new(FALSE, FALSE, sizeof(int));
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (!probe->enabled)
continue;
ctx->probeindices = g_array_append_val(
ctx->probeindices, probe->index);
ctx->num_enabled_probes++;
}
if (ctx->num_enabled_probes > 94) {
sr_err("VCD only supports 94 probes.");
return SR_ERR;
}
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
ctx->header = g_string_sized_new(512);
num_probes = g_slist_length(o->sdi->channels);
/* timestamp */
t = time(NULL);
timestamp = g_strdup(ctime(&t));
timestamp[strlen(timestamp)-1] = 0;
g_string_printf(ctx->header, "$date %s $end\n", timestamp);
g_free(timestamp);
/* generator */
g_string_append_printf(ctx->header, "$version %s %s $end\n",
PACKAGE, PACKAGE_VERSION);
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
if (!((samplerate_s = sr_samplerate_string(ctx->samplerate)))) {
g_string_free(ctx->header, TRUE);
g_free(ctx);
return SR_ERR;
}
g_string_append_printf(ctx->header, vcd_header_comment,
ctx->num_enabled_probes, num_probes, samplerate_s);
g_free(samplerate_s);
}
/* timescale */
/* VCD can only handle 1/10/100 (s - fs), so scale up first */
if (ctx->samplerate > SR_MHZ(1))
ctx->period = SR_GHZ(1);
else if (ctx->samplerate > SR_KHZ(1))
ctx->period = SR_MHZ(1);
else
ctx->period = SR_KHZ(1);
if (!(frequency_s = sr_period_string(ctx->period))) {
g_string_free(ctx->header, TRUE);
g_free(ctx);
return SR_ERR;
}
g_string_append_printf(ctx->header, "$timescale %s $end\n", frequency_s);
g_free(frequency_s);
/* scope */
g_string_append_printf(ctx->header, "$scope module %s $end\n", PACKAGE);
/* Wires / channels */
for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
probe = l->data;
if (!probe->enabled)
continue;
g_string_append_printf(ctx->header, "$var wire 1 %c %s $end\n",
(char)('!' + i), probe->name);
}
g_string_append(ctx->header, "$upscope $end\n"
"$enddefinitions $end\n$dumpvars\n");
if (!(ctx->prevsample = g_try_malloc0(ctx->unitsize))) {
g_string_free(ctx->header, TRUE);
g_free(ctx);
sr_err("%s: ctx->prevsample malloc failed", __func__);
return SR_ERR_MALLOC;
}
return SR_OK;
}
static int receive(struct sr_output *o, const struct sr_dev_inst *sdi,
const struct sr_datafeed_packet *packet, GString **out)
{
const struct sr_datafeed_logic *logic;
struct context *ctx;
unsigned int i;
int p, curbit, prevbit, index;
uint8_t *sample;
static uint64_t samplecount = 0;
(void)sdi;
*out = NULL;
if (!o || !o->internal)
return SR_ERR_ARG;
ctx = o->internal;
if (packet->type == SR_DF_END) {
*out = g_string_new("$dumpoff\n$end\n");
return SR_OK;
} else if (packet->type != SR_DF_LOGIC)
return SR_OK;
if (ctx->header) {
/* The header is still here, this must be the first packet. */
*out = ctx->header;
ctx->header = NULL;
} else {
*out = g_string_sized_new(512);
}
logic = packet->payload;
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
samplecount++;
sample = logic->data + i;
for (p = 0; p < ctx->num_enabled_probes; p++) {
index = g_array_index(ctx->probeindices, int, p);
curbit = (sample[p / 8] & (((uint8_t) 1) << index)) >> index;
prevbit = (ctx->prevsample[p / 8] & (((uint64_t) 1) << index)) >> index;
/* VCD only contains deltas/changes of signals. */
if (prevbit == curbit)
continue;
/* Output which signal changed to which value. */
g_string_append_printf(*out, "#%" PRIu64 "\n%i%c\n",
(uint64_t)(((float)samplecount / ctx->samplerate)
* ctx->period), curbit, (char)('!' + p));
}
memcpy(ctx->prevsample, sample, ctx->unitsize);
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->internal)
return SR_ERR_ARG;
ctx = o->internal;
g_free(ctx);
return SR_OK;
}
struct sr_output_format output_vcd = {
.id = "vcd",
.description = "Value Change Dump (VCD)",
.df_type = SR_DF_LOGIC,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

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

View File

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

View File

@ -1,33 +0,0 @@
##
## This file is part of the libsigrok project.
##
## Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
# Local lib, this is NOT meant to be installed!
noinst_LTLIBRARIES = libsigrok4DSLoutputtext.la
libsigrok4DSLoutputtext_la_SOURCES = \
text.c \
text.h \
bits.c \
hex.c \
ascii.c
libsigrok4DSLoutputtext_la_CFLAGS = \
-I$(top_srcdir)

View File

@ -1,136 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/ascii: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV int init_ascii(struct sr_output *o)
{
return init(o, DEFAULT_BPL_ASCII, MODE_ASCII);
}
SR_PRIV int data_ascii(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
unsigned int outsize, offset, p;
int max_linelen;
const uint8_t *sample;
uint8_t *outbuf;
ctx = o->internal;
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
+ ctx->samples_per_line / 8;
/*
* Calculate space needed for probes. Set aside 512 bytes for
* extra output, e.g. trigger.
*/
outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
* (ctx->num_enabled_probes * max_linelen);
if (!(outbuf = g_try_malloc0(outsize + 1))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
outbuf[0] = '\0';
if (ctx->header) {
/* The header is still here, this must be the first packet. */
strncpy((char *)outbuf, ctx->header, outsize);
g_free(ctx->header);
ctx->header = NULL;
}
if (length_in >= ctx->unitsize) {
for (offset = 0; offset <= length_in - ctx->unitsize;
offset += ctx->unitsize) {
sample = data_in + offset;
char tmpval[ctx->num_enabled_probes];
for (p = 0; p < ctx->num_enabled_probes; p++) {
uint8_t curbit = (sample[p / 8] & ((uint8_t) 1 << (p % 8)));
uint8_t prevbit = (ctx->prevsample[p / 8] &
((uint8_t) 1 << (p % 8)));
if (curbit < prevbit && ctx->line_offset > 0) {
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset-1] = '\\';
}
if (curbit > prevbit) {
tmpval[p] = '/';
} else {
if (curbit)
tmpval[p] = '"';
else
tmpval[p] = '.';
}
}
/* End of line. */
if (ctx->spl_cnt >= ctx->samples_per_line) {
flush_linebufs(ctx, outbuf);
ctx->line_offset = ctx->spl_cnt = 0;
ctx->mark_trigger = -1;
}
for (p = 0; p < ctx->num_enabled_probes; p++) {
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset] = tmpval[p];
}
ctx->line_offset++;
ctx->spl_cnt++;
memcpy(ctx->prevsample, sample, ctx->unitsize);
}
} else {
sr_info("Short buffer (length_in=%" PRIu64 ").", length_in);
}
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
return SR_OK;
}
SR_PRIV struct sr_output_format output_text_ascii = {
.id = "ascii",
.description = "ASCII",
.df_type = SR_DF_LOGIC,
.init = init_ascii,
.data = data_ascii,
.event = event,
};

View File

@ -1,119 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/bits: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV int init_bits(struct sr_output *o)
{
return init(o, DEFAULT_BPL_BITS, MODE_BITS);
}
SR_PRIV int data_bits(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
unsigned int outsize, offset, p;
int max_linelen;
const uint8_t *sample;
uint8_t *outbuf, c;
ctx = o->internal;
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
+ ctx->samples_per_line / 8;
/*
* Calculate space needed for probes. Set aside 512 bytes for
* extra output, e.g. trigger.
*/
outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
* (ctx->num_enabled_probes * max_linelen);
if (!(outbuf = g_try_malloc0(outsize + 1))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
outbuf[0] = '\0';
if (ctx->header) {
/* The header is still here, this must be the first packet. */
strncpy((char *)outbuf, ctx->header, outsize);
g_free(ctx->header);
ctx->header = NULL;
}
if (length_in >= ctx->unitsize) {
for (offset = 0; offset <= length_in - ctx->unitsize;
offset += ctx->unitsize) {
sample = data_in + offset;
for (p = 0; p < ctx->num_enabled_probes; p++) {
c = (sample[p / 8] & ((uint8_t) 1 << (p % 8))) ? '1' : '0';
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset] = c;
}
ctx->line_offset++;
ctx->spl_cnt++;
/* Add a space every 8th bit. */
if ((ctx->spl_cnt & 7) == 0) {
for (p = 0; p < ctx->num_enabled_probes; p++)
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset] = ' ';
ctx->line_offset++;
}
/* End of line. */
if (ctx->spl_cnt >= ctx->samples_per_line) {
flush_linebufs(ctx, outbuf);
ctx->line_offset = ctx->spl_cnt = 0;
ctx->mark_trigger = -1;
}
}
} else {
sr_info("Short buffer (length_in=%" PRIu64 ").", length_in);
}
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
return SR_OK;
}
SR_PRIV struct sr_output_format output_text_bits = {
.id = "bits",
.description = "Bits",
.df_type = SR_DF_LOGIC,
.init = init_bits,
.data = data_bits,
.event = event,
};

View File

@ -1,112 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/hex: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV int init_hex(struct sr_output *o)
{
return init(o, DEFAULT_BPL_HEX, MODE_HEX);
}
SR_PRIV int data_hex(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
unsigned int outsize, offset, p;
int max_linelen;
const uint8_t *sample;
uint8_t *outbuf;
ctx = o->internal;
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
+ ctx->samples_per_line / 2;
outsize = length_in / ctx->unitsize * ctx->num_enabled_probes
/ ctx->samples_per_line * max_linelen + 512;
if (!(outbuf = g_try_malloc0(outsize + 1))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
outbuf[0] = '\0';
if (ctx->header) {
/* The header is still here, this must be the first packet. */
strncpy((char *)outbuf, ctx->header, outsize);
g_free(ctx->header);
ctx->header = NULL;
}
ctx->line_offset = 0;
for (offset = 0; offset <= length_in - ctx->unitsize;
offset += ctx->unitsize) {
sample = data_in + offset;
for (p = 0; p < ctx->num_enabled_probes; p++) {
ctx->linevalues[p] <<= 1;
if (sample[p / 8] & ((uint8_t) 1 << (p % 8)))
ctx->linevalues[p] |= 1;
sprintf((char *)ctx->linebuf + (p * ctx->linebuf_len) +
ctx->line_offset, "%.2x", ctx->linevalues[p]);
}
ctx->spl_cnt++;
/* Add a space after every complete hex byte. */
if ((ctx->spl_cnt & 7) == 0) {
for (p = 0; p < ctx->num_enabled_probes; p++)
ctx->linebuf[p * ctx->linebuf_len +
ctx->line_offset + 2] = ' ';
ctx->line_offset += 3;
}
/* End of line. */
if (ctx->spl_cnt >= ctx->samples_per_line) {
flush_linebufs(ctx, outbuf);
ctx->line_offset = ctx->spl_cnt = 0;
}
}
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
return SR_OK;
}
SR_PRIV struct sr_output_format output_text_hex = {
.id = "hex",
.description = "Hexadecimal",
.df_type = SR_DF_LOGIC,
.init = init_hex,
.data = data_hex,
.event = event,
};

View File

@ -1,208 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE_STRING and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
#include "text.h"
/* Message logging helpers with subsystem-specific prefix string. */
#define LOG_PREFIX "output/text: "
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
SR_PRIV void flush_linebufs(struct context *ctx, uint8_t *outbuf)
{
static int max_probename_len = 0;
int len, i;
GSList *l;
char *probe_name;
if (ctx->linebuf[0] == 0)
return;
if (max_probename_len == 0) {
/* First time through... */
for (l = ctx->probenames; l; l = l->next) {
probe_name = l->data;
len = strlen(probe_name);
if (len > max_probename_len)
max_probename_len = len;
}
}
for (i = 0, l = ctx->probenames; l; l = l->next, i++) {
probe_name = l->data;
sprintf((char *)outbuf + strlen((const char *)outbuf),
"%*s:%s\n", max_probename_len,
probe_name, ctx->linebuf + i * ctx->linebuf_len);
}
/* Mark trigger with a ^ character. */
if (ctx->mark_trigger != -1)
{
int space_offset = ctx->mark_trigger / 8;
if (ctx->mode == MODE_ASCII)
space_offset = 0;
sprintf((char *)outbuf + strlen((const char *)outbuf),
"T:%*s^\n", ctx->mark_trigger + space_offset, "");
}
memset(ctx->linebuf, 0, i * ctx->linebuf_len);
}
SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode)
{
struct context *ctx;
struct sr_channel *probe;
GSList *l;
GVariant *gvar;
uint64_t samplerate;
int num_probes, ret;
char *samplerate_s;
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
sr_err("%s: ctx malloc failed", __func__);
return SR_ERR_MALLOC;
}
o->internal = ctx;
ctx->num_enabled_probes = 0;
ctx->probenames = NULL;
for (l = o->sdi->channels; l; l = l->next) {
probe = l->data;
if (!probe->enabled)
continue;
ctx->probenames = g_slist_append(ctx->probenames, probe->name);
ctx->num_enabled_probes++;
}
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
ctx->line_offset = 0;
ctx->spl_cnt = 0;
ctx->mark_trigger = -1;
ctx->mode = mode;
ret = SR_OK;
if (o->param && o->param[0]) {
ctx->samples_per_line = strtoul(o->param, NULL, 10);
if (ctx->samples_per_line < 1) {
ret = SR_ERR;
goto err;
}
} else
ctx->samples_per_line = default_spl;
if (!(ctx->header = g_try_malloc0(512))) {
sr_err("%s: ctx->header malloc failed", __func__);
ret = SR_ERR_MALLOC;
goto err;
}
snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING);
num_probes = g_slist_length(o->sdi->channels);
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
if (!(samplerate_s = sr_samplerate_string(samplerate))) {
ret = SR_ERR;
goto err;
}
snprintf(ctx->header + strlen(ctx->header),
511 - strlen(ctx->header),
"Acquisition with %d/%d probes at %s\n",
ctx->num_enabled_probes, num_probes, samplerate_s);
g_free(samplerate_s);
}
ctx->linebuf_len = ctx->samples_per_line * 2 + 4;
if (!(ctx->linebuf = g_try_malloc0(num_probes * ctx->linebuf_len))) {
sr_err("%s: ctx->linebuf malloc failed", __func__);
ret = SR_ERR_MALLOC;
goto err;
}
if (!(ctx->linevalues = g_try_malloc0(num_probes))) {
sr_err("%s: ctx->linevalues malloc failed", __func__);
ret = SR_ERR_MALLOC;
}
if (mode == MODE_ASCII &&
!(ctx->prevsample = g_try_malloc0(num_probes / 8))) {
sr_err("%s: ctx->prevsample malloc failed", __func__);
ret = SR_ERR_MALLOC;
}
err:
if (ret != SR_OK) {
g_free(ctx->header);
g_free(ctx);
}
return ret;
}
SR_PRIV int event(struct sr_output *o, int event_type, uint8_t **data_out,
uint64_t *length_out)
{
struct context *ctx;
int outsize;
uint8_t *outbuf;
ctx = o->internal;
switch (event_type) {
case SR_DF_TRIGGER:
ctx->mark_trigger = ctx->spl_cnt;
*data_out = NULL;
*length_out = 0;
break;
case SR_DF_END:
outsize = ctx->num_enabled_probes
* (ctx->samples_per_line + 20) + 512;
if (!(outbuf = g_try_malloc0(outsize))) {
sr_err("%s: outbuf malloc failed", __func__);
return SR_ERR_MALLOC;
}
flush_linebufs(ctx, outbuf);
*data_out = outbuf;
*length_out = strlen((const char *)outbuf);
g_free(o->internal);
o->internal = NULL;
break;
default:
*data_out = NULL;
*length_out = 0;
break;
}
return SR_OK;
}

View File

@ -1,69 +0,0 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_OUTPUT_TEXT_TEXT_H
#define LIBSIGROK_OUTPUT_TEXT_TEXT_H
#define DEFAULT_BPL_BITS 64
#define DEFAULT_BPL_HEX 192
#define DEFAULT_BPL_ASCII 74
enum outputmode {
MODE_BITS = 1,
MODE_HEX,
MODE_ASCII,
};
struct context {
unsigned int num_enabled_probes;
int samples_per_line;
unsigned int unitsize;
int line_offset;
int linebuf_len;
GSList *probenames;
uint8_t *linebuf;
int spl_cnt;
uint8_t *linevalues;
char *header;
int mark_trigger;
uint8_t *prevsample;
enum outputmode mode;
};
SR_PRIV void flush_linebufs(struct context *ctx, uint8_t *outbuf);
SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode);
SR_PRIV int event(struct sr_output *o, int event_type, uint8_t **data_out,
uint64_t *length_out);
SR_PRIV int init_bits(struct sr_output *o);
SR_PRIV int data_bits(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out);
SR_PRIV int init_hex(struct sr_output *o);
SR_PRIV int data_hex(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out);
SR_PRIV int init_ascii(struct sr_output *o);
SR_PRIV int data_ascii(struct sr_output *o, const uint8_t *data_in,
uint64_t length_in, uint8_t **data_out,
uint64_t *length_out);
#endif

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

@ -0,0 +1,271 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "config.h" /* Needed for PACKAGE and others. */
#include "libsigrok.h"
#include "libsigrok-internal.h"
#define LOG_PREFIX "output/vcd"
struct context {
int num_enabled_channels;
GArray *channelindices;
uint8_t *prevsample;
gboolean header_done;
int period;
int *channel_index;
uint64_t samplerate;
uint64_t samplecount;
};
static int init(struct sr_output *o, GHashTable *options)
{
struct context *ctx;
struct sr_channel *ch;
GSList *l;
int num_enabled_channels, i;
(void)options;
num_enabled_channels = 0;
for (l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
num_enabled_channels++;
}
if (num_enabled_channels > 94) {
sr_err("VCD only supports 94 channels.");
return SR_ERR;
}
ctx = g_malloc0(sizeof(struct context));
o->priv = ctx;
ctx->num_enabled_channels = num_enabled_channels;
ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
/* Once more to map the enabled channels. */
for (i = 0, l = o->sdi->channels; l; l = l->next) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
ctx->channel_index[i++] = ch->index;
}
return SR_OK;
}
static GString *gen_header(const struct sr_output *o)
{
struct context *ctx;
struct sr_channel *ch;
GVariant *gvar;
GString *header;
GSList *l;
time_t t;
int num_channels, i;
char *samplerate_s, *frequency_s, *timestamp;
ctx = o->priv;
header = g_string_sized_new(512);
num_channels = g_slist_length(o->sdi->channels);
/* timestamp */
t = time(NULL);
timestamp = g_strdup(ctime(&t));
timestamp[strlen(timestamp)-1] = 0;
g_string_printf(header, "$date %s $end\n", timestamp);
g_free(timestamp);
/* generator */
g_string_append_printf(header, "$version %s %s $end\n",
PACKAGE, PACKAGE_VERSION);
g_string_append_printf(header, "$comment\n Acquisition with "
"%d/%d channels", ctx->num_enabled_channels, num_channels);
if (ctx->samplerate == 0) {
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
&gvar) == SR_OK) {
ctx->samplerate = g_variant_get_uint64(gvar);
g_variant_unref(gvar);
}
}
if (ctx->samplerate != 0) {
samplerate_s = sr_samplerate_string(ctx->samplerate);
g_string_append_printf(header, " at %s", samplerate_s);
g_free(samplerate_s);
}
g_string_append_printf(header, "\n$end\n");
/* timescale */
/* VCD can only handle 1/10/100 (s - fs), so scale up first */
if (ctx->samplerate > SR_MHZ(1))
ctx->period = SR_GHZ(1);
else if (ctx->samplerate > SR_KHZ(1))
ctx->period = SR_MHZ(1);
else
ctx->period = SR_KHZ(1);
frequency_s = sr_period_string(ctx->period);
g_string_append_printf(header, "$timescale %s $end\n", frequency_s);
g_free(frequency_s);
/* scope */
g_string_append_printf(header, "$scope module %s $end\n", PACKAGE);
/* Wires / channels */
for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
ch = l->data;
if (ch->type != SR_CHANNEL_LOGIC)
continue;
if (!ch->enabled)
continue;
g_string_append_printf(header, "$var wire 1 %c %s $end\n",
(char)('!' + i), ch->name);
}
g_string_append(header, "$upscope $end\n$enddefinitions $end\n");
return header;
}
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
GString **out)
{
const struct sr_datafeed_meta *meta;
const struct sr_datafeed_logic *logic;
const struct sr_config *src;
GSList *l;
struct context *ctx;
unsigned int i;
int p, curbit, prevbit, index;
uint8_t *sample;
gboolean timestamp_written;
*out = NULL;
if (!o || !o->priv)
return SR_ERR_BUG;
ctx = o->priv;
switch (packet->type) {
case SR_DF_META:
meta = packet->payload;
for (l = meta->config; l; l = l->next) {
src = l->data;
if (src->key != SR_CONF_SAMPLERATE)
continue;
ctx->samplerate = g_variant_get_uint64(src->data);
}
break;
case SR_DF_LOGIC:
logic = packet->payload;
if (!ctx->header_done) {
*out = gen_header(o);
ctx->header_done = TRUE;
} else {
*out = g_string_sized_new(512);
}
if (!ctx->prevsample) {
/* Can't allocate this until we know the stream's unitsize. */
ctx->prevsample = g_malloc0(logic->unitsize);
}
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
sample = logic->data + i;
timestamp_written = FALSE;
for (p = 0; p < ctx->num_enabled_channels; p++) {
index = ctx->channel_index[p];
curbit = ((unsigned)sample[index / 8]
>> (index % 8)) & 1;
prevbit = ((unsigned)ctx->prevsample[index / 8]
>> (index % 8)) & 1;
/* VCD only contains deltas/changes of signals. */
if (prevbit == curbit && ctx->samplecount > 0)
continue;
/* Output timestamp of subsequent signal changes. */
if (!timestamp_written)
g_string_append_printf(*out, "#%.0f",
(double)ctx->samplecount /
ctx->samplerate * ctx->period);
/* Output which signal changed to which value. */
g_string_append_c(*out, ' ');
g_string_append_c(*out, '0' + curbit);
g_string_append_c(*out, '!' + p);
timestamp_written = TRUE;
}
if (timestamp_written)
g_string_append_c(*out, '\n');
ctx->samplecount++;
memcpy(ctx->prevsample, sample, logic->unitsize);
}
break;
case SR_DF_END:
/* Write final timestamp as length indicator. */
*out = g_string_sized_new(512);
g_string_printf(*out, "#%.0f\n",
(double)ctx->samplecount / ctx->samplerate * ctx->period);
break;
}
return SR_OK;
}
static int cleanup(struct sr_output *o)
{
struct context *ctx;
if (!o || !o->priv)
return SR_ERR_ARG;
ctx = o->priv;
g_free(ctx->prevsample);
g_free(ctx->channel_index);
g_free(ctx);
return SR_OK;
}
struct sr_output_module output_vcd = {
.id = "vcd",
.name = "VCD",
.desc = "Value Change Dump",
.exts = (const char*[]){"vcd", NULL},
.options = NULL,
.init = init,
.receive = receive,
.cleanup = cleanup,
};

View File

@ -132,7 +132,7 @@ SR_API struct sr_input_format **sr_input_list(void);
/*--- output/output.c -------------------------------------------------------*/
SR_API struct sr_output_format **sr_output_list(void);
SR_API const struct sr_output_module **sr_output_list(void);
/*--- strutil.c -------------------------------------------------------------*/

69
libsigrok4DSL/version.h Normal file
View File

@ -0,0 +1,69 @@
/*
* This file is part of the libsigrok project.
*
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBSIGROK_VERSION_H
#define LIBSIGROK_VERSION_H
/**
* @file
*
* Version number definitions and macros.
*/
/**
* @ingroup grp_versions
*
* @{
*/
/*
* Package version macros (can be used for conditional compilation).
*/
/** The libsigrok package 'major' version number. */
#define SR_PACKAGE_VERSION_MAJOR 0
/** The libsigrok package 'minor' version number. */
#define SR_PACKAGE_VERSION_MINOR 2
/** The libsigrok package 'micro' version number. */
#define SR_PACKAGE_VERSION_MICRO 0
/** The libsigrok package version ("major.minor.micro") as string. */
#define SR_PACKAGE_VERSION_STRING "0.2.0"
/*
* Library/libtool version macros (can be used for conditional compilation).
*/
/** The libsigrok libtool 'current' version number. */
#define SR_LIB_VERSION_CURRENT 1
/** The libsigrok libtool 'revision' version number. */
#define SR_LIB_VERSION_REVISION 2
/** The libsigrok libtool 'age' version number. */
#define SR_LIB_VERSION_AGE 0
/** The libsigrok libtool version ("current:revision:age") as string. */
#define SR_LIB_VERSION_STRING "1:2:0"
/** @} */
#endif