mirror of
https://github.com/DreamSourceLab/DSView.git
synced 2025-01-13 13:32:53 +08:00
Merge pull request #50 from asanza/develop
Add support for export capture data into multiple file formats.
This commit is contained in:
commit
1b1bb88e75
@ -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)
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QApplication>
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
@ -37,7 +37,7 @@ using namespace std;
|
||||
namespace pv {
|
||||
namespace dialogs {
|
||||
|
||||
DeviceOptions::DeviceOptions(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst) :
|
||||
DeviceOptions::DeviceOptions(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst) :
|
||||
QDialog(parent),
|
||||
_dev_inst(dev_inst),
|
||||
_layout(this),
|
||||
|
@ -37,7 +37,7 @@ using namespace std;
|
||||
namespace pv {
|
||||
namespace dialogs {
|
||||
|
||||
StreamOptions::StreamOptions(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst,
|
||||
StreamOptions::StreamOptions(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst,
|
||||
uint64_t sample_count, bool stream) :
|
||||
QDialog(parent),
|
||||
_dev_inst(dev_inst),
|
||||
|
@ -39,7 +39,7 @@ namespace dialogs {
|
||||
|
||||
const QString WaitingDialog::TIPS_INFO = "Waiting";
|
||||
|
||||
WaitingDialog::WaitingDialog(QWidget *parent, shared_ptr<pv::device::DevInst> dev_inst) :
|
||||
WaitingDialog::WaitingDialog(QWidget *parent, boost::shared_ptr<pv::device::DevInst> dev_inst) :
|
||||
QDialog(parent),
|
||||
_dev_inst(dev_inst),
|
||||
_button_box(QDialogButtonBox::Save | QDialogButtonBox::Abort,
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ private slots:
|
||||
void on_actionOpen_triggered();
|
||||
void on_actionSave_triggered();
|
||||
void on_actionCapture_triggered();
|
||||
void on_actionExport_triggered();
|
||||
|
||||
private:
|
||||
bool _enable;
|
||||
@ -67,6 +68,7 @@ private:
|
||||
|
||||
QAction *_action_open;
|
||||
QAction *_action_save;
|
||||
QAction *_action_export;
|
||||
QAction *_action_capture;
|
||||
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ LogoBar::LogoBar(SigSession &session, QWidget *parent) :
|
||||
|
||||
_about = new QAction(this);
|
||||
_about->setText(QApplication::translate(
|
||||
"File", "&About...", 0, QApplication::UnicodeUTF8));
|
||||
"File", "&About...", 0));
|
||||
_about->setIcon(QIcon::fromTheme("file",
|
||||
QIcon(":/icons/about.png")));
|
||||
_about->setObjectName(QString::fromUtf8("actionAbout"));
|
||||
@ -56,7 +56,7 @@ LogoBar::LogoBar(SigSession &session, QWidget *parent) :
|
||||
|
||||
_wiki = new QAction(this);
|
||||
_wiki->setText(QApplication::translate(
|
||||
"File", "&Wiki", 0, QApplication::UnicodeUTF8));
|
||||
"File", "&Wiki", 0));
|
||||
_wiki->setIcon(QIcon::fromTheme("file",
|
||||
QIcon(":/icons/wiki.png")));
|
||||
_wiki->setObjectName(QString::fromUtf8("actionWiki"));
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -63,7 +63,7 @@ bool GroupSignal::enabled() const
|
||||
return true;
|
||||
}
|
||||
|
||||
shared_ptr<pv::data::SignalData> GroupSignal::data() const
|
||||
boost::shared_ptr<pv::data::SignalData> GroupSignal::data() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
const boost::shared_ptr<Trace> mTrace =
|
||||
get_mTrace(action, event->pos());
|
||||
if (action == Trace::LABEL && mTrace) {
|
||||
shared_ptr<view::DsoSignal> dsoSig;
|
||||
boost::shared_ptr<view::DsoSignal> dsoSig;
|
||||
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
|
||||
dsoSig->auto_set();
|
||||
}
|
||||
@ -239,8 +239,8 @@ void Header::mousePressEvent(QMouseEvent *event)
|
||||
else
|
||||
mTrace->set_trig(Trace::EDGETRIG);
|
||||
} else if (action == Trace::VDIAL && mTrace) {
|
||||
shared_ptr<view::DsoSignal> dsoSig;
|
||||
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
|
||||
boost::shared_ptr<view::DsoSignal> dsoSig;
|
||||
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
|
||||
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
|
||||
dsoSig->set_hDialActive(false);
|
||||
if (t != mTrace) {
|
||||
@ -251,17 +251,17 @@ void Header::mousePressEvent(QMouseEvent *event)
|
||||
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace))
|
||||
dsoSig->set_vDialActive(!dsoSig->get_vDialActive());
|
||||
} else if (action == Trace::HDIAL && mTrace) {
|
||||
shared_ptr<view::DsoSignal> dsoSig;
|
||||
boost::shared_ptr<view::DsoSignal> dsoSig;
|
||||
if (dsoSig = dynamic_pointer_cast<view::DsoSignal>(mTrace)) {
|
||||
if (dsoSig->get_hDialActive()) {
|
||||
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
|
||||
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
|
||||
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
|
||||
dsoSig->set_vDialActive(false);
|
||||
dsoSig->set_hDialActive(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
|
||||
BOOST_FOREACH(const boost::shared_ptr<Trace> t, traces) {
|
||||
if(dsoSig = dynamic_pointer_cast<view::DsoSignal>(t)) {
|
||||
dsoSig->set_vDialActive(false);
|
||||
dsoSig->set_hDialActive(true);
|
||||
@ -270,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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -47,6 +47,7 @@ class Viewport : public QWidget
|
||||
|
||||
public:
|
||||
static const int HitCursorMargin = 10;
|
||||
static const double HitCursorTimeMargin;
|
||||
|
||||
public:
|
||||
explicit Viewport(View &parent);
|
||||
|
@ -261,7 +261,7 @@ static int sanity_check_all_input_modules(void)
|
||||
static int sanity_check_all_output_modules(void)
|
||||
{
|
||||
int i, errors, ret = SR_OK;
|
||||
struct sr_output_format **outputs;
|
||||
struct sr_output_module **outputs;
|
||||
const char *d;
|
||||
|
||||
sr_spew("Sanity-checking all output modules.");
|
||||
@ -276,18 +276,18 @@ static int sanity_check_all_output_modules(void)
|
||||
sr_err("No ID in module %d ('%s').", i, d);
|
||||
errors++;
|
||||
}
|
||||
if (!outputs[i]->description) {
|
||||
if (!outputs[i]->desc) {
|
||||
sr_err("No description in module %d ('%s').", i, d);
|
||||
errors++;
|
||||
}
|
||||
if (outputs[i]->df_type < 10000 || outputs[i]->df_type > 10007) {
|
||||
/*if (outputs[i]->df_type < 10000 || outputs[i]->df_type > 10007) {
|
||||
sr_err("Invalid df_type %d in module %d ('%s').",
|
||||
outputs[i]->df_type, i, d);
|
||||
errors++;
|
||||
}
|
||||
}*/
|
||||
|
||||
/* All modules must provide a data or recv API callback. */
|
||||
if (!outputs[i]->data && !outputs[i]->receive) {
|
||||
if (!outputs[i]->receive) {
|
||||
sr_err("No data/receive in module %d ('%s').", i, d);
|
||||
errors++;
|
||||
}
|
||||
|
@ -227,7 +227,6 @@ AC_CONFIG_FILES([Makefile version.h hardware/Makefile
|
||||
hardware/DSL/Makefile
|
||||
input/Makefile
|
||||
output/Makefile
|
||||
output/text/Makefile
|
||||
libsigrok4DSL.pc
|
||||
tests/Makefile
|
||||
])
|
||||
|
@ -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,
|
||||
|
@ -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
225
libsigrok4DSL/output/csv.c
Normal 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,
|
||||
};
|
229
libsigrok4DSL/output/gnuplot.c
Normal file
229
libsigrok4DSL/output/gnuplot.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "config.h" /* Needed for PACKAGE_STRING and others. */
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "output/gnuplot"
|
||||
|
||||
struct context {
|
||||
unsigned int num_enabled_channels;
|
||||
uint64_t samplerate;
|
||||
uint64_t samplecount;
|
||||
gboolean header_done;
|
||||
uint8_t *prevsample;
|
||||
int *channel_index;
|
||||
};
|
||||
|
||||
static const char *gnuplot_header = "\
|
||||
# Sample data in space-separated columns format usable by gnuplot.\n";
|
||||
static const char *gnuplot_header2 = "\
|
||||
#\n# Column\tChannel\n\
|
||||
# -----------------------------------------------------------------------------\n\
|
||||
# 0\t\tSample counter (for internal gnuplot purposes)\n";
|
||||
|
||||
|
||||
static int init(struct sr_output *o, GHashTable *options)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *ch;
|
||||
GSList *l;
|
||||
unsigned int i;
|
||||
|
||||
(void)options;
|
||||
|
||||
if (!o || !o->sdi)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
ctx = g_malloc0(sizeof(struct context));
|
||||
o->priv = ctx;
|
||||
ctx->num_enabled_channels = 0;
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_LOGIC)
|
||||
continue;
|
||||
if (!ch->enabled)
|
||||
continue;
|
||||
ctx->num_enabled_channels++;
|
||||
}
|
||||
if (ctx->num_enabled_channels <= 0) {
|
||||
sr_err("No logic channel enabled.");
|
||||
return SR_ERR;
|
||||
}
|
||||
ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
|
||||
|
||||
/* Once more to map the enabled channels. */
|
||||
for (i = 0, l = o->sdi->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_LOGIC)
|
||||
continue;
|
||||
if (!ch->enabled)
|
||||
continue;
|
||||
ctx->channel_index[i++] = ch->index;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static GString *gen_header(const struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *ch;
|
||||
GVariant *gvar;
|
||||
GString *header;
|
||||
time_t t;
|
||||
unsigned int num_channels, i;
|
||||
char *samplerate_s;
|
||||
|
||||
ctx = o->priv;
|
||||
if (ctx->samplerate == 0) {
|
||||
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
|
||||
&gvar) == SR_OK) {
|
||||
ctx->samplerate = g_variant_get_uint64(gvar);
|
||||
g_variant_unref(gvar);
|
||||
}
|
||||
}
|
||||
|
||||
t = time(NULL);
|
||||
header = g_string_sized_new(512);
|
||||
g_string_printf(header, "%s", gnuplot_header);
|
||||
g_string_append_printf(header, "# Generated by %s on %s",
|
||||
PACKAGE_STRING, ctime(&t));
|
||||
|
||||
num_channels = g_slist_length(o->sdi->channels);
|
||||
g_string_append_printf(header, "# Acquisition with %d/%d channels",
|
||||
ctx->num_enabled_channels, num_channels);
|
||||
if (ctx->samplerate != 0) {
|
||||
samplerate_s = sr_samplerate_string(ctx->samplerate);
|
||||
g_string_append_printf(header, " at %s", samplerate_s);
|
||||
g_free(samplerate_s);
|
||||
}
|
||||
g_string_append_printf(header, "\n");
|
||||
|
||||
g_string_append_printf(header, "%s", gnuplot_header2);
|
||||
|
||||
/* Columns / channels */
|
||||
for (i = 0; i < ctx->num_enabled_channels; i++) {
|
||||
ch = g_slist_nth_data(o->sdi->channels, ctx->channel_index[i]);
|
||||
g_string_append_printf(header, "# %d\t\t%s\n", i + 1, ch->name);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
|
||||
GString **out)
|
||||
{
|
||||
const struct sr_datafeed_meta *meta;
|
||||
const struct sr_datafeed_logic *logic;
|
||||
const struct sr_config *src;
|
||||
GSList *l;
|
||||
struct context *ctx;
|
||||
const uint8_t *sample;
|
||||
unsigned int curbit, p, idx, i;
|
||||
|
||||
*out = NULL;
|
||||
if (!o || !o->priv)
|
||||
return SR_ERR_BUG;
|
||||
ctx = o->priv;
|
||||
|
||||
if (packet->type == SR_DF_META) {
|
||||
meta = packet->payload;
|
||||
for (l = meta->config; l; l = l->next) {
|
||||
src = l->data;
|
||||
if (src->key != SR_CONF_SAMPLERATE)
|
||||
continue;
|
||||
ctx->samplerate = g_variant_get_uint64(src->data);
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->type != SR_DF_LOGIC)
|
||||
return SR_OK;
|
||||
logic = packet->payload;
|
||||
|
||||
if (!ctx->prevsample) {
|
||||
/* Can't allocate this until we know the stream's unitsize. */
|
||||
ctx->prevsample = g_malloc0(logic->unitsize);
|
||||
}
|
||||
|
||||
if (!ctx->header_done) {
|
||||
*out = gen_header(o);
|
||||
ctx->header_done = TRUE;
|
||||
} else {
|
||||
*out = g_string_sized_new(512);
|
||||
}
|
||||
|
||||
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
|
||||
sample = logic->data + i;
|
||||
ctx->samplecount++;
|
||||
|
||||
/*
|
||||
* Don't output the same sample multiple times, but make
|
||||
* sure to output at least the first and last sample.
|
||||
*/
|
||||
if (i > 0 && i < logic->length - logic->unitsize) {
|
||||
if (!memcmp(sample, ctx->prevsample, logic->unitsize))
|
||||
continue;
|
||||
}
|
||||
memcpy(ctx->prevsample, sample, logic->unitsize);
|
||||
|
||||
/* The first column is a counter (needed for gnuplot). */
|
||||
g_string_append_printf(*out, "%" PRIu64 "\t", ctx->samplecount);
|
||||
|
||||
/* The next columns are the values of all channels. */
|
||||
for (p = 0; p < ctx->num_enabled_channels; p++) {
|
||||
idx = ctx->channel_index[p];
|
||||
curbit = (sample[idx / 8] & ((uint8_t) (1 << (idx % 8)))) >> (idx % 8);
|
||||
g_string_append_printf(*out, "%d ", curbit);
|
||||
}
|
||||
g_string_append_printf(*out, "\n");
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int cleanup(struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
|
||||
if (!o || !o->priv)
|
||||
return SR_ERR_BUG;
|
||||
ctx = o->priv;
|
||||
g_free(ctx->channel_index);
|
||||
g_free(ctx->prevsample);
|
||||
g_free(ctx);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_module output_gnuplot = {
|
||||
.id = "gnuplot",
|
||||
.name = "Gnuplot",
|
||||
.desc = "Gnuplot data file format",
|
||||
.exts = (const char*[]){"dat", NULL},
|
||||
.options = NULL,
|
||||
.init = init,
|
||||
.receive = receive,
|
||||
.cleanup = cleanup,
|
||||
};
|
@ -1,251 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <glib.h>
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/analog: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
struct context {
|
||||
int num_enabled_probes;
|
||||
GPtrArray *probelist;
|
||||
};
|
||||
|
||||
static int init(struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *probe;
|
||||
GSList *l;
|
||||
|
||||
sr_spew("Initializing output module.");
|
||||
|
||||
if (!o || !o->sdi)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
|
||||
sr_err("Output module context malloc failed.");
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
o->internal = ctx;
|
||||
|
||||
/* Get the number of probes and their names. */
|
||||
ctx->probelist = g_ptr_array_new();
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
probe = l->data;
|
||||
if (!probe || !probe->enabled)
|
||||
continue;
|
||||
g_ptr_array_add(ctx->probelist, probe->name);
|
||||
ctx->num_enabled_probes++;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static void si_printf(float value, GString *out, char *unitstr)
|
||||
{
|
||||
float v;
|
||||
|
||||
if (signbit(value))
|
||||
v = -(value);
|
||||
else
|
||||
v = value;
|
||||
|
||||
if (v < 1e-12 || v > 1e+12)
|
||||
g_string_append_printf(out, "%f %s", value, unitstr);
|
||||
else if (v > 1e+9)
|
||||
g_string_append_printf(out, "%f G%s", value / 1e+9, unitstr);
|
||||
else if (v > 1e+6)
|
||||
g_string_append_printf(out, "%f M%s", value / 1e+6, unitstr);
|
||||
else if (v > 1e+3)
|
||||
g_string_append_printf(out, "%f k%s", value / 1e+3, unitstr);
|
||||
else if (v < 1e-9)
|
||||
g_string_append_printf(out, "%f n%s", value * 1e+9, unitstr);
|
||||
else if (v < 1e-6)
|
||||
g_string_append_printf(out, "%f u%s", value * 1e+6, unitstr);
|
||||
else if (v < 1e-3)
|
||||
g_string_append_printf(out, "%f m%s", value * 1e+3, unitstr);
|
||||
else
|
||||
g_string_append_printf(out, "%f %s", value, unitstr);
|
||||
|
||||
}
|
||||
|
||||
static void fancyprint(int unit, int mqflags, float value, GString *out)
|
||||
{
|
||||
switch (unit) {
|
||||
case SR_UNIT_VOLT:
|
||||
si_printf(value, out, "V");
|
||||
break;
|
||||
case SR_UNIT_AMPERE:
|
||||
si_printf(value, out, "A");
|
||||
break;
|
||||
case SR_UNIT_OHM:
|
||||
si_printf(value, out, "");
|
||||
g_string_append_unichar(out, 0x2126);
|
||||
break;
|
||||
case SR_UNIT_FARAD:
|
||||
si_printf(value, out, "F");
|
||||
break;
|
||||
case SR_UNIT_KELVIN:
|
||||
si_printf(value, out, "K");
|
||||
break;
|
||||
case SR_UNIT_CELSIUS:
|
||||
si_printf(value, out, "");
|
||||
g_string_append_unichar(out, 0x00b0);
|
||||
g_string_append_c(out, 'C');
|
||||
break;
|
||||
case SR_UNIT_FAHRENHEIT:
|
||||
si_printf(value, out, "");
|
||||
g_string_append_unichar(out, 0x00b0);
|
||||
g_string_append_c(out, 'F');
|
||||
break;
|
||||
case SR_UNIT_HERTZ:
|
||||
si_printf(value, out, "Hz");
|
||||
break;
|
||||
case SR_UNIT_PERCENTAGE:
|
||||
g_string_append_printf(out, "%f%%", value);
|
||||
break;
|
||||
case SR_UNIT_BOOLEAN:
|
||||
if (value > 0)
|
||||
g_string_append_printf(out, "TRUE");
|
||||
else
|
||||
g_string_append_printf(out, "FALSE");
|
||||
break;
|
||||
case SR_UNIT_SECOND:
|
||||
si_printf(value, out, "s");
|
||||
break;
|
||||
case SR_UNIT_SIEMENS:
|
||||
si_printf(value, out, "S");
|
||||
break;
|
||||
case SR_UNIT_DECIBEL_MW:
|
||||
si_printf(value, out, "dBu");
|
||||
break;
|
||||
case SR_UNIT_DECIBEL_VOLT:
|
||||
si_printf(value, out, "dBV");
|
||||
break;
|
||||
case SR_UNIT_DECIBEL_SPL:
|
||||
if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
|
||||
si_printf(value, out, "dB(A)");
|
||||
else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_C)
|
||||
si_printf(value, out, "dB(C)");
|
||||
else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_Z)
|
||||
si_printf(value, out, "dB(Z)");
|
||||
else
|
||||
/* No frequency weighting, or non-standard "flat" */
|
||||
si_printf(value, out, "dB(SPL)");
|
||||
if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_S)
|
||||
g_string_append(out, " S");
|
||||
else if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
|
||||
g_string_append(out, " F");
|
||||
if (mqflags & SR_MQFLAG_SPL_LAT)
|
||||
g_string_append(out, " LAT");
|
||||
else if (mqflags & SR_MQFLAG_SPL_PCT_OVER_ALARM)
|
||||
/* Not a standard function for SLMs, so this is
|
||||
* a made-up notation. */
|
||||
g_string_append(out, " %oA");
|
||||
break;
|
||||
case SR_UNIT_CONCENTRATION:
|
||||
g_string_append_printf(out, "%f ppm", value * 1000000);
|
||||
break;
|
||||
default:
|
||||
si_printf(value, out, "");
|
||||
break;
|
||||
}
|
||||
if ((mqflags & (SR_MQFLAG_AC | SR_MQFLAG_DC)) == (SR_MQFLAG_AC | SR_MQFLAG_DC))
|
||||
g_string_append_printf(out, " AC+DC");
|
||||
else if (mqflags & SR_MQFLAG_AC)
|
||||
g_string_append_printf(out, " AC");
|
||||
else if (mqflags & SR_MQFLAG_DC)
|
||||
g_string_append_printf(out, " DC");
|
||||
g_string_append_c(out, '\n');
|
||||
}
|
||||
|
||||
static int receive(struct sr_output *o, const struct sr_dev_inst *sdi,
|
||||
const struct sr_datafeed_packet *packet, GString **out)
|
||||
{
|
||||
const struct sr_datafeed_analog *analog;
|
||||
struct sr_channel *probe;
|
||||
GSList *l;
|
||||
const float *fdata;
|
||||
int i, p;
|
||||
|
||||
(void)sdi;
|
||||
|
||||
*out = NULL;
|
||||
if (!o || !o->sdi)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
switch (packet->type) {
|
||||
case SR_DF_FRAME_BEGIN:
|
||||
*out = g_string_new("FRAME-BEGIN\n");
|
||||
break;
|
||||
case SR_DF_FRAME_END:
|
||||
*out = g_string_new("FRAME-END\n");
|
||||
break;
|
||||
case SR_DF_ANALOG:
|
||||
analog = packet->payload;
|
||||
fdata = (const float *)analog->data;
|
||||
*out = g_string_sized_new(512);
|
||||
for (i = 0; i < analog->num_samples; i++) {
|
||||
for (l = analog->probes, p = 0; l; l = l->next, p++) {
|
||||
probe = l->data;
|
||||
g_string_append_printf(*out, "%s: ", probe->name);
|
||||
fancyprint(analog->unit, analog->mqflags,
|
||||
fdata[i + p], *out);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int cleanup(struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
|
||||
if (!o || !o->sdi)
|
||||
return SR_ERR_ARG;
|
||||
ctx = o->internal;
|
||||
|
||||
g_ptr_array_free(ctx->probelist, 1);
|
||||
g_free(ctx);
|
||||
o->internal = NULL;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_format output_analog = {
|
||||
.id = "analog",
|
||||
.description = "Analog data",
|
||||
.df_type = SR_DF_ANALOG,
|
||||
.init = init,
|
||||
.receive = receive,
|
||||
.cleanup = cleanup
|
||||
};
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/binary: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
static int data(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
|
||||
{
|
||||
uint8_t *outbuf;
|
||||
|
||||
(void)o;
|
||||
|
||||
if (!data_in) {
|
||||
sr_err("%s: data_in was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!length_out) {
|
||||
sr_err("%s: length_out was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (length_in == 0) {
|
||||
sr_err("%s: length_in was 0", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!(outbuf = g_try_malloc0(length_in))) {
|
||||
sr_err("%s: outbuf malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
memcpy(outbuf, data_in, length_in);
|
||||
*data_out = outbuf;
|
||||
*length_out = length_in;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_format output_binary = {
|
||||
.id = "binary",
|
||||
.description = "Raw binary",
|
||||
.df_type = SR_DF_LOGIC,
|
||||
.init = NULL,
|
||||
.data = data,
|
||||
.event = NULL,
|
||||
};
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "config.h" /* Needed for PACKAGE_STRING and others. */
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/csv: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
struct context {
|
||||
unsigned int num_enabled_probes;
|
||||
unsigned int unitsize;
|
||||
uint64_t samplerate;
|
||||
GString *header;
|
||||
char separator;
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Option to specify delimiter character and/or string.
|
||||
* - Option to (not) print metadata as comments.
|
||||
* - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
|
||||
* - Option to (not) print samplenumber / time as extra column.
|
||||
* - Option to "compress" output (only print changed samples, VCD-like).
|
||||
* - Option to print comma-separated bits, or whole bytes/words (for 8/16
|
||||
* probe LAs) as ASCII/hex etc. etc.
|
||||
* - Trigger support.
|
||||
*/
|
||||
|
||||
static int init(struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *probe;
|
||||
GSList *l;
|
||||
GVariant *gvar;
|
||||
int num_probes;
|
||||
time_t t;
|
||||
|
||||
if (!o) {
|
||||
sr_err("%s: o was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!o->sdi) {
|
||||
sr_err("%s: o->sdi was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
|
||||
sr_err("%s: ctx malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
o->internal = ctx;
|
||||
|
||||
/* Get the number of probes, and the unitsize. */
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
probe = l->data;
|
||||
if (probe->enabled)
|
||||
ctx->num_enabled_probes++;
|
||||
}
|
||||
|
||||
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
|
||||
|
||||
num_probes = g_slist_length(o->sdi->channels);
|
||||
|
||||
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
|
||||
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
|
||||
ctx->samplerate = g_variant_get_uint64(gvar);
|
||||
g_variant_unref(gvar);
|
||||
} else
|
||||
ctx->samplerate = 0;
|
||||
|
||||
ctx->separator = ',';
|
||||
ctx->header = g_string_sized_new(512);
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
/* Some metadata */
|
||||
g_string_append_printf(ctx->header, "; CSV, generated by %s on %s",
|
||||
PACKAGE_STRING, ctime(&t));
|
||||
g_string_append_printf(ctx->header, "; Samplerate: %"PRIu64"\n",
|
||||
ctx->samplerate);
|
||||
|
||||
/* Columns / channels */
|
||||
g_string_append_printf(ctx->header, "; Channels (%d/%d): ",
|
||||
ctx->num_enabled_probes, num_probes);
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
probe = l->data;
|
||||
if (probe->enabled)
|
||||
g_string_append_printf(ctx->header, "%s, ", probe->name);
|
||||
}
|
||||
g_string_append_printf(ctx->header, "\n");
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int event(struct sr_output *o, int event_type, uint8_t **data_out,
|
||||
uint64_t *length_out)
|
||||
{
|
||||
struct context *ctx;
|
||||
|
||||
if (!o) {
|
||||
sr_err("%s: o was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!(ctx = o->internal)) {
|
||||
sr_err("%s: o->internal was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!data_out) {
|
||||
sr_err("%s: data_out was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
switch (event_type) {
|
||||
case SR_DF_TRIGGER:
|
||||
sr_dbg("%s: SR_DF_TRIGGER event", __func__);
|
||||
/* TODO */
|
||||
*data_out = NULL;
|
||||
*length_out = 0;
|
||||
break;
|
||||
case SR_DF_END:
|
||||
sr_dbg("%s: SR_DF_END event", __func__);
|
||||
/* TODO */
|
||||
*data_out = NULL;
|
||||
*length_out = 0;
|
||||
g_free(o->internal);
|
||||
o->internal = NULL;
|
||||
break;
|
||||
default:
|
||||
sr_err("%s: unsupported event type: %d", __func__, event_type);
|
||||
*data_out = NULL;
|
||||
*length_out = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int data(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out, uint64_t *length_out)
|
||||
{
|
||||
struct context *ctx;
|
||||
GString *outstr;
|
||||
uint64_t sample, i;
|
||||
int j;
|
||||
|
||||
if (!o) {
|
||||
sr_err("%s: o was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!(ctx = o->internal)) {
|
||||
sr_err("%s: o->internal was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (!data_in) {
|
||||
sr_err("%s: data_in was NULL", __func__);
|
||||
return SR_ERR_ARG;
|
||||
}
|
||||
|
||||
if (ctx->header) {
|
||||
/* First data packet. */
|
||||
outstr = ctx->header;
|
||||
ctx->header = NULL;
|
||||
} else {
|
||||
outstr = g_string_sized_new(512);
|
||||
}
|
||||
|
||||
for (i = 0; i <= length_in - ctx->unitsize; i += ctx->unitsize) {
|
||||
memcpy(&sample, data_in + i, ctx->unitsize);
|
||||
for (j = ctx->num_enabled_probes - 1; j >= 0; j--) {
|
||||
g_string_append_printf(outstr, "%d%c",
|
||||
(int)((sample & (1 << j)) >> j),
|
||||
ctx->separator);
|
||||
}
|
||||
g_string_append_printf(outstr, "\n");
|
||||
}
|
||||
|
||||
*data_out = (uint8_t *)outstr->str;
|
||||
*length_out = outstr->len;
|
||||
g_string_free(outstr, FALSE);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_format output_csv = {
|
||||
.id = "csv",
|
||||
.description = "Comma-separated values (CSV)",
|
||||
.df_type = SR_DF_LOGIC,
|
||||
.init = init,
|
||||
.data = data,
|
||||
.event = event,
|
||||
};
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "config.h" /* Needed for PACKAGE and others. */
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/vcd: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
struct context {
|
||||
int num_enabled_probes;
|
||||
GArray *probeindices;
|
||||
GString *header;
|
||||
uint8_t *prevsample;
|
||||
int period;
|
||||
uint64_t samplerate;
|
||||
unsigned int unitsize;
|
||||
};
|
||||
|
||||
static const char *vcd_header_comment = "\
|
||||
$comment\n Acquisition with %d/%d probes at %s\n$end\n";
|
||||
|
||||
static int init(struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *probe;
|
||||
GSList *l;
|
||||
GVariant *gvar;
|
||||
int num_probes, i;
|
||||
char *samplerate_s, *frequency_s, *timestamp;
|
||||
time_t t;
|
||||
|
||||
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
|
||||
sr_err("%s: ctx malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
o->internal = ctx;
|
||||
ctx->num_enabled_probes = 0;
|
||||
ctx->probeindices = g_array_new(FALSE, FALSE, sizeof(int));
|
||||
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
probe = l->data;
|
||||
if (!probe->enabled)
|
||||
continue;
|
||||
ctx->probeindices = g_array_append_val(
|
||||
ctx->probeindices, probe->index);
|
||||
ctx->num_enabled_probes++;
|
||||
}
|
||||
if (ctx->num_enabled_probes > 94) {
|
||||
sr_err("VCD only supports 94 probes.");
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
|
||||
ctx->header = g_string_sized_new(512);
|
||||
num_probes = g_slist_length(o->sdi->channels);
|
||||
|
||||
/* timestamp */
|
||||
t = time(NULL);
|
||||
timestamp = g_strdup(ctime(&t));
|
||||
timestamp[strlen(timestamp)-1] = 0;
|
||||
g_string_printf(ctx->header, "$date %s $end\n", timestamp);
|
||||
g_free(timestamp);
|
||||
|
||||
/* generator */
|
||||
g_string_append_printf(ctx->header, "$version %s %s $end\n",
|
||||
PACKAGE, PACKAGE_VERSION);
|
||||
|
||||
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
|
||||
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
|
||||
ctx->samplerate = g_variant_get_uint64(gvar);
|
||||
g_variant_unref(gvar);
|
||||
if (!((samplerate_s = sr_samplerate_string(ctx->samplerate)))) {
|
||||
g_string_free(ctx->header, TRUE);
|
||||
g_free(ctx);
|
||||
return SR_ERR;
|
||||
}
|
||||
g_string_append_printf(ctx->header, vcd_header_comment,
|
||||
ctx->num_enabled_probes, num_probes, samplerate_s);
|
||||
g_free(samplerate_s);
|
||||
}
|
||||
|
||||
/* timescale */
|
||||
/* VCD can only handle 1/10/100 (s - fs), so scale up first */
|
||||
if (ctx->samplerate > SR_MHZ(1))
|
||||
ctx->period = SR_GHZ(1);
|
||||
else if (ctx->samplerate > SR_KHZ(1))
|
||||
ctx->period = SR_MHZ(1);
|
||||
else
|
||||
ctx->period = SR_KHZ(1);
|
||||
if (!(frequency_s = sr_period_string(ctx->period))) {
|
||||
g_string_free(ctx->header, TRUE);
|
||||
g_free(ctx);
|
||||
return SR_ERR;
|
||||
}
|
||||
g_string_append_printf(ctx->header, "$timescale %s $end\n", frequency_s);
|
||||
g_free(frequency_s);
|
||||
|
||||
/* scope */
|
||||
g_string_append_printf(ctx->header, "$scope module %s $end\n", PACKAGE);
|
||||
|
||||
/* Wires / channels */
|
||||
for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
|
||||
probe = l->data;
|
||||
if (!probe->enabled)
|
||||
continue;
|
||||
g_string_append_printf(ctx->header, "$var wire 1 %c %s $end\n",
|
||||
(char)('!' + i), probe->name);
|
||||
}
|
||||
|
||||
g_string_append(ctx->header, "$upscope $end\n"
|
||||
"$enddefinitions $end\n$dumpvars\n");
|
||||
|
||||
if (!(ctx->prevsample = g_try_malloc0(ctx->unitsize))) {
|
||||
g_string_free(ctx->header, TRUE);
|
||||
g_free(ctx);
|
||||
sr_err("%s: ctx->prevsample malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int receive(struct sr_output *o, const struct sr_dev_inst *sdi,
|
||||
const struct sr_datafeed_packet *packet, GString **out)
|
||||
{
|
||||
const struct sr_datafeed_logic *logic;
|
||||
struct context *ctx;
|
||||
unsigned int i;
|
||||
int p, curbit, prevbit, index;
|
||||
uint8_t *sample;
|
||||
static uint64_t samplecount = 0;
|
||||
|
||||
(void)sdi;
|
||||
|
||||
*out = NULL;
|
||||
if (!o || !o->internal)
|
||||
return SR_ERR_ARG;
|
||||
ctx = o->internal;
|
||||
|
||||
if (packet->type == SR_DF_END) {
|
||||
*out = g_string_new("$dumpoff\n$end\n");
|
||||
return SR_OK;
|
||||
} else if (packet->type != SR_DF_LOGIC)
|
||||
return SR_OK;
|
||||
|
||||
if (ctx->header) {
|
||||
/* The header is still here, this must be the first packet. */
|
||||
*out = ctx->header;
|
||||
ctx->header = NULL;
|
||||
} else {
|
||||
*out = g_string_sized_new(512);
|
||||
}
|
||||
|
||||
logic = packet->payload;
|
||||
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
|
||||
samplecount++;
|
||||
|
||||
sample = logic->data + i;
|
||||
|
||||
for (p = 0; p < ctx->num_enabled_probes; p++) {
|
||||
index = g_array_index(ctx->probeindices, int, p);
|
||||
curbit = (sample[p / 8] & (((uint8_t) 1) << index)) >> index;
|
||||
prevbit = (ctx->prevsample[p / 8] & (((uint64_t) 1) << index)) >> index;
|
||||
|
||||
/* VCD only contains deltas/changes of signals. */
|
||||
if (prevbit == curbit)
|
||||
continue;
|
||||
|
||||
/* Output which signal changed to which value. */
|
||||
g_string_append_printf(*out, "#%" PRIu64 "\n%i%c\n",
|
||||
(uint64_t)(((float)samplecount / ctx->samplerate)
|
||||
* ctx->period), curbit, (char)('!' + p));
|
||||
}
|
||||
|
||||
memcpy(ctx->prevsample, sample, ctx->unitsize);
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int cleanup(struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
|
||||
if (!o || !o->internal)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
ctx = o->internal;
|
||||
g_free(ctx);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
struct sr_output_format output_vcd = {
|
||||
.id = "vcd",
|
||||
.description = "Value Change Dump (VCD)",
|
||||
.df_type = SR_DF_LOGIC,
|
||||
.init = init,
|
||||
.receive = receive,
|
||||
.cleanup = cleanup,
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -17,64 +17,327 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
/** @cond PRIVATE */
|
||||
#define LOG_PREFIX "output"
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Output file/data format handling.
|
||||
* Output module handling.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup grp_output Output formats
|
||||
* @defgroup grp_output Output modules
|
||||
*
|
||||
* Output file/data format handling.
|
||||
* Output module handling.
|
||||
*
|
||||
* libsigrok supports several output (file) formats, e.g. binary, VCD,
|
||||
* gnuplot, and so on. It provides an output API that frontends can use.
|
||||
* New output formats can be added/implemented in libsigrok without having
|
||||
* libsigrok supports several output modules for file formats such as binary,
|
||||
* VCD, gnuplot, and so on. It provides an output API that frontends can use.
|
||||
* New output modules can be added/implemented in libsigrok without having
|
||||
* to change the frontends at all.
|
||||
*
|
||||
* All output modules are fed data in a stream. Devices that can stream data
|
||||
* into libsigrok live, instead of storing and then transferring the whole
|
||||
* buffer, can thus generate output live.
|
||||
* into libsigrok, instead of storing and then transferring the whole buffer,
|
||||
* can thus generate output live.
|
||||
*
|
||||
* Output modules are responsible for allocating enough memory to store
|
||||
* their own output, and passing a pointer to that memory (and length) of
|
||||
* the allocated memory back to the caller. The caller is then expected to
|
||||
* free this memory when finished with it.
|
||||
* Output modules generate a newly allocated GString. The caller is then
|
||||
* expected to free this with g_string_free() when finished with it.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @cond PRIVATE */
|
||||
extern SR_PRIV struct sr_output_format output_text_bits;
|
||||
extern SR_PRIV struct sr_output_format output_text_hex;
|
||||
extern SR_PRIV struct sr_output_format output_text_ascii;
|
||||
extern SR_PRIV struct sr_output_format output_binary;
|
||||
extern SR_PRIV struct sr_output_format output_vcd;
|
||||
|
||||
extern SR_PRIV struct sr_output_format output_csv;
|
||||
extern SR_PRIV struct sr_output_format output_analog;
|
||||
/* extern SR_PRIV struct sr_output_format output_analog_gnuplot; */
|
||||
extern SR_PRIV struct sr_output_module output_bits;
|
||||
extern SR_PRIV struct sr_output_module output_hex;
|
||||
extern SR_PRIV struct sr_output_module output_ascii;
|
||||
extern SR_PRIV struct sr_output_module output_binary;
|
||||
extern SR_PRIV struct sr_output_module output_vcd;
|
||||
extern SR_PRIV struct sr_output_module output_ols;
|
||||
extern SR_PRIV struct sr_output_module output_gnuplot;
|
||||
extern SR_PRIV struct sr_output_module output_chronovu_la8;
|
||||
extern SR_PRIV struct sr_output_module output_csv;
|
||||
extern SR_PRIV struct sr_output_module output_analog;
|
||||
extern SR_PRIV struct sr_output_module output_srzip;
|
||||
extern SR_PRIV struct sr_output_module output_wav;
|
||||
/* @endcond */
|
||||
|
||||
static struct sr_output_format *output_module_list[] = {
|
||||
&output_text_bits,
|
||||
&output_text_hex,
|
||||
&output_text_ascii,
|
||||
&output_binary,
|
||||
&output_vcd,
|
||||
static const struct sr_output_module *output_module_list[] = {
|
||||
&output_csv,
|
||||
&output_vcd,
|
||||
&output_gnuplot,
|
||||
&output_srzip,
|
||||
/*&output_ascii,
|
||||
&output_binary,
|
||||
&output_bits,
|
||||
&output_hex,
|
||||
&output_ols,
|
||||
&output_chronovu_la8,
|
||||
&output_analog,
|
||||
/* &output_analog_gnuplot, */
|
||||
&output_wav,*/
|
||||
NULL,
|
||||
};
|
||||
|
||||
SR_API struct sr_output_format **sr_output_list(void)
|
||||
/**
|
||||
* Returns a NULL-terminated list of all available output modules.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const struct sr_output_module **sr_output_list(void)
|
||||
{
|
||||
return output_module_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified output module's ID.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const char *sr_output_id_get(const struct sr_output_module *omod)
|
||||
{
|
||||
if (!omod) {
|
||||
sr_err("Invalid output module NULL!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return omod->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified output module's name.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const char *sr_output_name_get(const struct sr_output_module *omod)
|
||||
{
|
||||
if (!omod) {
|
||||
sr_err("Invalid output module NULL!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return omod->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified output module's description.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const char *sr_output_description_get(const struct sr_output_module *omod)
|
||||
{
|
||||
if (!omod) {
|
||||
sr_err("Invalid output module NULL!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return omod->desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified output module's file extensions typical for the file
|
||||
* format, as a NULL terminated array, or returns a NULL pointer if there is
|
||||
* no preferred extension.
|
||||
* @note these are a suggestions only.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const char *const *sr_output_extensions_get(
|
||||
const struct sr_output_module *omod)
|
||||
{
|
||||
if (!omod) {
|
||||
sr_err("Invalid output module NULL!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return omod->exts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the output module with the specified ID, or NULL if no module
|
||||
* with that id is found.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const struct sr_output_module *sr_output_find(char *id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; output_module_list[i]; i++) {
|
||||
if (!strcmp(output_module_list[i]->id, id))
|
||||
return output_module_list[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a NULL-terminated array of struct sr_option, or NULL if the
|
||||
* module takes no options.
|
||||
*
|
||||
* Each call to this function must be followed by a call to
|
||||
* sr_output_options_free().
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const struct sr_option **sr_output_options_get(const struct sr_output_module *omod)
|
||||
{
|
||||
const struct sr_option *mod_opts, **opts;
|
||||
int size, i;
|
||||
|
||||
if (!omod || !omod->options)
|
||||
return NULL;
|
||||
|
||||
mod_opts = omod->options();
|
||||
|
||||
for (size = 0; mod_opts[size].id; size++)
|
||||
;
|
||||
opts = g_malloc((size + 1) * sizeof(struct sr_option *));
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
opts[i] = &mod_opts[i];
|
||||
opts[i] = NULL;
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
/**
|
||||
* After a call to sr_output_options_get(), this function cleans up all
|
||||
* resources returned by that call.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API void sr_output_options_free(const struct sr_option **options)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!options)
|
||||
return;
|
||||
|
||||
for (i = 0; options[i]; i++) {
|
||||
if (options[i]->def) {
|
||||
g_variant_unref(options[i]->def);
|
||||
((struct sr_option *)options[i])->def = NULL;
|
||||
}
|
||||
|
||||
if (options[i]->values) {
|
||||
g_slist_free_full(options[i]->values, (GDestroyNotify)g_variant_unref);
|
||||
((struct sr_option *)options[i])->values = NULL;
|
||||
}
|
||||
}
|
||||
g_free(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new output instance using the specified output module.
|
||||
*
|
||||
* <code>options</code> is a *HashTable with the keys corresponding with
|
||||
* the module options' <code>id</code> field. The values should be GVariant
|
||||
* pointers with sunk * references, of the same GVariantType as the option's
|
||||
* default value.
|
||||
*
|
||||
* The sr_dev_inst passed in can be used by the instance to determine
|
||||
* channel names, samplerate, and so on.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API const struct sr_output *sr_output_new(const struct sr_output_module *omod,
|
||||
GHashTable *options, const struct sr_dev_inst *sdi)
|
||||
{
|
||||
struct sr_output *op;
|
||||
const struct sr_option *mod_opts;
|
||||
const GVariantType *gvt;
|
||||
GHashTable *new_opts;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
int i;
|
||||
|
||||
op = g_malloc(sizeof(struct sr_output));
|
||||
op->module = omod;
|
||||
op->sdi = sdi;
|
||||
|
||||
new_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
||||
(GDestroyNotify)g_variant_unref);
|
||||
if (omod->options) {
|
||||
mod_opts = omod->options();
|
||||
for (i = 0; mod_opts[i].id; i++) {
|
||||
if (options && g_hash_table_lookup_extended(options,
|
||||
mod_opts[i].id, &key, &value)) {
|
||||
/* Pass option along. */
|
||||
gvt = g_variant_get_type(mod_opts[i].def);
|
||||
if (!g_variant_is_of_type(value, gvt)) {
|
||||
sr_err("Invalid type for '%s' option.", key);
|
||||
g_free(op);
|
||||
return NULL;
|
||||
}
|
||||
g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
|
||||
g_variant_ref(value));
|
||||
} else {
|
||||
/* Option not given: insert the default value. */
|
||||
g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
|
||||
g_variant_ref(mod_opts[i].def));
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure no invalid options were given. */
|
||||
if (options) {
|
||||
g_hash_table_iter_init(&iter, options);
|
||||
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||
if (!g_hash_table_lookup(new_opts, key)) {
|
||||
sr_err("Output module '%s' has no option '%s'", omod->id, key);
|
||||
g_hash_table_destroy(new_opts);
|
||||
g_free(op);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (op->module->init && op->module->init(op, new_opts) != SR_OK) {
|
||||
g_free(op);
|
||||
op = NULL;
|
||||
}
|
||||
if (new_opts)
|
||||
g_hash_table_destroy(new_opts);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to the specified output instance.
|
||||
*
|
||||
* The instance's output is returned as a newly allocated GString,
|
||||
* which must be freed by the caller.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API int sr_output_send(const struct sr_output *o,
|
||||
const struct sr_datafeed_packet *packet, GString **out)
|
||||
{
|
||||
return o->module->receive(o, packet, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the specified output instance and all associated resources.
|
||||
*
|
||||
* @since 0.4.0
|
||||
*/
|
||||
SR_API int sr_output_free(const struct sr_output *o)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!o)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
ret = SR_OK;
|
||||
if (o->module->cleanup)
|
||||
ret = o->module->cleanup((struct sr_output *)o);
|
||||
g_free((gpointer)o);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
321
libsigrok4DSL/output/srzip.c
Normal file
321
libsigrok4DSL/output/srzip.c
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <zip.h>
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "output/srzip"
|
||||
|
||||
struct out_context {
|
||||
gboolean zip_created;
|
||||
uint64_t samplerate;
|
||||
char *filename;
|
||||
};
|
||||
|
||||
static int init(struct sr_output *o, GHashTable *options)
|
||||
{
|
||||
struct out_context *outc;
|
||||
|
||||
outc = g_malloc0(sizeof(struct out_context));
|
||||
o->priv = outc;
|
||||
outc->filename = g_strdup(g_variant_get_string(g_hash_table_lookup(options, "filename"), NULL));
|
||||
if (strlen(outc->filename) == 0)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int zip_create(const struct sr_output *o)
|
||||
{
|
||||
struct out_context *outc;
|
||||
struct sr_channel *ch;
|
||||
FILE *meta;
|
||||
struct zip *zipfile;
|
||||
struct zip_source *versrc, *metasrc;
|
||||
GVariant *gvar;
|
||||
GSList *l;
|
||||
int tmpfile, ret;
|
||||
char version[1], metafile[32], *s;
|
||||
|
||||
outc = o->priv;
|
||||
if (outc->samplerate == 0) {
|
||||
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
|
||||
&gvar) == SR_OK) {
|
||||
outc->samplerate = g_variant_get_uint64(gvar);
|
||||
g_variant_unref(gvar);
|
||||
}
|
||||
}
|
||||
|
||||
/* Quietly delete it first, libzip wants replace ops otherwise. */
|
||||
unlink(outc->filename);
|
||||
if (!(zipfile = zip_open(outc->filename, ZIP_CREATE, &ret)))
|
||||
return SR_ERR;
|
||||
|
||||
/* "version" */
|
||||
version[0] = '2';
|
||||
if (!(versrc = zip_source_buffer(zipfile, version, 1, 0)))
|
||||
return SR_ERR;
|
||||
if (zip_add(zipfile, "version", versrc) == -1) {
|
||||
sr_info("Error saving version into zipfile: %s.",
|
||||
zip_strerror(zipfile));
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
/* init "metadata" */
|
||||
strcpy(metafile, "sigrok-meta-XXXXXX");
|
||||
if ((tmpfile = g_mkstemp(metafile)) == -1)
|
||||
return SR_ERR;
|
||||
close(tmpfile);
|
||||
meta = g_fopen(metafile, "wb");
|
||||
fprintf(meta, "[global]\n");
|
||||
fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION);
|
||||
fprintf(meta, "[device 1]\ncapturefile = logic-1\n");
|
||||
fprintf(meta, "total probes = %d\n", g_slist_length(o->sdi->channels));
|
||||
s = sr_samplerate_string(outc->samplerate);
|
||||
fprintf(meta, "samplerate = %s\n", s);
|
||||
g_free(s);
|
||||
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_LOGIC)
|
||||
continue;
|
||||
if (!ch->enabled)
|
||||
continue;
|
||||
fprintf(meta, "probe%d = %s\n", ch->index + 1, ch->name);
|
||||
}
|
||||
fclose(meta);
|
||||
|
||||
if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) {
|
||||
unlink(metafile);
|
||||
return SR_ERR;
|
||||
}
|
||||
if (zip_add(zipfile, "metadata", metasrc) == -1) {
|
||||
unlink(metafile);
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if ((ret = zip_close(zipfile)) == -1) {
|
||||
sr_info("Error saving zipfile: %s.", zip_strerror(zipfile));
|
||||
unlink(metafile);
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
unlink(metafile);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int zip_append(const struct sr_output *o, unsigned char *buf,
|
||||
int unitsize, int length)
|
||||
{
|
||||
struct out_context *outc;
|
||||
struct zip *archive;
|
||||
struct zip_source *logicsrc;
|
||||
zip_int64_t num_files;
|
||||
struct zip_file *zf;
|
||||
struct zip_stat zs;
|
||||
struct zip_source *metasrc;
|
||||
GKeyFile *kf;
|
||||
GError *error;
|
||||
gsize len;
|
||||
int chunk_num, next_chunk_num, tmpfile, ret, i;
|
||||
const char *entry_name;
|
||||
char *metafile, tmpname[32], chunkname[16];
|
||||
|
||||
outc = o->priv;
|
||||
if (!(archive = zip_open(outc->filename, 0, &ret)))
|
||||
return SR_ERR;
|
||||
|
||||
if (zip_stat(archive, "metadata", 0, &zs) == -1)
|
||||
return SR_ERR;
|
||||
|
||||
metafile = g_malloc(zs.size);
|
||||
zf = zip_fopen_index(archive, zs.index, 0);
|
||||
zip_fread(zf, metafile, zs.size);
|
||||
zip_fclose(zf);
|
||||
|
||||
/*
|
||||
* If the file was only initialized but doesn't yet have any
|
||||
* data it in, it won't have a unitsize field in metadata yet.
|
||||
*/
|
||||
error = NULL;
|
||||
kf = g_key_file_new();
|
||||
if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) {
|
||||
sr_err("Failed to parse metadata: %s.", error->message);
|
||||
return SR_ERR;
|
||||
}
|
||||
g_free(metafile);
|
||||
tmpname[0] = '\0';
|
||||
if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) {
|
||||
if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
|
||||
sr_err("Failed to check unitsize key: %s", error ? error->message : "?");
|
||||
return SR_ERR;
|
||||
}
|
||||
/* Add unitsize field. */
|
||||
g_key_file_set_integer(kf, "device 1", "unitsize", unitsize);
|
||||
metafile = g_key_file_to_data(kf, &len, &error);
|
||||
strcpy(tmpname, "sigrok-meta-XXXXXX");
|
||||
if ((tmpfile = g_mkstemp(tmpname)) == -1)
|
||||
return SR_ERR;
|
||||
if (write(tmpfile, metafile, len) < 0) {
|
||||
sr_dbg("Failed to create new metadata: %s", strerror(errno));
|
||||
g_free(metafile);
|
||||
unlink(tmpname);
|
||||
return SR_ERR;
|
||||
}
|
||||
close(tmpfile);
|
||||
if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) {
|
||||
sr_err("Failed to create zip source for metadata.");
|
||||
g_free(metafile);
|
||||
unlink(tmpname);
|
||||
return SR_ERR;
|
||||
}
|
||||
if (zip_replace(archive, zs.index, metasrc) == -1) {
|
||||
sr_err("Failed to replace metadata file.");
|
||||
g_free(metafile);
|
||||
unlink(tmpname);
|
||||
return SR_ERR;
|
||||
}
|
||||
g_free(metafile);
|
||||
}
|
||||
g_key_file_free(kf);
|
||||
|
||||
next_chunk_num = 1;
|
||||
num_files = zip_get_num_entries(archive, 0);
|
||||
for (i = 0; i < num_files; i++) {
|
||||
entry_name = zip_get_name(archive, i, 0);
|
||||
if (strncmp(entry_name, "logic-1", 7))
|
||||
continue;
|
||||
if (strlen(entry_name) == 7) {
|
||||
/* This file has no extra chunks, just a single "logic-1".
|
||||
* Rename it to "logic-1-1" * and continue with chunk 2. */
|
||||
if (zip_rename(archive, i, "logic-1-1") == -1) {
|
||||
sr_err("Failed to rename 'logic-1' to 'logic-1-1'.");
|
||||
unlink(tmpname);
|
||||
return SR_ERR;
|
||||
}
|
||||
next_chunk_num = 2;
|
||||
break;
|
||||
} else if (strlen(entry_name) > 8 && entry_name[7] == '-') {
|
||||
chunk_num = strtoull(entry_name + 8, NULL, 10);
|
||||
if (chunk_num >= next_chunk_num)
|
||||
next_chunk_num = chunk_num + 1;
|
||||
}
|
||||
}
|
||||
snprintf(chunkname, 15, "logic-1-%d", next_chunk_num);
|
||||
if (!(logicsrc = zip_source_buffer(archive, buf, length, FALSE))) {
|
||||
unlink(tmpname);
|
||||
return SR_ERR;
|
||||
}
|
||||
if (zip_add(archive, chunkname, logicsrc) == -1) {
|
||||
unlink(tmpname);
|
||||
return SR_ERR;
|
||||
}
|
||||
if ((ret = zip_close(archive)) == -1) {
|
||||
sr_info("error saving session file: %s", zip_strerror(archive));
|
||||
unlink(tmpname);
|
||||
return SR_ERR;
|
||||
}
|
||||
unlink(tmpname);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
|
||||
GString **out)
|
||||
{
|
||||
struct out_context *outc;
|
||||
const struct sr_datafeed_meta *meta;
|
||||
const struct sr_datafeed_logic *logic;
|
||||
const struct sr_config *src;
|
||||
GSList *l;
|
||||
|
||||
int ret;
|
||||
|
||||
*out = NULL;
|
||||
if (!o || !o->sdi || !(outc = o->priv))
|
||||
return SR_ERR_ARG;
|
||||
|
||||
switch (packet->type) {
|
||||
case SR_DF_META:
|
||||
meta = packet->payload;
|
||||
for (l = meta->config; l; l = l->next) {
|
||||
src = l->data;
|
||||
if (src->key != SR_CONF_SAMPLERATE)
|
||||
continue;
|
||||
outc->samplerate = g_variant_get_uint64(src->data);
|
||||
}
|
||||
break;
|
||||
case SR_DF_LOGIC:
|
||||
if (!outc->zip_created) {
|
||||
if ((ret = zip_create(o)) != SR_OK)
|
||||
return ret;
|
||||
outc->zip_created = TRUE;
|
||||
}
|
||||
logic = packet->payload;
|
||||
ret = zip_append(o, logic->data, logic->unitsize, logic->length);
|
||||
break;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int cleanup(struct sr_output *o)
|
||||
{
|
||||
struct out_context *outc;
|
||||
|
||||
outc = o->priv;
|
||||
g_free(outc->filename);
|
||||
g_free(outc);
|
||||
o->priv = NULL;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static struct sr_option options[] = {
|
||||
{ "filename", "Filename", "File to write", NULL, NULL },
|
||||
{0}
|
||||
};
|
||||
|
||||
static const struct sr_option *get_options(void)
|
||||
{
|
||||
if (!options[0].def)
|
||||
options[0].def = g_variant_ref_sink(g_variant_new_string(""));
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_module output_srzip = {
|
||||
.id = "srzip",
|
||||
.name = "srzip",
|
||||
.desc = "srzip session file",
|
||||
.exts = (const char*[]){"sr", NULL},
|
||||
.options = get_options,
|
||||
.init = init,
|
||||
.receive = receive,
|
||||
.cleanup = cleanup,
|
||||
};
|
||||
|
@ -1,33 +0,0 @@
|
||||
##
|
||||
## This file is part of the libsigrok project.
|
||||
##
|
||||
## Copyright (C) 2011 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software
|
||||
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
##
|
||||
|
||||
# Local lib, this is NOT meant to be installed!
|
||||
noinst_LTLIBRARIES = libsigrok4DSLoutputtext.la
|
||||
|
||||
libsigrok4DSLoutputtext_la_SOURCES = \
|
||||
text.c \
|
||||
text.h \
|
||||
bits.c \
|
||||
hex.c \
|
||||
ascii.c
|
||||
|
||||
libsigrok4DSLoutputtext_la_CFLAGS = \
|
||||
-I$(top_srcdir)
|
||||
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
#include "text.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/ascii: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
SR_PRIV int init_ascii(struct sr_output *o)
|
||||
{
|
||||
return init(o, DEFAULT_BPL_ASCII, MODE_ASCII);
|
||||
}
|
||||
|
||||
SR_PRIV int data_ascii(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out,
|
||||
uint64_t *length_out)
|
||||
{
|
||||
struct context *ctx;
|
||||
unsigned int outsize, offset, p;
|
||||
int max_linelen;
|
||||
const uint8_t *sample;
|
||||
uint8_t *outbuf;
|
||||
|
||||
ctx = o->internal;
|
||||
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
|
||||
+ ctx->samples_per_line / 8;
|
||||
/*
|
||||
* Calculate space needed for probes. Set aside 512 bytes for
|
||||
* extra output, e.g. trigger.
|
||||
*/
|
||||
outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
|
||||
* (ctx->num_enabled_probes * max_linelen);
|
||||
|
||||
if (!(outbuf = g_try_malloc0(outsize + 1))) {
|
||||
sr_err("%s: outbuf malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
outbuf[0] = '\0';
|
||||
if (ctx->header) {
|
||||
/* The header is still here, this must be the first packet. */
|
||||
strncpy((char *)outbuf, ctx->header, outsize);
|
||||
g_free(ctx->header);
|
||||
ctx->header = NULL;
|
||||
}
|
||||
|
||||
if (length_in >= ctx->unitsize) {
|
||||
for (offset = 0; offset <= length_in - ctx->unitsize;
|
||||
offset += ctx->unitsize) {
|
||||
sample = data_in + offset;
|
||||
|
||||
char tmpval[ctx->num_enabled_probes];
|
||||
|
||||
for (p = 0; p < ctx->num_enabled_probes; p++) {
|
||||
uint8_t curbit = (sample[p / 8] & ((uint8_t) 1 << (p % 8)));
|
||||
uint8_t prevbit = (ctx->prevsample[p / 8] &
|
||||
((uint8_t) 1 << (p % 8)));
|
||||
|
||||
if (curbit < prevbit && ctx->line_offset > 0) {
|
||||
ctx->linebuf[p * ctx->linebuf_len +
|
||||
ctx->line_offset-1] = '\\';
|
||||
}
|
||||
|
||||
if (curbit > prevbit) {
|
||||
tmpval[p] = '/';
|
||||
} else {
|
||||
if (curbit)
|
||||
tmpval[p] = '"';
|
||||
else
|
||||
tmpval[p] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
/* End of line. */
|
||||
if (ctx->spl_cnt >= ctx->samples_per_line) {
|
||||
flush_linebufs(ctx, outbuf);
|
||||
ctx->line_offset = ctx->spl_cnt = 0;
|
||||
ctx->mark_trigger = -1;
|
||||
}
|
||||
|
||||
for (p = 0; p < ctx->num_enabled_probes; p++) {
|
||||
ctx->linebuf[p * ctx->linebuf_len +
|
||||
ctx->line_offset] = tmpval[p];
|
||||
}
|
||||
|
||||
ctx->line_offset++;
|
||||
ctx->spl_cnt++;
|
||||
|
||||
memcpy(ctx->prevsample, sample, ctx->unitsize);
|
||||
}
|
||||
} else {
|
||||
sr_info("Short buffer (length_in=%" PRIu64 ").", length_in);
|
||||
}
|
||||
|
||||
*data_out = outbuf;
|
||||
*length_out = strlen((const char *)outbuf);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_format output_text_ascii = {
|
||||
.id = "ascii",
|
||||
.description = "ASCII",
|
||||
.df_type = SR_DF_LOGIC,
|
||||
.init = init_ascii,
|
||||
.data = data_ascii,
|
||||
.event = event,
|
||||
};
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
#include "text.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/bits: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
SR_PRIV int init_bits(struct sr_output *o)
|
||||
{
|
||||
return init(o, DEFAULT_BPL_BITS, MODE_BITS);
|
||||
}
|
||||
|
||||
SR_PRIV int data_bits(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out,
|
||||
uint64_t *length_out)
|
||||
{
|
||||
struct context *ctx;
|
||||
unsigned int outsize, offset, p;
|
||||
int max_linelen;
|
||||
const uint8_t *sample;
|
||||
uint8_t *outbuf, c;
|
||||
|
||||
ctx = o->internal;
|
||||
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
|
||||
+ ctx->samples_per_line / 8;
|
||||
/*
|
||||
* Calculate space needed for probes. Set aside 512 bytes for
|
||||
* extra output, e.g. trigger.
|
||||
*/
|
||||
outsize = 512 + (1 + (length_in / ctx->unitsize) / ctx->samples_per_line)
|
||||
* (ctx->num_enabled_probes * max_linelen);
|
||||
|
||||
if (!(outbuf = g_try_malloc0(outsize + 1))) {
|
||||
sr_err("%s: outbuf malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
outbuf[0] = '\0';
|
||||
if (ctx->header) {
|
||||
/* The header is still here, this must be the first packet. */
|
||||
strncpy((char *)outbuf, ctx->header, outsize);
|
||||
g_free(ctx->header);
|
||||
ctx->header = NULL;
|
||||
}
|
||||
|
||||
if (length_in >= ctx->unitsize) {
|
||||
for (offset = 0; offset <= length_in - ctx->unitsize;
|
||||
offset += ctx->unitsize) {
|
||||
sample = data_in + offset;
|
||||
for (p = 0; p < ctx->num_enabled_probes; p++) {
|
||||
c = (sample[p / 8] & ((uint8_t) 1 << (p % 8))) ? '1' : '0';
|
||||
ctx->linebuf[p * ctx->linebuf_len +
|
||||
ctx->line_offset] = c;
|
||||
}
|
||||
ctx->line_offset++;
|
||||
ctx->spl_cnt++;
|
||||
|
||||
/* Add a space every 8th bit. */
|
||||
if ((ctx->spl_cnt & 7) == 0) {
|
||||
for (p = 0; p < ctx->num_enabled_probes; p++)
|
||||
ctx->linebuf[p * ctx->linebuf_len +
|
||||
ctx->line_offset] = ' ';
|
||||
ctx->line_offset++;
|
||||
}
|
||||
|
||||
/* End of line. */
|
||||
if (ctx->spl_cnt >= ctx->samples_per_line) {
|
||||
flush_linebufs(ctx, outbuf);
|
||||
ctx->line_offset = ctx->spl_cnt = 0;
|
||||
ctx->mark_trigger = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sr_info("Short buffer (length_in=%" PRIu64 ").", length_in);
|
||||
}
|
||||
|
||||
*data_out = outbuf;
|
||||
*length_out = strlen((const char *)outbuf);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_format output_text_bits = {
|
||||
.id = "bits",
|
||||
.description = "Bits",
|
||||
.df_type = SR_DF_LOGIC,
|
||||
.init = init_bits,
|
||||
.data = data_bits,
|
||||
.event = event,
|
||||
};
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
#include "text.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/hex: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
SR_PRIV int init_hex(struct sr_output *o)
|
||||
{
|
||||
return init(o, DEFAULT_BPL_HEX, MODE_HEX);
|
||||
}
|
||||
|
||||
SR_PRIV int data_hex(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out,
|
||||
uint64_t *length_out)
|
||||
{
|
||||
struct context *ctx;
|
||||
unsigned int outsize, offset, p;
|
||||
int max_linelen;
|
||||
const uint8_t *sample;
|
||||
uint8_t *outbuf;
|
||||
|
||||
ctx = o->internal;
|
||||
max_linelen = SR_MAX_PROBENAME_LEN + 3 + ctx->samples_per_line
|
||||
+ ctx->samples_per_line / 2;
|
||||
outsize = length_in / ctx->unitsize * ctx->num_enabled_probes
|
||||
/ ctx->samples_per_line * max_linelen + 512;
|
||||
|
||||
if (!(outbuf = g_try_malloc0(outsize + 1))) {
|
||||
sr_err("%s: outbuf malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
outbuf[0] = '\0';
|
||||
if (ctx->header) {
|
||||
/* The header is still here, this must be the first packet. */
|
||||
strncpy((char *)outbuf, ctx->header, outsize);
|
||||
g_free(ctx->header);
|
||||
ctx->header = NULL;
|
||||
}
|
||||
|
||||
ctx->line_offset = 0;
|
||||
for (offset = 0; offset <= length_in - ctx->unitsize;
|
||||
offset += ctx->unitsize) {
|
||||
sample = data_in + offset;
|
||||
for (p = 0; p < ctx->num_enabled_probes; p++) {
|
||||
ctx->linevalues[p] <<= 1;
|
||||
if (sample[p / 8] & ((uint8_t) 1 << (p % 8)))
|
||||
ctx->linevalues[p] |= 1;
|
||||
sprintf((char *)ctx->linebuf + (p * ctx->linebuf_len) +
|
||||
ctx->line_offset, "%.2x", ctx->linevalues[p]);
|
||||
}
|
||||
ctx->spl_cnt++;
|
||||
|
||||
/* Add a space after every complete hex byte. */
|
||||
if ((ctx->spl_cnt & 7) == 0) {
|
||||
for (p = 0; p < ctx->num_enabled_probes; p++)
|
||||
ctx->linebuf[p * ctx->linebuf_len +
|
||||
ctx->line_offset + 2] = ' ';
|
||||
ctx->line_offset += 3;
|
||||
}
|
||||
|
||||
/* End of line. */
|
||||
if (ctx->spl_cnt >= ctx->samples_per_line) {
|
||||
flush_linebufs(ctx, outbuf);
|
||||
ctx->line_offset = ctx->spl_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*data_out = outbuf;
|
||||
*length_out = strlen((const char *)outbuf);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
SR_PRIV struct sr_output_format output_text_hex = {
|
||||
.id = "hex",
|
||||
.description = "Hexadecimal",
|
||||
.df_type = SR_DF_LOGIC,
|
||||
.init = init_hex,
|
||||
.data = data_hex,
|
||||
.event = event,
|
||||
};
|
@ -1,208 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
|
||||
* Copyright (C) 2011 Håvard Espeland <gus@ping.uio.no>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "config.h" /* Needed for PACKAGE_STRING and others. */
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
#include "text.h"
|
||||
|
||||
/* Message logging helpers with subsystem-specific prefix string. */
|
||||
#define LOG_PREFIX "output/text: "
|
||||
#define sr_log(l, s, args...) sr_log(l, LOG_PREFIX s, ## args)
|
||||
#define sr_spew(s, args...) sr_spew(LOG_PREFIX s, ## args)
|
||||
#define sr_dbg(s, args...) sr_dbg(LOG_PREFIX s, ## args)
|
||||
#define sr_info(s, args...) sr_info(LOG_PREFIX s, ## args)
|
||||
#define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args)
|
||||
#define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args)
|
||||
|
||||
SR_PRIV void flush_linebufs(struct context *ctx, uint8_t *outbuf)
|
||||
{
|
||||
static int max_probename_len = 0;
|
||||
int len, i;
|
||||
GSList *l;
|
||||
char *probe_name;
|
||||
|
||||
if (ctx->linebuf[0] == 0)
|
||||
return;
|
||||
|
||||
if (max_probename_len == 0) {
|
||||
/* First time through... */
|
||||
for (l = ctx->probenames; l; l = l->next) {
|
||||
probe_name = l->data;
|
||||
len = strlen(probe_name);
|
||||
if (len > max_probename_len)
|
||||
max_probename_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, l = ctx->probenames; l; l = l->next, i++) {
|
||||
probe_name = l->data;
|
||||
sprintf((char *)outbuf + strlen((const char *)outbuf),
|
||||
"%*s:%s\n", max_probename_len,
|
||||
probe_name, ctx->linebuf + i * ctx->linebuf_len);
|
||||
}
|
||||
|
||||
/* Mark trigger with a ^ character. */
|
||||
if (ctx->mark_trigger != -1)
|
||||
{
|
||||
int space_offset = ctx->mark_trigger / 8;
|
||||
|
||||
if (ctx->mode == MODE_ASCII)
|
||||
space_offset = 0;
|
||||
|
||||
sprintf((char *)outbuf + strlen((const char *)outbuf),
|
||||
"T:%*s^\n", ctx->mark_trigger + space_offset, "");
|
||||
}
|
||||
|
||||
memset(ctx->linebuf, 0, i * ctx->linebuf_len);
|
||||
}
|
||||
|
||||
SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *probe;
|
||||
GSList *l;
|
||||
GVariant *gvar;
|
||||
uint64_t samplerate;
|
||||
int num_probes, ret;
|
||||
char *samplerate_s;
|
||||
|
||||
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
|
||||
sr_err("%s: ctx malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
o->internal = ctx;
|
||||
ctx->num_enabled_probes = 0;
|
||||
ctx->probenames = NULL;
|
||||
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
probe = l->data;
|
||||
if (!probe->enabled)
|
||||
continue;
|
||||
ctx->probenames = g_slist_append(ctx->probenames, probe->name);
|
||||
ctx->num_enabled_probes++;
|
||||
}
|
||||
|
||||
ctx->unitsize = (ctx->num_enabled_probes + 7) / 8;
|
||||
ctx->line_offset = 0;
|
||||
ctx->spl_cnt = 0;
|
||||
ctx->mark_trigger = -1;
|
||||
ctx->mode = mode;
|
||||
|
||||
ret = SR_OK;
|
||||
if (o->param && o->param[0]) {
|
||||
ctx->samples_per_line = strtoul(o->param, NULL, 10);
|
||||
if (ctx->samples_per_line < 1) {
|
||||
ret = SR_ERR;
|
||||
goto err;
|
||||
}
|
||||
} else
|
||||
ctx->samples_per_line = default_spl;
|
||||
|
||||
if (!(ctx->header = g_try_malloc0(512))) {
|
||||
sr_err("%s: ctx->header malloc failed", __func__);
|
||||
ret = SR_ERR_MALLOC;
|
||||
goto err;
|
||||
}
|
||||
|
||||
snprintf(ctx->header, 511, "%s\n", PACKAGE_STRING);
|
||||
num_probes = g_slist_length(o->sdi->channels);
|
||||
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL,
|
||||
SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
|
||||
samplerate = g_variant_get_uint64(gvar);
|
||||
g_variant_unref(gvar);
|
||||
if (!(samplerate_s = sr_samplerate_string(samplerate))) {
|
||||
ret = SR_ERR;
|
||||
goto err;
|
||||
}
|
||||
snprintf(ctx->header + strlen(ctx->header),
|
||||
511 - strlen(ctx->header),
|
||||
"Acquisition with %d/%d probes at %s\n",
|
||||
ctx->num_enabled_probes, num_probes, samplerate_s);
|
||||
g_free(samplerate_s);
|
||||
}
|
||||
|
||||
ctx->linebuf_len = ctx->samples_per_line * 2 + 4;
|
||||
if (!(ctx->linebuf = g_try_malloc0(num_probes * ctx->linebuf_len))) {
|
||||
sr_err("%s: ctx->linebuf malloc failed", __func__);
|
||||
ret = SR_ERR_MALLOC;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(ctx->linevalues = g_try_malloc0(num_probes))) {
|
||||
sr_err("%s: ctx->linevalues malloc failed", __func__);
|
||||
ret = SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
if (mode == MODE_ASCII &&
|
||||
!(ctx->prevsample = g_try_malloc0(num_probes / 8))) {
|
||||
sr_err("%s: ctx->prevsample malloc failed", __func__);
|
||||
ret = SR_ERR_MALLOC;
|
||||
}
|
||||
|
||||
err:
|
||||
if (ret != SR_OK) {
|
||||
g_free(ctx->header);
|
||||
g_free(ctx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SR_PRIV int event(struct sr_output *o, int event_type, uint8_t **data_out,
|
||||
uint64_t *length_out)
|
||||
{
|
||||
struct context *ctx;
|
||||
int outsize;
|
||||
uint8_t *outbuf;
|
||||
|
||||
ctx = o->internal;
|
||||
switch (event_type) {
|
||||
case SR_DF_TRIGGER:
|
||||
ctx->mark_trigger = ctx->spl_cnt;
|
||||
*data_out = NULL;
|
||||
*length_out = 0;
|
||||
break;
|
||||
case SR_DF_END:
|
||||
outsize = ctx->num_enabled_probes
|
||||
* (ctx->samples_per_line + 20) + 512;
|
||||
if (!(outbuf = g_try_malloc0(outsize))) {
|
||||
sr_err("%s: outbuf malloc failed", __func__);
|
||||
return SR_ERR_MALLOC;
|
||||
}
|
||||
flush_linebufs(ctx, outbuf);
|
||||
*data_out = outbuf;
|
||||
*length_out = strlen((const char *)outbuf);
|
||||
g_free(o->internal);
|
||||
o->internal = NULL;
|
||||
break;
|
||||
default:
|
||||
*data_out = NULL;
|
||||
*length_out = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBSIGROK_OUTPUT_TEXT_TEXT_H
|
||||
#define LIBSIGROK_OUTPUT_TEXT_TEXT_H
|
||||
|
||||
#define DEFAULT_BPL_BITS 64
|
||||
#define DEFAULT_BPL_HEX 192
|
||||
#define DEFAULT_BPL_ASCII 74
|
||||
|
||||
enum outputmode {
|
||||
MODE_BITS = 1,
|
||||
MODE_HEX,
|
||||
MODE_ASCII,
|
||||
};
|
||||
|
||||
struct context {
|
||||
unsigned int num_enabled_probes;
|
||||
int samples_per_line;
|
||||
unsigned int unitsize;
|
||||
int line_offset;
|
||||
int linebuf_len;
|
||||
GSList *probenames;
|
||||
uint8_t *linebuf;
|
||||
int spl_cnt;
|
||||
uint8_t *linevalues;
|
||||
char *header;
|
||||
int mark_trigger;
|
||||
uint8_t *prevsample;
|
||||
enum outputmode mode;
|
||||
};
|
||||
|
||||
SR_PRIV void flush_linebufs(struct context *ctx, uint8_t *outbuf);
|
||||
SR_PRIV int init(struct sr_output *o, int default_spl, enum outputmode mode);
|
||||
SR_PRIV int event(struct sr_output *o, int event_type, uint8_t **data_out,
|
||||
uint64_t *length_out);
|
||||
|
||||
SR_PRIV int init_bits(struct sr_output *o);
|
||||
SR_PRIV int data_bits(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out,
|
||||
uint64_t *length_out);
|
||||
|
||||
SR_PRIV int init_hex(struct sr_output *o);
|
||||
SR_PRIV int data_hex(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out,
|
||||
uint64_t *length_out);
|
||||
|
||||
SR_PRIV int init_ascii(struct sr_output *o);
|
||||
SR_PRIV int data_ascii(struct sr_output *o, const uint8_t *data_in,
|
||||
uint64_t length_in, uint8_t **data_out,
|
||||
uint64_t *length_out);
|
||||
|
||||
#endif
|
271
libsigrok4DSL/output/vcd.c
Normal file
271
libsigrok4DSL/output/vcd.c
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
* Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "config.h" /* Needed for PACKAGE and others. */
|
||||
#include "libsigrok.h"
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "output/vcd"
|
||||
|
||||
struct context {
|
||||
int num_enabled_channels;
|
||||
GArray *channelindices;
|
||||
uint8_t *prevsample;
|
||||
gboolean header_done;
|
||||
int period;
|
||||
int *channel_index;
|
||||
uint64_t samplerate;
|
||||
uint64_t samplecount;
|
||||
};
|
||||
|
||||
static int init(struct sr_output *o, GHashTable *options)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *ch;
|
||||
GSList *l;
|
||||
int num_enabled_channels, i;
|
||||
|
||||
(void)options;
|
||||
|
||||
num_enabled_channels = 0;
|
||||
for (l = o->sdi->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_LOGIC)
|
||||
continue;
|
||||
if (!ch->enabled)
|
||||
continue;
|
||||
num_enabled_channels++;
|
||||
}
|
||||
if (num_enabled_channels > 94) {
|
||||
sr_err("VCD only supports 94 channels.");
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
ctx = g_malloc0(sizeof(struct context));
|
||||
o->priv = ctx;
|
||||
ctx->num_enabled_channels = num_enabled_channels;
|
||||
ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
|
||||
|
||||
/* Once more to map the enabled channels. */
|
||||
for (i = 0, l = o->sdi->channels; l; l = l->next) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_LOGIC)
|
||||
continue;
|
||||
if (!ch->enabled)
|
||||
continue;
|
||||
ctx->channel_index[i++] = ch->index;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static GString *gen_header(const struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
struct sr_channel *ch;
|
||||
GVariant *gvar;
|
||||
GString *header;
|
||||
GSList *l;
|
||||
time_t t;
|
||||
int num_channels, i;
|
||||
char *samplerate_s, *frequency_s, *timestamp;
|
||||
|
||||
ctx = o->priv;
|
||||
header = g_string_sized_new(512);
|
||||
num_channels = g_slist_length(o->sdi->channels);
|
||||
|
||||
/* timestamp */
|
||||
t = time(NULL);
|
||||
timestamp = g_strdup(ctime(&t));
|
||||
timestamp[strlen(timestamp)-1] = 0;
|
||||
g_string_printf(header, "$date %s $end\n", timestamp);
|
||||
g_free(timestamp);
|
||||
|
||||
/* generator */
|
||||
g_string_append_printf(header, "$version %s %s $end\n",
|
||||
PACKAGE, PACKAGE_VERSION);
|
||||
g_string_append_printf(header, "$comment\n Acquisition with "
|
||||
"%d/%d channels", ctx->num_enabled_channels, num_channels);
|
||||
|
||||
if (ctx->samplerate == 0) {
|
||||
if (sr_config_get(o->sdi->driver, o->sdi, NULL, NULL, SR_CONF_SAMPLERATE,
|
||||
&gvar) == SR_OK) {
|
||||
ctx->samplerate = g_variant_get_uint64(gvar);
|
||||
g_variant_unref(gvar);
|
||||
}
|
||||
}
|
||||
if (ctx->samplerate != 0) {
|
||||
samplerate_s = sr_samplerate_string(ctx->samplerate);
|
||||
g_string_append_printf(header, " at %s", samplerate_s);
|
||||
g_free(samplerate_s);
|
||||
}
|
||||
g_string_append_printf(header, "\n$end\n");
|
||||
|
||||
/* timescale */
|
||||
/* VCD can only handle 1/10/100 (s - fs), so scale up first */
|
||||
if (ctx->samplerate > SR_MHZ(1))
|
||||
ctx->period = SR_GHZ(1);
|
||||
else if (ctx->samplerate > SR_KHZ(1))
|
||||
ctx->period = SR_MHZ(1);
|
||||
else
|
||||
ctx->period = SR_KHZ(1);
|
||||
frequency_s = sr_period_string(ctx->period);
|
||||
g_string_append_printf(header, "$timescale %s $end\n", frequency_s);
|
||||
g_free(frequency_s);
|
||||
|
||||
/* scope */
|
||||
g_string_append_printf(header, "$scope module %s $end\n", PACKAGE);
|
||||
|
||||
/* Wires / channels */
|
||||
for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
|
||||
ch = l->data;
|
||||
if (ch->type != SR_CHANNEL_LOGIC)
|
||||
continue;
|
||||
if (!ch->enabled)
|
||||
continue;
|
||||
g_string_append_printf(header, "$var wire 1 %c %s $end\n",
|
||||
(char)('!' + i), ch->name);
|
||||
}
|
||||
|
||||
g_string_append(header, "$upscope $end\n$enddefinitions $end\n");
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static int receive(const struct sr_output *o, const struct sr_datafeed_packet *packet,
|
||||
GString **out)
|
||||
{
|
||||
const struct sr_datafeed_meta *meta;
|
||||
const struct sr_datafeed_logic *logic;
|
||||
const struct sr_config *src;
|
||||
GSList *l;
|
||||
struct context *ctx;
|
||||
unsigned int i;
|
||||
int p, curbit, prevbit, index;
|
||||
uint8_t *sample;
|
||||
gboolean timestamp_written;
|
||||
|
||||
*out = NULL;
|
||||
if (!o || !o->priv)
|
||||
return SR_ERR_BUG;
|
||||
ctx = o->priv;
|
||||
|
||||
switch (packet->type) {
|
||||
case SR_DF_META:
|
||||
meta = packet->payload;
|
||||
for (l = meta->config; l; l = l->next) {
|
||||
src = l->data;
|
||||
if (src->key != SR_CONF_SAMPLERATE)
|
||||
continue;
|
||||
ctx->samplerate = g_variant_get_uint64(src->data);
|
||||
}
|
||||
break;
|
||||
case SR_DF_LOGIC:
|
||||
logic = packet->payload;
|
||||
|
||||
if (!ctx->header_done) {
|
||||
*out = gen_header(o);
|
||||
ctx->header_done = TRUE;
|
||||
} else {
|
||||
*out = g_string_sized_new(512);
|
||||
}
|
||||
|
||||
if (!ctx->prevsample) {
|
||||
/* Can't allocate this until we know the stream's unitsize. */
|
||||
ctx->prevsample = g_malloc0(logic->unitsize);
|
||||
}
|
||||
|
||||
for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
|
||||
sample = logic->data + i;
|
||||
timestamp_written = FALSE;
|
||||
|
||||
for (p = 0; p < ctx->num_enabled_channels; p++) {
|
||||
index = ctx->channel_index[p];
|
||||
|
||||
curbit = ((unsigned)sample[index / 8]
|
||||
>> (index % 8)) & 1;
|
||||
prevbit = ((unsigned)ctx->prevsample[index / 8]
|
||||
>> (index % 8)) & 1;
|
||||
|
||||
/* VCD only contains deltas/changes of signals. */
|
||||
if (prevbit == curbit && ctx->samplecount > 0)
|
||||
continue;
|
||||
|
||||
/* Output timestamp of subsequent signal changes. */
|
||||
if (!timestamp_written)
|
||||
g_string_append_printf(*out, "#%.0f",
|
||||
(double)ctx->samplecount /
|
||||
ctx->samplerate * ctx->period);
|
||||
|
||||
/* Output which signal changed to which value. */
|
||||
g_string_append_c(*out, ' ');
|
||||
g_string_append_c(*out, '0' + curbit);
|
||||
g_string_append_c(*out, '!' + p);
|
||||
|
||||
timestamp_written = TRUE;
|
||||
}
|
||||
|
||||
if (timestamp_written)
|
||||
g_string_append_c(*out, '\n');
|
||||
|
||||
ctx->samplecount++;
|
||||
memcpy(ctx->prevsample, sample, logic->unitsize);
|
||||
}
|
||||
break;
|
||||
case SR_DF_END:
|
||||
/* Write final timestamp as length indicator. */
|
||||
*out = g_string_sized_new(512);
|
||||
g_string_printf(*out, "#%.0f\n",
|
||||
(double)ctx->samplecount / ctx->samplerate * ctx->period);
|
||||
break;
|
||||
}
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
static int cleanup(struct sr_output *o)
|
||||
{
|
||||
struct context *ctx;
|
||||
|
||||
if (!o || !o->priv)
|
||||
return SR_ERR_ARG;
|
||||
|
||||
ctx = o->priv;
|
||||
g_free(ctx->prevsample);
|
||||
g_free(ctx->channel_index);
|
||||
g_free(ctx);
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
struct sr_output_module output_vcd = {
|
||||
.id = "vcd",
|
||||
.name = "VCD",
|
||||
.desc = "Value Change Dump",
|
||||
.exts = (const char*[]){"vcd", NULL},
|
||||
.options = NULL,
|
||||
.init = init,
|
||||
.receive = receive,
|
||||
.cleanup = cleanup,
|
||||
};
|
@ -132,7 +132,7 @@ SR_API struct sr_input_format **sr_input_list(void);
|
||||
|
||||
/*--- output/output.c -------------------------------------------------------*/
|
||||
|
||||
SR_API struct sr_output_format **sr_output_list(void);
|
||||
SR_API const struct sr_output_module **sr_output_list(void);
|
||||
|
||||
/*--- strutil.c -------------------------------------------------------------*/
|
||||
|
||||
|
69
libsigrok4DSL/version.h
Normal file
69
libsigrok4DSL/version.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBSIGROK_VERSION_H
|
||||
#define LIBSIGROK_VERSION_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Version number definitions and macros.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup grp_versions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
* Package version macros (can be used for conditional compilation).
|
||||
*/
|
||||
|
||||
/** The libsigrok package 'major' version number. */
|
||||
#define SR_PACKAGE_VERSION_MAJOR 0
|
||||
|
||||
/** The libsigrok package 'minor' version number. */
|
||||
#define SR_PACKAGE_VERSION_MINOR 2
|
||||
|
||||
/** The libsigrok package 'micro' version number. */
|
||||
#define SR_PACKAGE_VERSION_MICRO 0
|
||||
|
||||
/** The libsigrok package version ("major.minor.micro") as string. */
|
||||
#define SR_PACKAGE_VERSION_STRING "0.2.0"
|
||||
|
||||
/*
|
||||
* Library/libtool version macros (can be used for conditional compilation).
|
||||
*/
|
||||
|
||||
/** The libsigrok libtool 'current' version number. */
|
||||
#define SR_LIB_VERSION_CURRENT 1
|
||||
|
||||
/** The libsigrok libtool 'revision' version number. */
|
||||
#define SR_LIB_VERSION_REVISION 2
|
||||
|
||||
/** The libsigrok libtool 'age' version number. */
|
||||
#define SR_LIB_VERSION_AGE 0
|
||||
|
||||
/** The libsigrok libtool version ("current:revision:age") as string. */
|
||||
#define SR_LIB_VERSION_STRING "1:2:0"
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user